1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.mimo.netty.handler.codec.icap;
15
16 import java.io.UnsupportedEncodingException;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.StringTokenizer;
22
23 import org.jboss.netty.buffer.ChannelBuffer;
24
25
26
27
28
29
30
31
32 public final class Encapsulated {
33
34 private List<Entry> entries;
35
36 public Encapsulated() {
37 entries = new ArrayList<Encapsulated.Entry>();
38 }
39
40
41
42
43
44
45 public Encapsulated(String headerValue) {
46 this();
47 parseHeaderValue(headerValue);
48 }
49
50
51
52
53
54
55
56 public boolean containsEntry(IcapMessageElementEnum entity) {
57 for(Entry entry : entries) {
58 if(entry.getName().equals(entity)) {
59 return true;
60 }
61 }
62 return false;
63 }
64
65
66
67
68
69
70
71
72 public IcapMessageElementEnum containsBodyEntry() {
73 IcapMessageElementEnum body = null;
74 for(Entry entry : entries) {
75 if(entry.getName().equals(IcapMessageElementEnum.OPTBODY)) {
76 body = entry.getName();
77 break;
78 } else if(entry.getName().equals(IcapMessageElementEnum.REQBODY)) {
79 body = entry.getName();
80 break;
81 } else if(entry.getName().equals(IcapMessageElementEnum.RESBODY)) {
82 body = entry.getName();
83 break;
84 } else if(entry.getName().equals(IcapMessageElementEnum.NULLBODY)) {
85 body = entry.getName();
86 break;
87 }
88 }
89 return body;
90 }
91
92
93
94
95
96
97
98
99
100 public IcapMessageElementEnum getNextEntry() {
101 IcapMessageElementEnum entryName = null;
102 for(Entry entry : entries) {
103 if(!entry.isProcessed()) {
104 entryName = entry.getName();
105 break;
106 }
107 }
108 return entryName;
109 }
110
111
112
113
114
115
116
117 public void setEntryAsProcessed(IcapMessageElementEnum entryName) {
118 Entry entry = getEntryByName(entryName);
119 if(entry != null) {
120 entry.setIsProcessed();
121 }
122 }
123
124
125
126
127
128
129
130 public void addEntry(IcapMessageElementEnum name, int position) {
131 Entry entry = new Entry(name,position);
132 entries.add(entry);
133 }
134
135
136
137
138
139
140
141
142 public int encode(ChannelBuffer buffer) throws UnsupportedEncodingException {
143 int index = buffer.readableBytes();
144 Collections.sort(entries);
145 buffer.writeBytes("Encapsulated: ".getBytes(IcapCodecUtil.ASCII_CHARSET));
146 Iterator<Entry> entryIterator = entries.iterator();
147 while(entryIterator.hasNext()) {
148 Entry entry = entryIterator.next();
149 buffer.writeBytes(entry.getName().getValue().getBytes(IcapCodecUtil.ASCII_CHARSET));
150 buffer.writeBytes("=".getBytes(IcapCodecUtil.ASCII_CHARSET));
151 buffer.writeBytes(Integer.toString(entry.getPosition()).getBytes(IcapCodecUtil.ASCII_CHARSET));
152 if(entryIterator.hasNext()) {
153 buffer.writeByte(',');
154 buffer.writeByte(IcapCodecUtil.SPACE);
155 }
156 }
157 buffer.writeBytes(IcapCodecUtil.CRLF);
158 buffer.writeBytes(IcapCodecUtil.CRLF);
159 return buffer.readableBytes() - index;
160 }
161
162
163
164
165
166
167
168
169 private void parseHeaderValue(String headerValue) {
170 if(headerValue == null) {
171 throw new IcapDecodingError("No value associated with Encapsualted header");
172 }
173 StringTokenizer tokenizer = new StringTokenizer(headerValue,",");
174 while(tokenizer.hasMoreTokens()) {
175 String parameterString = tokenizer.nextToken();
176 if(parameterString != null) {
177 String[] parameter = splitParameter(parameterString.trim());
178 try {
179 int value = Integer.parseInt(parameter[1]);
180 Entry entry = new Entry(IcapMessageElementEnum.fromString(parameter[0]),value);
181 entries.add(entry);
182 } catch(NumberFormatException nfe) {
183 throw new IcapDecodingError("the Encapsulated header value [" + parameter[1] + "] for the key [" + parameter[0] + "] is not a number");
184 }
185 }
186 }
187 Collections.sort(entries);
188 }
189
190 private String[] splitParameter(String parameter) {
191 int offset = parameter.indexOf('=');
192 if(offset <= 0) {
193 throw new IcapDecodingError("Encapsulated header value was not understood [" + parameter + "]");
194 }
195 String key = parameter.substring(0,offset);
196 String value = parameter.substring(offset + 1,parameter.length());
197 if(value.contains(",")) {
198 value = value.substring(0,value.indexOf(','));
199 }
200 return new String[]{key.trim(),value};
201 }
202
203 private Entry getEntryByName(IcapMessageElementEnum entryName) {
204 Entry returnValue = null;
205 for(Entry entry : entries) {
206 if(entry.getName().equals(entryName)) {
207 returnValue = entry;
208 break;
209 }
210 }
211 return returnValue;
212 }
213
214 private final static class Entry implements Comparable<Entry> {
215
216 private final IcapMessageElementEnum name;
217 private final Integer position;
218 private boolean processed;
219
220 public Entry(IcapMessageElementEnum name, Integer position) {
221 this.name = name;
222 this.position = position;
223 }
224
225 public IcapMessageElementEnum getName() {
226 return name;
227 }
228
229 public int getPosition() {
230 return position;
231 }
232
233 public void setIsProcessed() {
234 processed = true;
235 }
236
237 public boolean isProcessed() {
238 return processed;
239 }
240
241 @Override
242 public int compareTo(Entry entry) {
243 if(this.name.equals(IcapMessageElementEnum.NULLBODY)) {
244 return 1;
245 }
246 return this.position.compareTo(entry.position);
247 }
248
249 @Override
250 public String toString() {
251 return name + "=" + position + " : " + processed;
252 }
253 }
254
255 @Override
256 public String toString() {
257 StringBuilder builder = new StringBuilder();
258 builder.append("Encapsulated: ");
259 for(Entry entry : entries) {
260 if(entry != null) {
261 builder.append(" [").append(entry.toString()).append("] ");
262 }
263 }
264 return builder.toString();
265 }
266 }