001    // Copyright 2006-2007 Daniel Gredler
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 net.sf.beanform.prop;
016    
017    import net.sf.beanform.util.StringCache;
018    
019    import org.apache.hivemind.ApplicationRuntimeException;
020    import org.apache.tapestry.services.DataSqueezer;
021    import org.apache.tapestry.util.io.SqueezeAdaptor;
022    
023    /**
024     * Squeezes {@link BeanProperty} objects into and out of HTML and URLs.
025     *
026     * Since many class names, property names and validator strings will be serialized
027     * to the client, but the number of distinct class names, property names and validator
028     * strings using this squeezer will usually be small, this implementation keeps small
029     * static caches of these strings and their corresponding "abbreviations", which are what
030     * is actually sent to the clients. This is extremely important, as URLs are generally
031     * <a href="http://support.microsoft.com/default.aspx?scid=KB;en-us;q208427">limited</a>
032     * to about 2,000 characters.
033     *
034     * @author Daniel Gredler
035     */
036    public class BeanPropertySqueezer implements SqueezeAdaptor {
037    
038        private final static StringCache CLASSNAME_CACHE = new StringCache( 100 );
039        private final static StringCache PROPERTY_CACHE = new StringCache( 100 );
040        private final static StringCache VALIDATOR_CACHE = new StringCache( 100 );
041        private final static StringCache INPUT_CACHE = new StringCache( 10 );
042    
043        private final static String PREFIX = "B";
044        private final static String DIVIDER = "_";
045    
046        public String getPrefix() {
047            return PREFIX;
048        }
049    
050        public Class getDataClass() {
051            return BeanProperty.class;
052        }
053    
054        public String squeeze( DataSqueezer squeezer, Object data ) {
055            BeanProperty prop = (BeanProperty) data;
056            String c = CLASSNAME_CACHE.getShortVersion( prop.getOwnerClass().getName() );
057            String p = PROPERTY_CACHE.getShortVersion( prop.getName() );
058            String v = VALIDATOR_CACHE.getShortVersion( prop.getValidators() );
059            String i = INPUT_CACHE.getShortVersion( prop.getInput() );
060            return PREFIX + DIVIDER + c + DIVIDER + p + DIVIDER + v + DIVIDER + i;
061        }
062    
063        public Object unsqueeze( DataSqueezer squeezer, String string ) {
064            String[] s = string.split( DIVIDER );
065            String c = CLASSNAME_CACHE.getRealVersion( s[ 1 ] );
066            String p = PROPERTY_CACHE.getRealVersion( s[ 2 ] );
067            String v = VALIDATOR_CACHE.getRealVersion( s[ 3 ] );
068            String i = INPUT_CACHE.getRealVersion( s[ 4 ] );
069            try {
070                Class clazz = Class.forName( c );
071                BeanProperty prop = new BeanProperty( clazz, p, v, i );
072                return prop;
073            }
074            catch( ClassNotFoundException e ) {
075                String msg = BeanPropertyMessages.unsqueezeClassNotFound( string, c );
076                throw new ApplicationRuntimeException( msg, e );
077            }
078        }
079    
080    }