/*
* Copyright (c) 2002-2012 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.valueencoder;
import static com.alibaba.citrus.util.StringUtil.*;
import java.beans.PropertyEditor;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
import com.alibaba.citrus.service.configuration.support.PropertyEditorRegistrarsSupport;
import com.alibaba.citrus.service.requestcontext.session.SessionStore.StoreContext;
import com.alibaba.citrus.service.requestcontext.session.encoder.SessionEncoderException;
import com.alibaba.citrus.service.requestcontext.session.encrypter.Encrypter;
import com.alibaba.citrus.springext.support.BeanSupport;
import com.alibaba.citrus.util.StringEscapeUtil;
import com.alibaba.citrus.util.io.StreamUtil;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.SimpleTypeConverter;
import org.springframework.beans.TypeConverter;
/**
* <code>SessionEncoder</code>针对非串行化场景的抽象编码实现,加密,base64来编码、解码。
*
* @author youqun.zhangyq
* @author Michael Zhou
*/
public abstract class AbstractSessionValueEncoder extends BeanSupport implements SessionValueEncoder {
private static final String DEFAULT_CHARSET = "UTF-8";
private PropertyEditorRegistrarsSupport propertyEditorRegistrars = new PropertyEditorRegistrarsSupport();
protected Encrypter encrypter;
private String charset;
public void setPropertyEditorRegistrars(PropertyEditorRegistrar[] registrars) {
propertyEditorRegistrars.setPropertyEditorRegistrars(registrars);
}
public void setEncrypter(Encrypter encrypter) {
this.encrypter = encrypter;
}
public String getCharset() {
return charset == null ? DEFAULT_CHARSET : charset;
}
public void setCharset(String charset) {
this.charset = trimToNull(charset);
}
protected abstract boolean doURLEncode();
protected abstract boolean doCompress();
public String encode(Object value, StoreContext storeContext) throws SessionValueEncoderException {
try {
String encodedValue = encodeValue(value);
// 如果提供了encrypter,则压缩并加密之
if (encrypter != null) {
encodedValue = new String(
Base64.encodeBase64(encrypter.encrypt(compress(encodedValue.getBytes("UTF-8")))), "8859_1");
}
// 如果加密,则必须进行url encoding
if (doURLEncode() || encrypter != null) {
encodedValue = StringEscapeUtil.escapeURL(encodedValue, getCharset());
}
return encodedValue;
} catch (Exception e) {
throw new SessionEncoderException("Failed to encode single value", e);
}
}
public Object decode(String encodedValue, StoreContext storeContext) throws SessionValueEncoderException {
try {
// 如果加密,则必须进行url decoding
if (doURLEncode() || encrypter != null) {
encodedValue = StringEscapeUtil.unescapeURL(encodedValue, getCharset());
}
// 如果提供了encrypter,则解密并解压缩之
if (encrypter != null) {
encodedValue = new String(decompress(encrypter.decrypt(Base64.decodeBase64(encodedValue
.getBytes("8859_1")))), "UTF-8");
}
return decodeValue(encodedValue);
} catch (Exception e) {
throw new SessionEncoderException("Failed to decode single value", e);
}
}
private byte[] compress(byte[] data) throws SessionValueEncoderException {
if (!doCompress()) {
return data;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Deflater def = new Deflater(Deflater.BEST_COMPRESSION, false);
DeflaterOutputStream dos = new DeflaterOutputStream(baos, def);
try {
dos.write(data);
} catch (Exception e) {
throw new SessionValueEncoderException(e);
} finally {
try {
dos.close();
} catch (IOException e) {
}
def.end();
}
return baos.toByteArray();
}
private byte[] decompress(byte[] data) throws SessionValueEncoderException {
if (!doCompress()) {
return data;
}
ByteArrayInputStream bais = new ByteArrayInputStream(data);
Inflater inf = new Inflater(false);
InflaterInputStream iis = new InflaterInputStream(bais, inf);
try {
return StreamUtil.readBytes(iis, true).toByteArray();
} catch (Exception e) {
throw new SessionValueEncoderException(e);
} finally {
inf.end();
}
}
protected final TypeConverter getTypeConverter() {
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
propertyEditorRegistrars.registerCustomEditors(typeConverter);
return typeConverter;
}
protected final String convertToString(Class<?> type, Object value, TypeConverter converter) {
if (value instanceof String) {
return (String) value;
} else {
if (converter instanceof PropertyEditorRegistry && type != null && type.isInstance(value)) {
PropertyEditor editor = ((PropertyEditorRegistry) converter).findCustomEditor(type, null);
if (editor != null) {
editor.setValue(value);
return editor.getAsText();
}
}
return (String) getTypeConverter().convertIfNecessary(value, String.class);
}
}
protected final Object convertToType(Class<?> type, String encodedValue, TypeConverter converter) {
if (type != null && !type.equals(String.class)) {
return converter.convertIfNecessary(encodedValue, type);
} else {
return encodedValue;
}
}
protected abstract String encodeValue(Object value) throws Exception;
protected abstract Object decodeValue(String encodedValue) throws Exception;
}