org.jets3t.service.impl.rest.CloudFrontXmlResponsesSaxParser.java Source code

Java tutorial

Introduction

Here is the source code for org.jets3t.service.impl.rest.CloudFrontXmlResponsesSaxParser.java

Source

/*
 * JetS3t : Java S3 Toolkit
 * Project hosted at http://bitbucket.org/jmurty/jets3t/
 *
 * Copyright 2008-2010 James Murty
 *
 * 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 org.jets3t.service.impl.rest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jets3t.service.CloudFrontServiceException;
import org.jets3t.service.Constants;
import org.jets3t.service.Jets3tProperties;
import org.jets3t.service.S3ServiceException;
import org.jets3t.service.ServiceException;
import org.jets3t.service.model.cloudfront.*;
import org.jets3t.service.model.cloudfront.CacheBehavior.ViewerProtocolPolicy;
import org.jets3t.service.utils.ServiceUtils;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * XML Sax parser to read XML documents returned by the CloudFront service via
 * the REST interface, and convert these documents into JetS3t objects.
 *
 * @author James Murty
 */
public class CloudFrontXmlResponsesSaxParser {
    private static final Log log = LogFactory.getLog(CloudFrontXmlResponsesSaxParser.class);

    private XMLReader xr = null;
    private Jets3tProperties properties = null;

    /**
     * Constructs the XML SAX parser.
     *
     * @param properties the JetS3t properties that will be applied when parsing XML documents.
     * @throws S3ServiceException
     */
    public CloudFrontXmlResponsesSaxParser(Jets3tProperties properties) throws ServiceException {
        this.properties = properties;
        this.xr = ServiceUtils.loadXMLReader();
    }

    public Jets3tProperties getProperties() {
        return this.properties;
    }

    /**
     * Parses an XML document from an input stream using a document handler.
     *
     * @param handler     The handler for the XML document
     * @param inputStream An input stream containing the XML document to parse
     * @throws CloudFrontServiceException Any parsing, IO or other exceptions are wrapped in an S3ServiceException.
     */
    protected void parseXmlInputStream(DefaultHandler handler, InputStream inputStream)
            throws CloudFrontServiceException {
        try {
            if (log.isDebugEnabled()) {
                log.debug("Parsing XML response document with handler: " + handler.getClass());
            }
            BufferedReader breader = new BufferedReader(
                    new InputStreamReader(inputStream, Constants.DEFAULT_ENCODING));
            xr.setContentHandler(handler);
            xr.setErrorHandler(handler);
            xr.parse(new InputSource(breader));
        } catch (Exception t) {
            try {
                inputStream.close();
            } catch (IOException e) {
                if (log.isErrorEnabled()) {
                    log.error("Unable to close response InputStream up after XML parse failure", e);
                }
            }
            throw new CloudFrontServiceException("Failed to parse XML document with handler " + handler.getClass(),
                    t);
        }
    }

    /**
     * Parses a ListBucket response XML document from an input stream.
     *
     * @param inputStream XML data input stream.
     * @return the XML handler object populated with data parsed from the XML stream.
     * @throws CloudFrontServiceException
     */
    public DistributionListHandler parseDistributionListResponse(InputStream inputStream)
            throws CloudFrontServiceException {
        DistributionListHandler handler = new DistributionListHandler(xr);
        parseXmlInputStream(handler, inputStream);
        return handler;
    }

    public DistributionHandler parseDistributionResponse(InputStream inputStream)
            throws CloudFrontServiceException {
        DistributionHandler handler = new DistributionHandler(xr);
        parseXmlInputStream(handler, inputStream);
        return handler;
    }

    public DistributionConfigHandler parseDistributionConfigResponse(InputStream inputStream)
            throws CloudFrontServiceException {
        DistributionConfigHandler handler = new DistributionConfigHandler(xr);
        parseXmlInputStream(handler, inputStream);
        return handler;
    }

    public OriginAccessIdentityHandler parseOriginAccessIdentity(InputStream inputStream)
            throws CloudFrontServiceException {
        OriginAccessIdentityHandler handler = new OriginAccessIdentityHandler(xr);
        parseXmlInputStream(handler, inputStream);
        return handler;
    }

    public OriginAccessIdentityConfigHandler parseOriginAccessIdentityConfig(InputStream inputStream)
            throws CloudFrontServiceException {
        OriginAccessIdentityConfigHandler handler = new OriginAccessIdentityConfigHandler(xr);
        parseXmlInputStream(handler, inputStream);
        return handler;
    }

    public OriginAccessIdentityListHandler parseOriginAccessIdentityListResponse(InputStream inputStream)
            throws CloudFrontServiceException {
        OriginAccessIdentityListHandler handler = new OriginAccessIdentityListHandler(xr);
        parseXmlInputStream(handler, inputStream);
        return handler;
    }

    public InvalidationHandler parseInvalidationResponse(InputStream inputStream)
            throws CloudFrontServiceException {
        InvalidationHandler handler = new InvalidationHandler(xr);
        parseXmlInputStream(handler, inputStream);
        return handler;
    }

    public InvalidationListHandler parseInvalidationListResponse(InputStream inputStream)
            throws CloudFrontServiceException {
        InvalidationListHandler handler = new InvalidationListHandler(xr);
        parseXmlInputStream(handler, inputStream);
        return handler;
    }

    public ErrorHandler parseErrorResponse(InputStream inputStream) throws CloudFrontServiceException {
        ErrorHandler handler = new ErrorHandler(xr);
        parseXmlInputStream(handler, inputStream);
        return handler;
    }

    // ////////////
    // Handlers //
    // ////////////

    public class DistributionHandler extends SimpleHandler {
        private Distribution distribution = null;

        private String id = null;
        private String status = null;
        private Date lastModifiedTime = null;
        private String domainName = null;
        private final Map<String, List<String>> activeTrustedSigners = new HashMap<String, List<String>>();

        private boolean inSignerElement;
        private String lastSignerIdentifier = null;

        public DistributionHandler(XMLReader xr) {
            super(xr);
        }

        public Distribution getDistribution() {
            return distribution;
        }

        public void endId(String text) {
            this.id = text;
        }

        public void endStatus(String text) {
            this.status = text;
        }

        public void endLastModifiedTime(String text) throws ParseException {
            this.lastModifiedTime = ServiceUtils.parseIso8601Date(text);
        }

        public void endDomainName(String text) {
            this.domainName = text;
        }

        // Handle ActiveTrustedSigner elements //
        public void startSigner() {
            inSignerElement = true;
        }

        public void endSigner(String text) {
            inSignerElement = false;
            lastSignerIdentifier = null;
        }

        public void endSelf(String text) {
            if (inSignerElement) {
                lastSignerIdentifier = "Self";
            }
        }

        public void endAwsAccountNumber(String text) {
            if (inSignerElement) {
                lastSignerIdentifier = text;
            }
        }

        public void endKeyPairId(String text) {
            if (inSignerElement) {
                List<String> keypairIdList = activeTrustedSigners.get(lastSignerIdentifier);
                if (keypairIdList == null) {
                    keypairIdList = new ArrayList<String>();
                    activeTrustedSigners.put(lastSignerIdentifier, keypairIdList);
                }
                keypairIdList.add(text);
            }
        }
        // End handle ActiveTrustedSigner elements //

        public void startDistributionConfig() {
            transferControlToHandler(new DistributionConfigHandler(xr));
        }

        public void startStreamingDistributionConfig() {
            transferControlToHandler(new DistributionConfigHandler(xr));
        }

        @Override
        public void controlReturned(SimpleHandler childHandler) {
            DistributionConfig config = ((DistributionConfigHandler) childHandler).getDistributionConfig();
            if (config instanceof StreamingDistributionConfig) {
                this.distribution = new StreamingDistribution(id, status, lastModifiedTime, domainName,
                        activeTrustedSigners, config);
            } else {
                this.distribution = new Distribution(id, status, lastModifiedTime, 0L, domainName,
                        activeTrustedSigners, config);
            }
        }

        // End of a normal Distribution
        public void endDistribution(String text) {
            returnControlToParentHandler();
        }

        // End of a StreamingDistribution
        public void endStreamingDistribution(String text) {
            returnControlToParentHandler();
        }
    }

    public class LoggingStatusHandler extends SimpleHandler {
        private LoggingStatus loggingStatus = new LoggingStatus(false, null, null);

        public LoggingStatusHandler(XMLReader xr) {
            super(xr);
        }

        public LoggingStatus getLoggingStatus() {
            return loggingStatus;
        }

        public void endEnabled(String text) {
            loggingStatus.setEnabled(String.valueOf(true).equals(text));
        }

        public void endBucket(String text) {
            loggingStatus.setBucket(text);
        }

        public void endPrefix(String text) {
            loggingStatus.setPrefix(text);
        }

        public void endLogging(String text) {
            returnControlToParentHandler();
        }
    }

    public class TrustedSignersHandler extends SimpleHandler {
        private List<String> trustedSigners = new ArrayList<String>();

        public TrustedSignersHandler(XMLReader xr) {
            super(xr);
        }

        public String[] getTrustedSigners() {
            return trustedSigners.toArray(new String[trustedSigners.size()]);
        }

        public void endAwsAccountNumber(String text) {
            trustedSigners.add(text);
        }

        public void endTrustedSigners(String text) {
            returnControlToParentHandler();
        }
    }

    public class CacheBehaviorHandler extends SimpleHandler {
        private CacheBehavior cacheBehavior = new CacheBehavior();

        public CacheBehaviorHandler(XMLReader xr) {
            super(xr);
        }

        public CacheBehavior getCacheBehavior() {
            return cacheBehavior;
        }

        public void endPathPattern(String text) {
            cacheBehavior.setPathPattern(text);
        }

        public void endTargetOriginId(String text) {
            cacheBehavior.setTargetOriginId(text);
        }

        public void endQueryString(String text) {
            cacheBehavior.setIsForwardQueryString(String.valueOf(true).equals(text));
        }

        public void endViewerProtocolPolicy(String text) {
            cacheBehavior.setViewerProtocolPolicy(ViewerProtocolPolicy.fromText(text));
        }

        public void endMinTTL(String text) {
            cacheBehavior.setMinTTL(new Long(text));
        }

        public void startTrustedSigners() {
            transferControlToHandler(new TrustedSignersHandler(xr));
        }

        @Override
        public void controlReturned(SimpleHandler childHandler) {
            cacheBehavior
                    .setTrustedSignerAwsAccountNumbers(((TrustedSignersHandler) childHandler).getTrustedSigners());
        }

        public void endDefaultCacheBehavior(String text) {
            returnControlToParentHandler();
        }

        public void endCacheBehavior(String text) {
            returnControlToParentHandler();
        }
    }

    public class DistributionConfigHandler extends SimpleHandler {
        private DistributionConfig distributionConfig = null;

        private String callerReference = null;
        private List<Origin> origins = new ArrayList<Origin>();
        private final List<String> cnamesList = new ArrayList<String>();
        private String comment = null;
        private boolean enabled = false;
        private LoggingStatus loggingStatus = null;
        private String defaultRootObject = null;
        private CacheBehavior defaultCacheBehavior;
        private List<CacheBehavior> cacheBehaviors = new ArrayList<CacheBehavior>();
        List<String> trustedSignerAwsAccountNumberList = new ArrayList<String>();

        private boolean inDefaultCacheBehavior = false;

        public DistributionConfigHandler(XMLReader xr) {
            super(xr);
        }

        public DistributionConfig getDistributionConfig() {
            return distributionConfig;
        }

        public void endCallerReference(String text) {
            this.callerReference = text;
        }

        public void endCNAME(String text) {
            this.cnamesList.add(text);
        }

        public void endDefaultRootObject(String text) {
            this.defaultRootObject = text;
        }

        public void endComment(String text) {
            this.comment = text;
        }

        public void endEnabled(String text) {
            this.enabled = String.valueOf(true).equalsIgnoreCase(text);
        }

        public void startOrigin() {
            // For DistributionConfig
            transferControlToHandler(new OriginHandler(xr));
        }

        public void startS3Origin() {
            // For StreamingDistributionConfig
            transferControlToHandler(new OriginHandler(xr));
        }

        public void startDefaultCacheBehavior() {
            inDefaultCacheBehavior = true;
            transferControlToHandler(new CacheBehaviorHandler(xr));
        }

        public void startCacheBehavior() {
            inDefaultCacheBehavior = false;
            transferControlToHandler(new CacheBehaviorHandler(xr));
        }

        public void startLogging() {
            transferControlToHandler(new LoggingStatusHandler(xr));
        }

        @Override
        public void controlReturned(SimpleHandler childHandler) {
            if (childHandler instanceof OriginHandler) {
                this.origins.add(((OriginHandler) childHandler).origin);
            } else if (childHandler instanceof CacheBehaviorHandler) {
                if (inDefaultCacheBehavior) {
                    this.defaultCacheBehavior = ((CacheBehaviorHandler) childHandler).cacheBehavior;
                } else {
                    this.cacheBehaviors.add(((CacheBehaviorHandler) childHandler).cacheBehavior);
                }
            } else if (childHandler instanceof LoggingStatusHandler) {
                this.loggingStatus = ((LoggingStatusHandler) childHandler).loggingStatus;
            }
        }

        public void endDistributionConfig(String text) {
            this.distributionConfig = new DistributionConfig(origins.toArray(new Origin[origins.size()]),
                    callerReference, cnamesList.toArray(new String[cnamesList.size()]), comment, enabled,
                    loggingStatus, defaultRootObject, defaultCacheBehavior,
                    cacheBehaviors.toArray(new CacheBehavior[cacheBehaviors.size()]));
            returnControlToParentHandler();
        }

        public void endStreamingDistributionConfig(String text) {
            this.distributionConfig = new StreamingDistributionConfig(origins.toArray(new Origin[origins.size()]),
                    callerReference, cnamesList.toArray(new String[cnamesList.size()]), comment, enabled,
                    loggingStatus, trustedSignerAwsAccountNumberList
                            .toArray(new String[trustedSignerAwsAccountNumberList.size()]));
            returnControlToParentHandler();
        }
    }

    public class DistributionSummaryHandler extends SimpleHandler {
        private Distribution distribution = null;

        private String id = null;
        private String status = null;
        private Date lastModifiedTime = null;
        private Long inProgressInvalidationBatches = 0l;
        private String domainName = null;
        private List<Origin> origins = new ArrayList<Origin>();
        private final List<String> cnamesList = new ArrayList<String>();
        private String comment = null;
        private boolean enabled = false;
        private CacheBehavior defaultCacheBehavior = null;
        private List<CacheBehavior> cacheBehaviors = new ArrayList<CacheBehavior>();

        private boolean inDefaultCacheBehavior = false;

        public DistributionSummaryHandler(XMLReader xr) {
            super(xr);
        }

        public Distribution getDistribution() {
            return distribution;
        }

        public void endId(String text) {
            this.id = text;
        }

        public void endStatus(String text) {
            this.status = text;
        }

        public void endLastModifiedTime(String text) throws ParseException {
            this.lastModifiedTime = ServiceUtils.parseIso8601Date(text);
        }

        public void endInProgressInvalidationBatches(String text) {
            this.inProgressInvalidationBatches = Long.parseLong(text);
        }

        public void endDomainName(String text) {
            this.domainName = text;
        }

        public void endCNAME(String text) {
            this.cnamesList.add(text);
        }

        public void startOrigin() {
            // For download distribution origins
            transferControlToHandler(new OriginHandler(xr));
        }

        public void startS3Origin() {
            // For streaming distribution origins
            transferControlToHandler(new OriginHandler(xr));
        }

        public void startDefaultCacheBehavior() {
            inDefaultCacheBehavior = true;
            transferControlToHandler(new CacheBehaviorHandler(xr));
        }

        public void startCacheBehavior() {
            inDefaultCacheBehavior = false;
            transferControlToHandler(new CacheBehaviorHandler(xr));
        }

        @Override
        public void controlReturned(SimpleHandler childHandler) {
            if (childHandler instanceof OriginHandler) {
                this.origins.add(((OriginHandler) childHandler).origin);
            } else if (childHandler instanceof CacheBehaviorHandler) {
                if (inDefaultCacheBehavior) {
                    this.defaultCacheBehavior = ((CacheBehaviorHandler) childHandler).cacheBehavior;
                } else {
                    this.cacheBehaviors.add(((CacheBehaviorHandler) childHandler).cacheBehavior);
                }
            }
        }

        public void endComment(String text) {
            this.comment = text;
        }

        public void endEnabled(String text) {
            this.enabled = String.valueOf(true).equalsIgnoreCase(text);
        }

        public void endDistributionSummary(String text) {
            DistributionConfig config = new DistributionConfig(this.origins.toArray(new Origin[origins.size()]),
                    null, // callerReference
                    this.cnamesList.toArray(new String[cnamesList.size()]), this.comment, this.enabled, null, // loggingStatus
                    null, this.defaultCacheBehavior,
                    this.cacheBehaviors.toArray(new CacheBehavior[cacheBehaviors.size()]));
            this.distribution = new Distribution(id, status, lastModifiedTime, inProgressInvalidationBatches,
                    domainName, null, config);
            returnControlToParentHandler();
        }

        public void endStreamingDistributionSummary(String text) {
            StreamingDistributionConfig config = new StreamingDistributionConfig(
                    this.origins.toArray(new Origin[origins.size()]), null, // callerReference
                    this.cnamesList.toArray(new String[cnamesList.size()]), this.comment, this.enabled, null, // loggingStatus
                    null // trustedSignerAwsAccountNumbers
            );
            this.distribution = new StreamingDistribution(id, status, lastModifiedTime, domainName, null, config);
            returnControlToParentHandler();
        }
    }

    public class DistributionListHandler extends SimpleHandler {
        private final List<Distribution> distributions = new ArrayList<Distribution>();
        private String marker = null;
        private String nextMarker = null;
        private int maxItems = 100;
        private boolean isTruncated = false;

        public DistributionListHandler(XMLReader xr) {
            super(xr);
        }

        public List<Distribution> getDistributions() {
            return distributions;
        }

        public boolean isTruncated() {
            return isTruncated;
        }

        public String getMarker() {
            return marker;
        }

        public String getNextMarker() {
            return nextMarker;
        }

        public int getMaxItems() {
            return maxItems;
        }

        public void startDistributionSummary() {
            transferControlToHandler(new DistributionSummaryHandler(xr));
        }

        public void startStreamingDistributionSummary() {
            transferControlToHandler(new DistributionSummaryHandler(xr));
        }

        @Override
        public void controlReturned(SimpleHandler childHandler) {
            distributions.add(((DistributionSummaryHandler) childHandler).getDistribution());
        }

        public void endMarker(String text) {
            this.marker = text;
        }

        public void endNextMarker(String text) {
            this.nextMarker = text;
        }

        public void endMaxItems(String text) {
            this.maxItems = Integer.parseInt(text);
        }

        public void endIsTruncated(String text) {
            this.isTruncated = String.valueOf(true).equalsIgnoreCase(text);
        }
    }

    public class OriginHandler extends SimpleHandler {
        protected Origin origin = null;
        private String id;
        private String domainName = null;
        private String originAccessIdentity = null; // S3Origin
        private String httpPort = null; // CustomOrigin
        private String httpsPort = null; // CustomOrigin
        private String originProtocolPolicy = null; // CustomOrigin

        public OriginHandler(XMLReader xr) {
            super(xr);
        }

        public void endId(String text) {
            this.id = text;
        }

        public void endDomainName(String text) {
            this.domainName = text;
        }

        public void endOriginAccessIdentity(String text) {
            this.originAccessIdentity = text;
        }

        public void endHTTPPort(String text) {
            this.httpPort = text;
        }

        public void endHTTPSPort(String text) {
            this.httpsPort = text;
        }

        public void endOriginProtocolPolicy(String text) {
            this.originProtocolPolicy = text;
        }

        public void endS3OriginConfig(String text) {
            // For download distribution origins
            if (this.originAccessIdentity != null && this.originAccessIdentity.length() == 0) {
                this.originAccessIdentity = null;
            }
            this.origin = new S3Origin(this.id, this.domainName, this.originAccessIdentity);
            returnControlToParentHandler();
        }

        public void endS3Origin(String text) {
            // For streaming distribution origins
            if (this.originAccessIdentity != null && this.originAccessIdentity.length() == 0) {
                this.originAccessIdentity = null;
            }
            this.origin = new S3Origin(this.id, this.domainName, this.originAccessIdentity);
            returnControlToParentHandler();
        }

        public void endCustomOriginConfig(String text) {
            // For download distribution origins
            this.origin = new CustomOrigin(this.id, this.domainName,
                    CustomOrigin.OriginProtocolPolicy.fromText(this.originProtocolPolicy),
                    Integer.valueOf(this.httpPort), Integer.valueOf(this.httpsPort));
            returnControlToParentHandler();
        }
    }

    public class OriginAccessIdentityHandler extends SimpleHandler {
        private String id = null;
        private String s3CanonicalUserId = null;
        private String comment = null;
        private OriginAccessIdentity originAccessIdentity = null;
        private OriginAccessIdentityConfig originAccessIdentityConfig = null;

        public OriginAccessIdentityHandler(XMLReader xr) {
            super(xr);
        }

        public OriginAccessIdentity getOriginAccessIdentity() {
            return this.originAccessIdentity;
        }

        public void endId(String text) {
            this.id = text;
        }

        public void endS3CanonicalUserId(String text) {
            this.s3CanonicalUserId = text;
        }

        public void endComment(String text) {
            this.comment = text;
        }

        public void startCloudFrontOriginAccessIdentityConfig() {
            transferControlToHandler(new OriginAccessIdentityConfigHandler(xr));
        }

        @Override
        public void controlReturned(SimpleHandler childHandler) {
            this.originAccessIdentityConfig = ((OriginAccessIdentityConfigHandler) childHandler)
                    .getOriginAccessIdentityConfig();
        }

        public void endCloudFrontOriginAccessIdentity(String text) {
            this.originAccessIdentity = new OriginAccessIdentity(this.id, this.s3CanonicalUserId,
                    this.originAccessIdentityConfig);
        }

        public void endCloudFrontOriginAccessIdentitySummary(String text) {
            this.originAccessIdentity = new OriginAccessIdentity(this.id, this.s3CanonicalUserId, this.comment);
            returnControlToParentHandler();
        }
    }

    public class OriginAccessIdentityConfigHandler extends SimpleHandler {
        private String callerReference = null;
        private String comment = null;
        private OriginAccessIdentityConfig config = null;

        public OriginAccessIdentityConfigHandler(XMLReader xr) {
            super(xr);
        }

        public OriginAccessIdentityConfig getOriginAccessIdentityConfig() {
            return this.config;
        }

        public void endCallerReference(String text) {
            this.callerReference = text;
        }

        public void endComment(String text) {
            this.comment = text;
        }

        public void endCloudFrontOriginAccessIdentityConfig(String text) {
            this.config = new OriginAccessIdentityConfig(this.callerReference, this.comment);
            returnControlToParentHandler();
        }
    }

    public class OriginAccessIdentityListHandler extends SimpleHandler {
        private final List<OriginAccessIdentity> originAccessIdentityList = new ArrayList<OriginAccessIdentity>();
        private String marker = null;
        private String nextMarker = null;
        private int maxItems = 100;
        private boolean isTruncated = false;

        public OriginAccessIdentityListHandler(XMLReader xr) {
            super(xr);
        }

        public List<OriginAccessIdentity> getOriginAccessIdentityList() {
            return this.originAccessIdentityList;
        }

        public boolean isTruncated() {
            return isTruncated;
        }

        public String getMarker() {
            return marker;
        }

        public String getNextMarker() {
            return nextMarker;
        }

        public int getMaxItems() {
            return maxItems;
        }

        public void startCloudFrontOriginAccessIdentitySummary() {
            transferControlToHandler(new OriginAccessIdentityHandler(xr));
        }

        @Override
        public void controlReturned(SimpleHandler childHandler) {
            originAccessIdentityList.add(((OriginAccessIdentityHandler) childHandler).getOriginAccessIdentity());
        }

        public void endMarker(String text) {
            this.marker = text;
        }

        public void endNextMarker(String text) {
            this.nextMarker = text;
        }

        public void endMaxItems(String text) {
            this.maxItems = Integer.parseInt(text);
        }

        public void endIsTruncated(String text) {
            this.isTruncated = String.valueOf(true).equalsIgnoreCase(text);
        }
    }

    public class InvalidationListHandler extends SimpleHandler {
        private String marker = null;
        private String nextMarker = null;
        private int maxItems = 100;
        private boolean isTruncated = false;
        private String invalidationSummaryId = null;
        private String invalidationSummaryStatus = null;
        private List<InvalidationSummary> invalidationSummaries = new ArrayList<InvalidationSummary>();
        private InvalidationList invalidationList = null;

        public InvalidationListHandler(XMLReader xr) {
            super(xr);
        }

        public InvalidationList getInvalidationList() {
            return invalidationList;
        }

        public boolean isTruncated() {
            return isTruncated;
        }

        public String getMarker() {
            return marker;
        }

        public String getNextMarker() {
            return nextMarker;
        }

        public int getMaxItems() {
            return maxItems;
        }

        public void endMarker(String text) {
            this.marker = text;
        }

        public void endNextMarker(String text) {
            this.nextMarker = text;
        }

        public void endMaxItems(String text) {
            this.maxItems = Integer.parseInt(text);
        }

        public void endIsTruncated(String text) {
            this.isTruncated = String.valueOf(true).equalsIgnoreCase(text);
        }

        // Inside InvalidationSummary
        public void endId(String text) {
            this.invalidationSummaryId = text;
        }

        // Inside InvalidationSummary
        public void endStatus(String text) {
            this.invalidationSummaryStatus = text;
            this.invalidationSummaries
                    .add(new InvalidationSummary(this.invalidationSummaryId, this.invalidationSummaryStatus));
        }

        public void endInvalidationList(String ignore) {
            this.invalidationList = new InvalidationList(this.marker, this.nextMarker, this.maxItems,
                    this.isTruncated, this.invalidationSummaries);
        }
    }

    public class InvalidationHandler extends SimpleHandler {
        private Invalidation invalidation = new Invalidation();

        public InvalidationHandler(XMLReader xr) {
            super(xr);
        }

        public Invalidation getInvalidation() {
            return this.invalidation;
        }

        public void endId(String text) {
            this.invalidation.setId(text);
        }

        public void endStatus(String text) {
            this.invalidation.setStatus(text);
        }

        public void endCreateTime(String text) throws ParseException {
            this.invalidation.setCreateTime(ServiceUtils.parseIso8601Date(text));
        }

        public void endPath(String text) {
            this.invalidation.getObjectKeys().add(text.substring(1));
        }

        public void endCallerReference(String text) {
            this.invalidation.setCallerReference(text);
        }
    }

    public class ErrorHandler extends SimpleHandler {
        private String type = null;
        private String code = null;
        private String message = null;
        private String detail = null;
        private String requestId = null;

        public ErrorHandler(XMLReader xr) {
            super(xr);
        }

        public String getCode() {
            return code;
        }

        public String getDetail() {
            return detail;
        }

        public String getMessage() {
            return message;
        }

        public String getRequestId() {
            return requestId;
        }

        public String getType() {
            return type;
        }

        public void endType(String text) {
            this.type = text;
        }

        public void endCode(String text) {
            this.code = text;
        }

        public void endMessage(String text) {
            this.message = text;
        }

        public void endDetail(String text) {
            this.detail = text;
        }

        public void endRequestId(String text) {
            this.requestId = text;
        }

        // Handle annoying case where request id is in
        // the element "RequestID", not "RequestId"
        public void endRequestID(String text) {
            this.requestId = text;
        }
    }
}