1
15 package com.amazonaws.http;
16
17 import com.amazonaws.AmazonWebServiceResponse;
18 import com.amazonaws.ResponseMetadata;
19 import com.amazonaws.internal.SdkFilterInputStream;
20 import com.amazonaws.transform.StaxUnmarshallerContext;
21 import com.amazonaws.transform.Unmarshaller;
22 import com.amazonaws.transform.VoidStaxUnmarshaller;
23 import com.amazonaws.util.StringUtils;
24 import com.amazonaws.util.XmlUtils;
25 import java.io.ByteArrayInputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.util.Map;
29 import javax.xml.stream.XMLEventReader;
30 import javax.xml.stream.XMLStreamException;
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.apache.http.impl.io.EmptyInputStream;
34
35
42 public class StaxResponseHandler<T> implements HttpResponseHandler<AmazonWebServiceResponse<T>> {
43
44
47 private Unmarshaller<T, StaxUnmarshallerContext> responseUnmarshaller;
48
49
52 private static final Log log = LogFactory.getLog("com.amazonaws.request");
53
54
62 public StaxResponseHandler(Unmarshaller<T, StaxUnmarshallerContext> responseUnmarshaller) {
63 this.responseUnmarshaller = responseUnmarshaller;
64
65
72 if (this.responseUnmarshaller == null) {
73 this.responseUnmarshaller = new VoidStaxUnmarshaller<T>();
74 }
75 }
76
77
78
81 public AmazonWebServiceResponse<T> handle(HttpResponse response) throws Exception {
82 log.trace("Parsing service response XML");
83 InputStream content = response.getContent();
84
85 if (content == null) {
86 content = new ByteArrayInputStream("<eof/>".getBytes(StringUtils.UTF8));
87 } else if (content instanceof SdkFilterInputStream &&
88 ((SdkFilterInputStream) content).getDelegateStream() instanceof EmptyInputStream) {
89 content = new ByteArrayInputStream("<eof/>".getBytes(StringUtils.UTF8));
90 }
91
92 XMLEventReader eventReader;
93 try {
94 eventReader = XmlUtils.getXmlInputFactory().createXMLEventReader(content);
95 } catch (XMLStreamException e) {
96 throw handleXmlStreamException(e);
97 }
98
99 try {
100 AmazonWebServiceResponse<T> awsResponse = new AmazonWebServiceResponse<T>();
101 StaxUnmarshallerContext unmarshallerContext = new StaxUnmarshallerContext(eventReader, response.getHeaders());
102 unmarshallerContext.registerMetadataExpression("ResponseMetadata/RequestId", 2, ResponseMetadata.AWS_REQUEST_ID);
103 unmarshallerContext.registerMetadataExpression("requestId", 2, ResponseMetadata.AWS_REQUEST_ID);
104 registerAdditionalMetadataExpressions(unmarshallerContext);
105
106 T result = responseUnmarshaller.unmarshall(unmarshallerContext);
107 awsResponse.setResult(result);
108
109 Map<String, String> metadata = unmarshallerContext.getMetadata();
110 Map<String, String> responseHeaders = response.getHeaders();
111 if (responseHeaders != null) {
112 if (responseHeaders.get(X_AMZN_REQUEST_ID_HEADER) != null) {
113 metadata.put(ResponseMetadata.AWS_REQUEST_ID,
114 responseHeaders.get(X_AMZN_REQUEST_ID_HEADER));
115 }
116 if (responseHeaders.get(X_AMZN_EXTENDED_REQUEST_ID_HEADER) != null) {
117 metadata.put(ResponseMetadata.AWS_EXTENDED_REQUEST_ID,
118 responseHeaders.get(X_AMZN_EXTENDED_REQUEST_ID_HEADER));
119 }
120 }
121 awsResponse.setResponseMetadata(getResponseMetadata(metadata));
122
123 log.trace("Done parsing service response");
124 return awsResponse;
125 } catch (XMLStreamException e) {
126 throw handleXmlStreamException(e);
127 } finally {
128 try {
129 eventReader.close();
130 } catch (XMLStreamException e) {
131 log.warn("Error closing xml parser", e);
132 }
133 }
134 }
135
136
140 private Exception handleXmlStreamException(XMLStreamException e) throws Exception {
141 if (e.getNestedException() instanceof IOException) {
142 return new IOException(e);
143 }
144 return e;
145 }
146
147
151 protected ResponseMetadata getResponseMetadata(Map<String, String> metadata) {
152 return new ResponseMetadata(metadata);
153 }
154
155
162 protected void registerAdditionalMetadataExpressions(StaxUnmarshallerContext unmarshallerContext) {
163 }
164
165
172 public boolean needsConnectionLeftOpen() {
173 return false;
174 }
175
176 }
177