summaryrefslogtreecommitdiffstats
path: root/simple/simple-http/src/main/java/org/simpleframework/http/message/EntityConsumer.java
blob: 9cf12fbcb0fb90e273caf9815706b7598cccc2cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
 * EntityConsumer.java February 2007
 *
 * Copyright (C) 2001, Niall Gallagher <niallg@users.sf.net>
 *
 * 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 org.simpleframework.http.message;

import static org.simpleframework.http.core.ContainerEvent.BODY_FINISHED;
import static org.simpleframework.http.core.ContainerEvent.HEADER_FINISHED;
import static org.simpleframework.http.core.ContainerEvent.READ_BODY;
import static org.simpleframework.http.core.ContainerEvent.READ_HEADER;

import java.io.IOException;

import org.simpleframework.common.buffer.Allocator;
import org.simpleframework.transport.Channel;
import org.simpleframework.transport.ByteCursor;
import org.simpleframework.transport.trace.Trace;

/**
 * The <code>EntityConsumer</code> object is used to consume data
 * from a cursor and build a request entity. Each constituent part of
 * the entity is consumed from the pipeline and can be acquired from
 * this consumer object. The <code>Header</code> and <code>Body</code>
 * can be used to extract the individual parts of the entity.
 * 
 * @author Niall Gallagher
 */
public class EntityConsumer implements ByteConsumer {   
   
   /**
    * This is used to determine if there a continue is expected.
    */
   protected ContinueDispatcher dispatcher;   
   
   /**
    * This is used to create a body consumer for the entity.
    */
   protected ConsumerFactory factory;
   
   /**
    * This is used to consume the header for the request entity. 
    */
   protected RequestConsumer header;
   
   /**
    * This is used to consume the body for the request entity.
    */
   protected BodyConsumer body;
   
   /**
    * This is used to trace the progress of the request consumption.
    */
   protected Trace trace;
   
   /**
    * Constructor for the <code>EntityConsumer</code> object. This
    * is used to build an entity from the constituent parts. Once
    * all of the parts have been consumed they are available from
    * the exposed methods of this consumed instance.
    * 
    * @param allocator this is used to allocate the memory used
    * @param channel this is the channel used to send a response
    */
   public EntityConsumer(Allocator allocator, Channel channel) {
      this.header = new RequestConsumer();
      this.dispatcher = new ContinueDispatcher(channel);
      this.factory = new ConsumerFactory(allocator, header);
      this.trace = channel.getTrace();
   }
   
   /**
    * This is used to acquire the body for this HTTP entity. This
    * will return a body which can be used to read the content of
    * the message, also if the request is multipart upload then all
    * of the parts are provided as <code>Attachment</code> objects. 
    * Each part can then be read as an individual message.
    *  
    * @return the body provided by the HTTP request message
    */
   public Body getBody() {
      return body.getBody();
   }
   
   /**
    * This provides the HTTP request header for the entity. This is
    * always populated and provides the details sent by the client
    * such as the target URI and the query if specified. Also this
    * can be used to determine the method and protocol version used.
    * 
    * @return the header provided by the HTTP request message
    */
   public Header getHeader() {
      return header;
   }
   
   /**
    * This consumes the header and body from the cursor. The header
    * is consumed first followed by the body if there is any. There
    * is a body of there is a Content-Length or a Transfer-Encoding
    * header present. If there is no body then a substitute body 
    * is given which has an empty input stream.
    * 
    * @param cursor used to consumed the bytes for the entity
    */
   public void consume(ByteCursor cursor) throws IOException {
      while(cursor.isReady()) {
         if(header.isFinished()) {            
            if(body == null) {
               CharSequence sequence = header.getHeader();
               
               trace.trace(HEADER_FINISHED, sequence);
               body = factory.getInstance();    
            }
            trace.trace(READ_BODY);
            body.consume(cursor);            
            
            if(body.isFinished()) {
               trace.trace(BODY_FINISHED);
               break;
            }
         } else {
            trace.trace(READ_HEADER);
            header.consume(cursor);
         }
      }
      if(header.isFinished()) {
         if(body == null) {
            CharSequence sequence = header.getHeader();
            
            trace.trace(HEADER_FINISHED, sequence);
            dispatcher.execute(header);            
            body = factory.getInstance();
         } 
      }
   }   
   
   /**
    * This is determined finished when the body has been consumed.
    * If only the header has been consumed then the body will be
    * created using the header information, the body is then read
    * from the cursor, which may read nothing for an empty body.
    * 
    * @return this returns true if the entity has been built
    */
   public boolean isFinished() {
      if(header.isFinished()) {
         if(body == null) {
            CharSequence sequence = header.getHeader();
            
            trace.trace(HEADER_FINISHED, sequence);
            body = factory.getInstance();
         }
         return body.isFinished();
      } 
      return false;
   
   }
   
   /**
    * This is used to determine if the header has finished. Exposing
    * this method ensures the entity consumer can be used to determine
    * if the header for the entity can be consumed before fully
    * processing the entity body of the request message.
    * 
    * @return determines if the header has been fully consumed
    */
   public boolean isHeaderFinished() {
      return header.isFinished();
   }
}