/* * Copyright 2013 Robotoworks Limited * 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.robotoworks.mechanoid.net; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.util.List; import java.util.Map; import com.robotoworks.mechanoid.util.Streams; /** * <p>A Mechanoid Net response that captures the HTTP response code and headers of a HTTP response.</p> * <p>The response defers parsing from the stream until {@link #parse()} is called, this allows examination * of the response code before reading the stream in case of an unexpected response code.</p> * * @param <T> A result representing that which will be parsed when {@link #parse()} is called. */ public class HttpUrlConnectionResponse<T> implements Response<T> { private T mContent; private HttpURLConnection mConn; private Parser<T> mParser; private int mResponseCode; private Map<String, List<String>> mHeaders; private byte[] mInputBytes; private boolean mParsed; /* (non-Javadoc) * @see com.robotoworks.mechanoid.net.Response2#getResponseCode() */ @Override public int getResponseCode() { return mResponseCode; } /* (non-Javadoc) * @see com.robotoworks.mechanoid.net.Response2#checkResponseCodeOk() */ @Override public void checkResponseCodeOk() throws UnexpectedHttpStatusException { if(mResponseCode != HTTP_OK) { throw new UnexpectedHttpStatusException(mResponseCode, HTTP_OK); } } /* (non-Javadoc) * @see com.robotoworks.mechanoid.net.Response2#checkResponseCode(int) */ @Override public void checkResponseCode(int responseCode) throws UnexpectedHttpStatusException { if(mResponseCode != responseCode) { throw new UnexpectedHttpStatusException(mResponseCode, HTTP_OK); } } /* (non-Javadoc) * @see com.robotoworks.mechanoid.net.Response2#getHeaders() */ @Override public Map<String, List<String>> getHeaders() { return mHeaders; } public HttpUrlConnectionResponse(HttpURLConnection conn, Parser<T> parser) throws ServiceException { mConn = conn; mParser = parser; try { mResponseCode = conn.getResponseCode(); mHeaders = conn.getHeaderFields(); } catch (Exception e) { throw new ServiceException(e); } } /* (non-Javadoc) * @see com.robotoworks.mechanoid.net.Response2#parse() */ @Override public T parse() throws ServiceException { if(mParsed) { return mContent; } try { InputStream stream = null; if(mInputBytes == null) { stream = getInputStream(); } else { if(mInputBytes.length > 0) { stream = new ByteArrayInputStream(mInputBytes); } } if(stream != null) { mContent = mParser.parse(stream); } } catch (Exception e) { throw new ServiceException(e); } mParsed = true; return mContent; } private InputStream getInputStream() throws IOException { // error stream is available only if there was a connection with the // server, the server returned an error and also returned some usefull // data. Example being status 404 with page to search for content. InputStream stream = mConn.getErrorStream(); if (stream != null) return stream; return mConn.getInputStream(); } /* (non-Javadoc) * @see com.robotoworks.mechanoid.net.Response2#readAsText() */ @Override public String readAsText() throws IOException { if(mInputBytes == null) { InputStream stream = getInputStream(); if(stream == null) { mInputBytes = new byte[]{}; } else { mInputBytes = Streams.readAllBytes(getInputStream()); } } return Streams.readAllText(new ByteArrayInputStream(mInputBytes)); } }