Java tutorial
/* * Copyright 2014-2017 Netflix, Inc. * * 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 com.amazonaws.http; import com.amazonaws.AmazonWebServiceResponse; import com.amazonaws.ResponseMetadata; import com.amazonaws.transform.StaxUnmarshallerContext; import com.amazonaws.transform.Unmarshaller; import com.amazonaws.transform.VoidStaxUnmarshaller; import com.amazonaws.util.RxSchedulers; import iep.io.reactivex.netty.protocol.http.client.HttpClientResponse; import io.netty.buffer.ByteBuf; import io.netty.util.ReferenceCountUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import rx.Observable; import rx.functions.Func2; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.HashMap; import java.util.Map; /** * Default implementation of HttpResponseHandler that handles a successful * response from an AWS service and unmarshalls the result using a StAX * unmarshaller. * * @param <T> * Indicates the type being unmarshalled by this response handler. */ public class StaxRxNettyResponseHandler<T> implements RxNettyResponseHandler<AmazonWebServiceResponse<T>> { /** The StAX unmarshaller to use when handling the response */ private Unmarshaller<T, StaxUnmarshallerContext> responseUnmarshaller; /** Shared logger for profiling information */ private static final Log log = LogFactory.getLog("com.amazonaws.request"); /** Shared factory for creating XML event readers */ private static final XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); /** * Constructs a new response handler that will use the specified StAX * unmarshaller to unmarshall the service response and uses the specified * response element path to find the root of the business data in the * service's response. * * @param responseUnmarshaller * The StAX unmarshaller to use on the response. */ public StaxRxNettyResponseHandler(Unmarshaller<T, StaxUnmarshallerContext> responseUnmarshaller) { this.responseUnmarshaller = responseUnmarshaller; if (this.responseUnmarshaller == null) { this.responseUnmarshaller = new VoidStaxUnmarshaller<T>(); } } @Override public AmazonWebServiceResponse<T> handle(HttpResponse r) { throw new UnsupportedOperationException("apache client not suppported"); } @Override public Observable<AmazonWebServiceResponse<T>> handle(HttpClientResponse<ByteBuf> response) throws Exception { return response.getContent().reduce(new ByteArrayOutputStream(), new Func2<ByteArrayOutputStream, ByteBuf, ByteArrayOutputStream>() { @Override public ByteArrayOutputStream call(ByteArrayOutputStream out, ByteBuf bb) { try { bb.readBytes(out, bb.readableBytes()); return out; } catch (java.io.IOException e) { throw new RuntimeException(e); } finally { ReferenceCountUtil.safeRelease(bb); } } }).observeOn(RxSchedulers.computation()).flatMap(out -> { byte[] bytes = out.toByteArray(); if (bytes.length == 0) bytes = "<eof/>".getBytes(); ByteArrayInputStream in = new ByteArrayInputStream(bytes); XMLEventReader reader = null; try { reader = xmlInputFactory.createXMLEventReader(in); } catch (XMLStreamException e) { throw new RuntimeException(e); } try { Map<String, String> responseHeaders = new HashMap<String, String>(); for (String k : response.getHeaders().names()) { // TODO: comma seperated? responseHeaders.put(k, response.getHeaders().get(k)); } AmazonWebServiceResponse<T> awsResponse = new AmazonWebServiceResponse<T>(); StaxUnmarshallerContext unmarshallerContext = new StaxUnmarshallerContext(reader, responseHeaders); unmarshallerContext.registerMetadataExpression("ResponseMetadata/RequestId", 2, ResponseMetadata.AWS_REQUEST_ID); unmarshallerContext.registerMetadataExpression("requestId", 2, ResponseMetadata.AWS_REQUEST_ID); registerAdditionalMetadataExpressions(unmarshallerContext); T result = responseUnmarshaller.unmarshall(unmarshallerContext); awsResponse.setResult(result); Map<String, String> metadata = unmarshallerContext.getMetadata(); if (responseHeaders != null) { if (responseHeaders.get("x-amzn-RequestId") != null) { metadata.put(ResponseMetadata.AWS_REQUEST_ID, responseHeaders.get("x-amzn-RequestId")); } } awsResponse.setResponseMetadata(new ResponseMetadata(metadata)); return Observable.just(awsResponse); } catch (Exception e) { throw new RuntimeException(e); } finally { try { reader.close(); } catch (XMLStreamException e) { log.warn("Error closing xml parser", e); } } }); } /** * Hook for subclasses to override in order to collect additional metadata * from service responses. * * @param unmarshallerContext * The unmarshaller context used to process a service's response * data. */ protected void registerAdditionalMetadataExpressions(StaxUnmarshallerContext unmarshallerContext) { } /** * Since this response handler completely consumes all the data from the * underlying HTTP connection during the handle method, we don't need to * keep the HTTP connection open. * * @see com.amazonaws.http.HttpResponseHandler#needsConnectionLeftOpen() */ public boolean needsConnectionLeftOpen() { return false; } }