1 /*
2 * ====================================================================
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 * ====================================================================
20 *
21 * This software consists of voluntary contributions made by many
22 * individuals on behalf of the Apache Software Foundation. For more
23 * information on the Apache Software Foundation, please see
24 * <http://www.apache.org/>.
25 *
26 */
27 package org.apache.http.nio.protocol;
28
29 import java.io.IOException;
30
31 import org.apache.http.HttpEntity;
32 import org.apache.http.HttpEntityEnclosingRequest;
33 import org.apache.http.HttpException;
34 import org.apache.http.HttpRequest;
35 import org.apache.http.annotation.ThreadSafe;
36 import org.apache.http.entity.ContentType;
37 import org.apache.http.nio.ContentDecoder;
38 import org.apache.http.nio.IOControl;
39 import org.apache.http.protocol.HttpContext;
40
41 /**
42 * Abstract {@link HttpAsyncRequestConsumer} implementation that relieves its
43 * subclasses form having to synchronize access to internal instance variables
44 * and provides a number of protected methods that they need to implement.
45 *
46 * @since 4.2
47 */
48 @ThreadSafe
49 public abstract class AbstractAsyncRequestConsumer<T> implements HttpAsyncRequestConsumer<T> {
50
51 private volatile boolean completed;
52 private volatile T result;
53 private volatile Exception ex;
54
55 public AbstractAsyncRequestConsumer() {
56 super();
57 }
58
59 /**
60 * Invoked when a HTTP request message is received. Please note
61 * that the {@link #onContentReceived(ContentDecoder, IOControl)} method
62 * will be invoked only for if the request message implements
63 * {@link HttpEntityEnclosingRequest} interface and has a content
64 * entity enclosed.
65 *
66 * @param request HTTP request message.
67 * @throws HttpException in case of HTTP protocol violation
68 * @throws IOException in case of an I/O error
69 */
70 protected abstract void onRequestReceived(
71 HttpRequest request) throws HttpException, IOException;
72
73 /**
74 * Invoked if the request message encloses a content entity.
75 *
76 * @param entity HTTP entity
77 * @param contentType expected content type.
78 * @throws IOException in case of an I/O error
79 */
80 protected abstract void onEntityEnclosed(
81 HttpEntity entity, ContentType contentType) throws IOException;
82
83 /**
84 * Invoked to process a chunk of content from the {@link ContentDecoder}.
85 * The {@link IOControl} interface can be used to suspend input events
86 * if the consumer is temporarily unable to consume more content.
87 * <p/>
88 * The consumer can use the {@link ContentDecoder#isCompleted()} method
89 * to find out whether or not the message content has been fully consumed.
90 *
91 * @param decoder content decoder.
92 * @param ioctrl I/O control of the underlying connection.
93 * @throws IOException in case of an I/O error
94 */
95 protected abstract void onContentReceived(
96 ContentDecoder decoder, IOControl ioctrl) throws IOException;
97
98 /**
99 * Invoked to generate a result object from the received HTTP request
100 * message.
101 *
102 * @param context HTTP context.
103 * @return result of the request processing.
104 * @throws Exception in case of an abnormal termination.
105 */
106 protected abstract T buildResult(HttpContext context) throws Exception;
107
108 /**
109 * Invoked to release all system resources currently allocated.
110 */
111 protected abstract void releaseResources();
112
113 /**
114 * Use {@link #onRequestReceived(HttpRequest)} instead.
115 */
116 public final synchronized void requestReceived(
117 final HttpRequest request) throws HttpException, IOException {
118 onRequestReceived(request);
119 if (request instanceof HttpEntityEnclosingRequest) {
120 final HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
121 if (entity != null) {
122 final ContentType contentType = ContentType.getOrDefault(entity);
123 onEntityEnclosed(entity, contentType);
124 }
125 }
126 }
127
128 /**
129 * Use {@link #onContentReceived(ContentDecoder, IOControl)} instead.
130 */
131 public final synchronized void consumeContent(
132 final ContentDecoder decoder, final IOControl ioctrl) throws IOException {
133 onContentReceived(decoder, ioctrl);
134 }
135
136 /**
137 * Use {@link #buildResult(HttpContext)} instead.
138 */
139 public final synchronized void requestCompleted(final HttpContext context) {
140 if (this.completed) {
141 return;
142 }
143 this.completed = true;
144 try {
145 this.result = buildResult(context);
146 } catch (final Exception ex) {
147 this.ex = ex;
148 } finally {
149 releaseResources();
150 }
151 }
152
153 public final synchronized void failed(final Exception ex) {
154 if (this.completed) {
155 return;
156 }
157 this.completed = true;
158 this.ex = ex;
159 releaseResources();
160 }
161
162 public final synchronized void close() throws IOException {
163 if (this.completed) {
164 return;
165 }
166 this.completed = true;
167 releaseResources();
168 }
169
170 public Exception getException() {
171 return this.ex;
172 }
173
174 public T getResult() {
175 return this.result;
176 }
177
178 public boolean isDone() {
179 return this.completed;
180 }
181
182 }