corner.protobuf.ProtocolBuffersModule.java Source code

Java tutorial

Introduction

Here is the source code for corner.protobuf.ProtocolBuffersModule.java

Source

/* 
 * Copyright 2009 The Corner Team.
 * 
 * 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 corner.protobuf;

import java.util.Collection;

import org.apache.commons.codec.binary.Base64;
import org.apache.tapestry5.ValueEncoder;
import org.apache.tapestry5.internal.InternalConstants;
import org.apache.tapestry5.ioc.MappedConfiguration;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
import org.apache.tapestry5.ioc.services.ClassNameLocator;
import org.apache.tapestry5.ioc.services.Coercion;
import org.apache.tapestry5.services.ValueEncoderFactory;

import corner.orm.model.PaginationOptions;

/**
 * ?<a href="http://code.google.com/p/protobuf/">Google protocol buffer</a>Value Encoder.
 * ??Object<->String?,?.
 * 
 * @author dong
 * @author <a href="jun.tsai@ganshane.net">Jun Tsai</a>
 * @version $Revision$
 * @since 0.0.1
 */
public class ProtocolBuffersModule {

    public static void contributeValueEncoderSource(MappedConfiguration<Class, ValueEncoderFactory> configuration,
            final ClassNameLocator classNameLocator,
            @Inject @Symbol(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM) String appRootPackage) {
        final String protoPackage = appRootPackage + ".protobuf";
        final Collection<String> protoClasses = classNameLocator.locateClassNames(protoPackage);
        final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        for (String className : protoClasses) {
            addProtobufferCoercer(configuration, contextClassLoader, className);
        }
        //add PaginationOptions class type coercer
        addProtobufferCoercer(configuration, contextClassLoader, PaginationOptions.class.getName());
    }

    private static void addProtobufferCoercer(MappedConfiguration<Class, ValueEncoderFactory> configuration,
            ClassLoader contextClassLoader, String className) {

        try {
            Class protoClass = contextClassLoader.loadClass(className);

            //?classProtocolBuffer??
            if (ProtocolBuffer.class.isAssignableFrom(protoClass)) {
                final ValueEncoderFactory factory = new ValueEncoderFactory() {
                    /**
                     * @see org.apache.tapestry5.services.ValueEncoderFactory#create(java.lang.Class)
                     */
                    @Override
                    @SuppressWarnings("unchecked")
                    public ValueEncoder create(Class type) {
                        return new ProtoValueEncoder(type);
                    }
                };
                configuration.add(protoClass, factory);
            }
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * ProtobufEncoder
     * @author dong
     * @author <a href="jun.tsai@ganshane.net">Jun Tsai</a>
     * @version $Revision$
     * @since 0.0.1
     */
    public static class ProtoValueEncoder<T extends ProtocolBuffer> implements ValueEncoder<T> {
        final Coercion<T, String> proto2string = new Object2ProtoStringCoercion<T>();
        final Coercion<String, T> string2proto;

        public ProtoValueEncoder(Class<T> type) {
            string2proto = new ProtoString2ObjectCoercion<T>(type);
        }

        /**
         * @see org.apache.tapestry5.ValueEncoder#toClient(java.lang.Object)
         */
        @Override
        public String toClient(T value) {
            return proto2string.coerce(value);
        }

        /**
         * @see org.apache.tapestry5.ValueEncoder#toValue(java.lang.String)
         */
        @Override
        public T toValue(String clientValue) {
            return this.string2proto.coerce(clientValue);
        }
    }

    /**
     * String Protobuffer
     * 
     * @author dong
     * @author <a href="jun.tsai@ganshane.net">Jun Tsai</a>
     * @version $Revision$
     * @since 0.0.1
     */
    static class ProtoString2ObjectCoercion<T extends ProtocolBuffer> implements Coercion<String, T> {
        private final Class<T> type;

        public ProtoString2ObjectCoercion(Class<T> type) {
            this.type = type;
        }

        /**
         * @see org.apache.tapestry5.ioc.services.Coercion#coerce(java.lang.Object)
         */
        @Override
        public T coerce(String input) {
            if (input == null) {
                return null;
            }

            T obj = null;
            try {
                obj = this.type.newInstance();
                if ("X".equals(input)) {
                    return obj;
                }
                //base64?
                byte[] _b64 = Base64.decodeBase64(input.getBytes());
                //??????
                obj.mergeData(_b64);
                return obj;
            } catch (Throwable te) {
                throw new RuntimeException(te);
            }
        }

    }

    /**
     * Protobufstring?
     * @author dong
     * @author <a href="jun.tsai@ganshane.net">Jun Tsai</a>
     * @version $Revision$
     * @since 0.0.1
     */
    static class Object2ProtoStringCoercion<T extends ProtocolBuffer> implements Coercion<T, String> {
        /**
         * @see org.apache.tapestry5.ioc.services.Coercion#coerce(java.lang.Object)
         */
        @Override
        public String coerce(T input) {
            if (input == null) {
                return null;
            }
            String str = new String(Base64.encodeBase64(input.getData()));
            if (InternalUtils.isBlank(str)) {
                return "X";
            }
            return str;
        }
    }
}