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.HttpEntityEnclosingRequest; 034import org.apache.http.HttpException; 035import org.apache.http.HttpRequest; 036import org.apache.http.entity.ContentType; 037import org.apache.http.nio.ContentDecoder; 038import org.apache.http.nio.IOControl; 039import org.apache.http.protocol.HttpContext; 040 041/** 042 * Abstract {@link HttpAsyncRequestConsumer} implementation that relieves its 043 * subclasses from having to manage internal state and provides a number of protected 044 * event methods that they need to implement. 045 * 046 * @since 4.2 047 */ 048public abstract class AbstractAsyncRequestConsumer<T> implements HttpAsyncRequestConsumer<T> { 049 050 private final AtomicBoolean completed; 051 052 private volatile T result; 053 private volatile Exception ex; 054 055 public AbstractAsyncRequestConsumer() { 056 super(); 057 this.completed = new AtomicBoolean(false); 058 } 059 060 /** 061 * Invoked when a HTTP request message is received. Please note 062 * that the {@link #onContentReceived(ContentDecoder, IOControl)} method 063 * will be invoked only for if the request message implements 064 * {@link HttpEntityEnclosingRequest} interface and has a content 065 * entity enclosed. 066 * 067 * @param request HTTP request message. 068 * @throws HttpException in case of HTTP protocol violation 069 * @throws IOException in case of an I/O error 070 */ 071 protected abstract void onRequestReceived( 072 HttpRequest request) throws HttpException, IOException; 073 074 /** 075 * Invoked if the request message encloses a content entity. 076 * 077 * @param entity HTTP entity 078 * @param contentType expected content type. 079 * @throws IOException in case of an I/O error 080 */ 081 protected abstract void onEntityEnclosed( 082 HttpEntity entity, ContentType contentType) throws IOException; 083 084 /** 085 * Invoked to process a chunk of content from the {@link ContentDecoder}. 086 * The {@link IOControl} interface can be used to suspend input events 087 * if the consumer is temporarily unable to consume more content. 088 * <p> 089 * The consumer can use the {@link ContentDecoder#isCompleted()} method 090 * to find out whether or not the message content has been fully consumed. 091 * 092 * @param decoder content decoder. 093 * @param ioctrl I/O control of the underlying connection. 094 * @throws IOException in case of an I/O error 095 */ 096 protected abstract void onContentReceived( 097 ContentDecoder decoder, IOControl ioctrl) throws IOException; 098 099 /** 100 * Invoked to generate a result object from the received HTTP request 101 * message. 102 * 103 * @param context HTTP context. 104 * @return result of the request processing. 105 * @throws Exception in case of an abnormal termination. 106 */ 107 protected abstract T buildResult(HttpContext context) throws Exception; 108 109 /** 110 * Invoked to release all system resources currently allocated. 111 */ 112 protected abstract void releaseResources(); 113 114 /** 115 * Invoked when the consumer is being closed. 116 * @throws IOException may be thrown by subclassses 117 * 118 * @since 4.3 119 */ 120 protected void onClose() throws IOException { 121 } 122 123 /** 124 * Use {@link #onRequestReceived(HttpRequest)} instead. 125 */ 126 @Override 127 public final void requestReceived( 128 final HttpRequest request) throws HttpException, IOException { 129 onRequestReceived(request); 130 if (request instanceof HttpEntityEnclosingRequest) { 131 final HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); 132 if (entity != null) { 133 final ContentType contentType = ContentType.getOrDefault(entity); 134 onEntityEnclosed(entity, contentType); 135 } 136 } 137 } 138 139 /** 140 * Use {@link #onContentReceived(ContentDecoder, IOControl)} instead. 141 */ 142 @Override 143 public final void consumeContent( 144 final ContentDecoder decoder, final IOControl ioctrl) throws IOException { 145 onContentReceived(decoder, ioctrl); 146 } 147 148 /** 149 * Use {@link #buildResult(HttpContext)} instead. 150 */ 151 @Override 152 public final void requestCompleted(final HttpContext context) { 153 if (this.completed.compareAndSet(false, true)) { 154 try { 155 this.result = buildResult(context); 156 } catch (final Exception ex) { 157 this.ex = ex; 158 } finally { 159 releaseResources(); 160 } 161 } 162 } 163 164 @Override 165 public final void failed(final Exception ex) { 166 if (this.completed.compareAndSet(false, true)) { 167 this.ex = ex; 168 releaseResources(); 169 } 170 } 171 172 @Override 173 public final void close() throws IOException { 174 if (this.completed.compareAndSet(false, true)) { 175 releaseResources(); 176 onClose(); 177 } 178 } 179 180 @Override 181 public Exception getException() { 182 return this.ex; 183 } 184 185 @Override 186 public T getResult() { 187 return this.result; 188 } 189 190 @Override 191 public boolean isDone() { 192 return this.completed.get(); 193 } 194 195}