001/* 002 * ==================================================================== 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 * ==================================================================== 020 * 021 * This software consists of voluntary contributions made by many 022 * individuals on behalf of the Apache Software Foundation. For more 023 * information on the Apache Software Foundation, please see 024 * <http://www.apache.org/>. 025 * 026 */ 027package org.apache.http.nio.protocol; 028 029import java.io.IOException; 030import java.util.concurrent.atomic.AtomicBoolean; 031 032import org.apache.http.HttpEntity; 033import org.apache.http.HttpException; 034import org.apache.http.HttpResponse; 035import org.apache.http.entity.ContentType; 036import org.apache.http.nio.ContentDecoder; 037import org.apache.http.nio.IOControl; 038import org.apache.http.protocol.HttpContext; 039 040/** 041 * Abstract {@link HttpAsyncResponseConsumer} implementation that relieves its 042 * subclasses from having to manage internal state and provides a number of protected 043 * event methods that they need to implement. 044 * 045 * @since 4.2 046 */ 047public abstract class AbstractAsyncResponseConsumer<T> implements HttpAsyncResponseConsumer<T> { 048 049 private final AtomicBoolean completed; 050 051 private volatile T result; 052 private volatile Exception ex; 053 054 public AbstractAsyncResponseConsumer() { 055 super(); 056 this.completed = new AtomicBoolean(false); 057 } 058 059 /** 060 * Invoked when a HTTP response message is received. Please note 061 * that the {@link #onContentReceived(ContentDecoder, IOControl)} method 062 * will be invoked only if the response messages has a content entity 063 * enclosed. 064 * 065 * @param response HTTP response message. 066 * @throws HttpException in case of HTTP protocol violation 067 * @throws IOException in case of an I/O error 068 */ 069 protected abstract void onResponseReceived( 070 HttpResponse response) throws HttpException, IOException; 071 072 /** 073 * Invoked to process a chunk of content from the {@link ContentDecoder}. 074 * The {@link IOControl} interface can be used to suspend input events 075 * if the consumer is temporarily unable to consume more content. 076 * <p> 077 * The consumer can use the {@link ContentDecoder#isCompleted()} method 078 * to find out whether or not the message content has been fully consumed. 079 * 080 * @param decoder content decoder. 081 * @param ioctrl I/O control of the underlying connection. 082 * @throws IOException in case of an I/O error 083 */ 084 protected abstract void onContentReceived( 085 ContentDecoder decoder, IOControl ioctrl) throws IOException; 086 087 /** 088 * Invoked if the response message encloses a content entity. 089 * 090 * @param entity HTTP entity 091 * @param contentType expected content type. 092 * @throws IOException in case of an I/O error 093 */ 094 protected abstract void onEntityEnclosed( 095 HttpEntity entity, ContentType contentType) throws IOException; 096 097 /** 098 * Invoked to generate a result object from the received HTTP response 099 * message. 100 * 101 * @param context HTTP context. 102 * @return result of the response processing. 103 * @throws Exception in case of an abnormal termination. 104 */ 105 protected abstract T buildResult(HttpContext context) throws Exception; 106 107 /** 108 * Invoked to release all system resources currently allocated. 109 */ 110 protected abstract void releaseResources(); 111 112 /** 113 * Invoked when the consumer is being closed. 114 * @throws IOException may be thrown by subclassses 115 * 116 * @since 4.3 117 */ 118 protected void onClose() throws IOException { 119 } 120 121 /** 122 * @since 4.4 123 */ 124 protected ContentType getContentType(final HttpEntity entity) { 125 return entity != null ? ContentType.getOrDefault(entity) : null; 126 } 127 128 /** 129 * Use {@link #onResponseReceived(HttpResponse)} instead. 130 */ 131 @Override 132 public final void responseReceived( 133 final HttpResponse response) throws IOException, HttpException { 134 onResponseReceived(response); 135 final HttpEntity entity = response.getEntity(); 136 if (entity != null) { 137 onEntityEnclosed(entity, getContentType(entity)); 138 } 139 } 140 141 /** 142 * Use {@link #onContentReceived(ContentDecoder, IOControl)} instead. 143 */ 144 @Override 145 public final void consumeContent( 146 final ContentDecoder decoder, final IOControl ioctrl) throws IOException { 147 onContentReceived(decoder, ioctrl); 148 } 149 150 /** 151 * Use {@link #buildResult(HttpContext)} instead. 152 */ 153 @Override 154 public final void responseCompleted(final HttpContext context) { 155 if (this.completed.compareAndSet(false, true)) { 156 try { 157 this.result = buildResult(context); 158 } catch (final Exception ex) { 159 this.ex = ex; 160 } finally { 161 releaseResources(); 162 } 163 } 164 } 165 166 @Override 167 public final boolean cancel() { 168 if (this.completed.compareAndSet(false, true)) { 169 releaseResources(); 170 return true; 171 } 172 return false; 173 } 174 175 @Override 176 public final void failed(final Exception ex) { 177 if (this.completed.compareAndSet(false, true)) { 178 this.ex = ex; 179 releaseResources(); 180 } 181 } 182 183 @Override 184 public final void close() throws IOException { 185 if (this.completed.compareAndSet(false, true)) { 186 releaseResources(); 187 onClose(); 188 } 189 } 190 191 @Override 192 public Exception getException() { 193 return this.ex; 194 } 195 196 @Override 197 public T getResult() { 198 return this.result; 199 } 200 201 @Override 202 public boolean isDone() { 203 return this.completed.get(); 204 } 205 206}