/*
* Copyright 2010 Alibaba Group Holding Limited.
* All rights reserved.
*
* 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 com.alibaba.citrus.service.requestcontext.session.encoder;
import static com.alibaba.citrus.util.ArrayUtil.*;
import static com.alibaba.citrus.util.Assert.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Map;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
import org.apache.commons.codec.binary.Base64;
import com.alibaba.citrus.service.requestcontext.session.SessionStore.StoreContext;
import com.alibaba.citrus.service.requestcontext.session.encrypter.Encrypter;
import com.alibaba.citrus.service.requestcontext.session.serializer.Serializer;
import com.alibaba.citrus.service.requestcontext.session.serializer.impl.HessianSerializer;
import com.alibaba.citrus.springext.support.BeanSupport;
import com.alibaba.citrus.util.io.ByteArrayOutputStream;
/**
* ͨ��<code>Serializer</code>�ṩ�����л���������������Լ������ַ�����
* <p>
* ���벽��Ϊ��
* </p>
* <ul>
* <li>��<code>Serializer</code>���л���Ĭ��ʹ��<code>HessianSerializer</code>��</li>
* <li>ѹ����</li>
* <li>���<code>Encrypter</code>���ڣ��������ܣ��������ܡ�</li>
* <li>Base64���롣</li>
* <li>URL encoding����ȷ�������ַ�������HTTP header��Ҫ��</li>
* </ul>
* <p>
* ���벽���෴��
* </p>
*
* @author Michael Zhou
*/
public abstract class AbstractSerializationEncoder extends BeanSupport implements SessionEncoder {
protected Serializer serializer;
protected Encrypter encrypter;
@Override
protected void init() throws Exception {
if (serializer == null) {
serializer = new HessianSerializer();
}
}
/**
* ���롣
*/
public String encode(Map<String, Object> attrs, StoreContext storeContext) throws SessionEncoderException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 1. ���л�
// 2. ѹ��
Deflater def = new Deflater(Deflater.BEST_COMPRESSION, false);
DeflaterOutputStream dos = new DeflaterOutputStream(baos, def);
try {
serializer.serialize(assertNotNull(attrs, "objectToEncode is null"), dos);
} catch (Exception e) {
throw new SessionEncoderException("Failed to encode session state", e);
} finally {
try {
dos.close();
} catch (IOException e) {
}
def.end();
}
byte[] plaintext = baos.toByteArray().toByteArray();
// 3. ����
byte[] cryptotext = encrypt(plaintext);
// 4. base64����
try {
String encodedValue = new String(Base64.encodeBase64(cryptotext, false), "ISO-8859-1");
return URLEncoder.encode(encodedValue, "ISO-8859-1");
} catch (UnsupportedEncodingException e) {
throw new SessionEncoderException("Failed to encode session state", e);
}
}
/**
* ���ܡ�
*/
private byte[] encrypt(byte[] plaintext) throws SessionEncoderException {
if (encrypter != null) {
return encrypter.encrypt(plaintext);
}
return plaintext;
}
/**
* ���롣
*/
public Map<String, Object> decode(String encodedValue, StoreContext storeContext) throws SessionEncoderException {
// 1. base64����
byte[] cryptotext = null;
try {
encodedValue = URLDecoder.decode(assertNotNull(encodedValue, "encodedValue is null"), "ISO-8859-1");
cryptotext = Base64.decodeBase64(encodedValue.getBytes("ISO-8859-1"));
if (isEmptyArray(cryptotext)) {
throw new SessionEncoderException("Session state is empty: " + encodedValue);
}
} catch (Exception e) {
throw new SessionEncoderException("Failed to decode session state: ", e);
}
// 2. ����
byte[] plaintext = decrypt(cryptotext);
if (isEmptyArray(plaintext)) {
throw new SessionEncoderException("Decrypted session state is empty: " + encodedValue);
}
// 3. ��ѹ��
ByteArrayInputStream bais = new ByteArrayInputStream(plaintext);
Inflater inf = new Inflater(false);
InflaterInputStream iis = new InflaterInputStream(bais, inf);
// 4. �����л�
try {
@SuppressWarnings("unchecked")
Map<String, Object> attrs = (Map<String, Object>) serializer.deserialize(iis);
return attrs;
} catch (Exception e) {
throw new SessionEncoderException("Failed to parse session state", e);
} finally {
try {
iis.close();
} catch (IOException e) {
}
inf.end();
}
}
/**
* ���ܡ�
*/
private byte[] decrypt(byte[] cryptotext) throws SessionEncoderException {
if (encrypter != null) {
return encrypter.decrypt(cryptotext);
}
return cryptotext;
}
@Override
public String toString() {
return getClass().getSimpleName() + "[" + serializer + ", " + (encrypter == null ? "no encrypter" : encrypter)
+ "]";
}
}