com.alibaba.citrus.service.requestcontext.session.encoder.AbstractSerializationEncoder.java Source code

Java tutorial

Introduction

Here is the source code for com.alibaba.citrus.service.requestcontext.session.encoder.AbstractSerializationEncoder.java

Source

/*
 * 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.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 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;
import org.apache.commons.codec.binary.Base64;

/**
 * <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) + "]";
    }
}