KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tapestry > record > PersistentPropertyDataEncoderImpl


1 // Copyright 2005 The Apache Software Foundation
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15 package org.apache.tapestry.record;
16
17 import java.io.BufferedInputStream JavaDoc;
18 import java.io.BufferedOutputStream JavaDoc;
19 import java.io.ByteArrayInputStream JavaDoc;
20 import java.io.ByteArrayOutputStream JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.InputStream JavaDoc;
23 import java.io.ObjectInputStream JavaDoc;
24 import java.io.ObjectOutputStream JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.zip.GZIPInputStream JavaDoc;
30 import java.util.zip.GZIPOutputStream JavaDoc;
31
32 import org.apache.commons.codec.binary.Base64;
33 import org.apache.hivemind.ApplicationRuntimeException;
34 import org.apache.hivemind.HiveMind;
35 import org.apache.hivemind.util.Defense;
36 import org.apache.tapestry.util.io.TeeOutputStream;
37
38 /**
39  * Responsible for converting lists of {@link org.apache.tapestry.record.PropertyChange}s back and
40  * forth to a URL safe encoded string.
41  * <p>
42  * A possible improvement would be to encode the binary data with encryption both on and off, and
43  * select the shortest (prefixing with a character that identifies whether encryption should be used
44  * to decode).
45  *
46  * @author Howard M. Lewis Ship
47  * @since 4.0
48  */

49 public class PersistentPropertyDataEncoderImpl implements PersistentPropertyDataEncoder
50 {
51     /**
52      * Prefix on the MIME encoding that indicates that the encoded data is not encoded.
53      */

54
55     public static final String JavaDoc BYTESTREAM_PREFIX = "B";
56
57     /**
58      * Prefix on the MIME encoding that indicates that the encoded data is encoded with GZIP.
59      */

60
61     public static final String JavaDoc GZIP_BYTESTREAM_PREFIX = "Z";
62
63     public String JavaDoc encodePageChanges(List JavaDoc changes)
64     {
65         Defense.notNull(changes, "changes");
66
67         if (changes.isEmpty())
68             return "";
69
70         try
71         {
72             ByteArrayOutputStream JavaDoc bosPlain = new ByteArrayOutputStream JavaDoc();
73             ByteArrayOutputStream JavaDoc bosCompressed = new ByteArrayOutputStream JavaDoc();
74
75             GZIPOutputStream JavaDoc gos = new GZIPOutputStream JavaDoc(bosCompressed);
76
77             TeeOutputStream tos = new TeeOutputStream(bosPlain, gos);
78
79             ObjectOutputStream JavaDoc oos = new ObjectOutputStream JavaDoc(new BufferedOutputStream JavaDoc(tos));
80
81             writeChangesToStream(changes, oos);
82
83             oos.close();
84
85             boolean useCompressed = bosCompressed.size() < bosPlain.size();
86
87             byte[] data = useCompressed ? bosCompressed.toByteArray() : bosPlain.toByteArray();
88
89             byte[] encoded = Base64.encodeBase64(data);
90
91             String JavaDoc prefix = useCompressed ? GZIP_BYTESTREAM_PREFIX : BYTESTREAM_PREFIX;
92
93             return prefix + new String JavaDoc(encoded);
94         }
95         catch (Exception JavaDoc ex)
96         {
97             throw new ApplicationRuntimeException(RecordMessages.encodeFailure(ex), ex);
98         }
99     }
100
101     public List JavaDoc decodePageChanges(String JavaDoc encoded)
102     {
103         if (HiveMind.isBlank(encoded))
104             return Collections.EMPTY_LIST;
105
106         String JavaDoc prefix = encoded.substring(0, 1);
107
108         if (!(prefix.equals(BYTESTREAM_PREFIX) || prefix.equals(GZIP_BYTESTREAM_PREFIX)))
109             throw new ApplicationRuntimeException(RecordMessages.unknownPrefix(prefix));
110
111         try
112         {
113             // Strip off the prefix, feed that in as a MIME stream.
114

115             byte[] decoded = Base64.decodeBase64(encoded.substring(1).getBytes());
116
117             InputStream JavaDoc is = new ByteArrayInputStream JavaDoc(decoded);
118
119             if (prefix.equals(GZIP_BYTESTREAM_PREFIX))
120                 is = new GZIPInputStream JavaDoc(is);
121
122             // I believe this is more efficient; the buffered input stream should ask the
123
// GZIP stream for large blocks of un-gzipped bytes, with should be more efficient.
124
// The object input stream will probably be looking for just a few bytes at
125
// a time.
126

127             ObjectInputStream JavaDoc ois = new ObjectInputStream JavaDoc(new BufferedInputStream JavaDoc(is));
128
129             List JavaDoc result = readChangesFromStream(ois);
130
131             ois.close();
132
133             return result;
134         }
135         catch (Exception JavaDoc ex)
136         {
137             throw new ApplicationRuntimeException(RecordMessages.decodeFailure(ex), ex);
138         }
139     }
140
141     private void writeChangesToStream(List JavaDoc changes, ObjectOutputStream JavaDoc oos) throws IOException JavaDoc
142     {
143         oos.writeInt(changes.size());
144
145         Iterator JavaDoc i = changes.iterator();
146         while (i.hasNext())
147         {
148             PropertyChange pc = (PropertyChange) i.next();
149
150             String JavaDoc componentPath = pc.getComponentPath();
151             String JavaDoc propertyName = pc.getPropertyName();
152             Object JavaDoc value = pc.getNewValue();
153
154             oos.writeBoolean(componentPath != null);
155
156             if (componentPath != null)
157                 oos.writeUTF(componentPath);
158
159             oos.writeUTF(propertyName);
160             oos.writeObject(value);
161         }
162     }
163
164     private List JavaDoc readChangesFromStream(ObjectInputStream JavaDoc ois) throws IOException JavaDoc,
165             ClassNotFoundException JavaDoc
166     {
167         List JavaDoc result = new ArrayList JavaDoc();
168
169         int count = ois.readInt();
170
171         for (int i = 0; i < count; i++)
172         {
173             boolean hasPath = ois.readBoolean();
174             String JavaDoc componentPath = hasPath ? ois.readUTF() : null;
175             String JavaDoc propertyName = ois.readUTF();
176             Object JavaDoc value = ois.readObject();
177
178             PropertyChangeImpl pc = new PropertyChangeImpl(componentPath, propertyName, value);
179
180             result.add(pc);
181         }
182
183         return result;
184     }
185 }
Popular Tags