001 // Copyright 2009, 2012 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry5.internal.services;
016
017 import org.apache.tapestry5.internal.util.Base64OutputStream;
018 import org.apache.tapestry5.internal.util.MacOutputStream;
019 import org.apache.tapestry5.internal.util.TeeOutputStream;
020 import org.apache.tapestry5.services.ClientDataSink;
021 import org.apache.tapestry5.services.URLEncoder;
022
023 import java.io.BufferedOutputStream;
024 import java.io.IOException;
025 import java.io.ObjectOutputStream;
026 import java.io.OutputStream;
027 import java.security.Key;
028 import java.util.zip.GZIPOutputStream;
029
030 public class ClientDataSinkImpl implements ClientDataSink
031 {
032 private final Base64OutputStream base64OutputStream;
033
034 private final ObjectOutputStream objectOutputStream;
035
036 private final URLEncoder urlEncoder;
037
038 private boolean closed;
039
040 private final MacOutputStream macOutputStream;
041
042 public ClientDataSinkImpl(URLEncoder urlEncoder, Key hmacKey) throws IOException
043 {
044 this.urlEncoder = urlEncoder;
045
046 base64OutputStream = new Base64OutputStream();
047 macOutputStream = MacOutputStream.streamFor(hmacKey);
048
049 final BufferedOutputStream pipeline = new BufferedOutputStream(new GZIPOutputStream(
050 new TeeOutputStream(macOutputStream, base64OutputStream)));
051
052 OutputStream guard = new OutputStream()
053 {
054 @Override
055 public void write(int b) throws IOException
056 {
057 pipeline.write(b);
058 }
059
060 @Override
061 public void close() throws IOException
062 {
063 closed = true;
064
065 pipeline.close();
066 }
067
068 @Override
069 public void flush() throws IOException
070 {
071 pipeline.flush();
072 }
073
074 @Override
075 public void write(byte[] b) throws IOException
076 {
077 pipeline.write(b);
078 }
079
080 @Override
081 public void write(byte[] b, int off, int len) throws IOException
082 {
083 pipeline.write(b, off, len);
084 }
085 };
086
087
088 objectOutputStream = new ObjectOutputStream(guard);
089 }
090
091 public ObjectOutputStream getObjectOutputStream()
092 {
093 return objectOutputStream;
094 }
095
096 public String getClientData()
097 {
098 if (!closed)
099 {
100 try
101 {
102 objectOutputStream.close();
103 } catch (IOException ex)
104 {
105 // Ignore.
106 }
107 }
108
109 return macOutputStream.getResult() + ":" + base64OutputStream.toBase64();
110 }
111
112 public String getEncodedClientData()
113 {
114 return urlEncoder.encode(getClientData());
115 }
116 }