001    package org.apache.jcs.auxiliary.remote.http.client;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import java.io.IOException;
023    import java.io.Serializable;
024    import java.io.UnsupportedEncodingException;
025    import java.net.URLEncoder;
026    
027    import org.apache.commons.httpclient.HttpException;
028    import org.apache.commons.httpclient.HttpMethod;
029    import org.apache.commons.httpclient.HttpState;
030    import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
031    import org.apache.commons.httpclient.methods.PostMethod;
032    import org.apache.commons.httpclient.methods.RequestEntity;
033    import org.apache.commons.logging.Log;
034    import org.apache.commons.logging.LogFactory;
035    import org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheDispatcher;
036    import org.apache.jcs.auxiliary.remote.value.RemoteCacheRequest;
037    import org.apache.jcs.auxiliary.remote.value.RemoteCacheResponse;
038    import org.apache.jcs.utils.serialization.StandardSerializer;
039    
040    /** Calls the service. */
041    public class RemoteHttpCacheDispatcher
042        extends AbstractHttpClient
043        implements IRemoteCacheDispatcher
044    {
045        /** Named of the parameter */
046        private static final String PARAMETER_REQUEST_TYPE = "RequestType";
047    
048        /** Named of the parameter */
049        private static final String PARAMETER_KEY = "Key";
050    
051        /** Named of the parameter */
052        private static final String PARAMETER_CACHE_NAME = "CacheName";
053    
054        /** The Logger. */
055        private final static Log log = LogFactory.getLog( RemoteHttpCacheDispatcher.class );
056    
057        /** This needs to be standard, since the other side is standard */
058        private StandardSerializer serializer = new StandardSerializer();
059    
060        /**
061         * @param remoteHttpCacheAttributes
062         */
063        public RemoteHttpCacheDispatcher( RemoteHttpCacheAttributes remoteHttpCacheAttributes )
064        {
065            super( remoteHttpCacheAttributes );
066        }
067    
068        /**
069         * All requests will go through this method.
070         * <p>
071         * TODO consider taking in a URL instead of using the one in the configuration.
072         * <p>
073         * @param remoteCacheRequest
074         * @return RemoteCacheResponse
075         * @throws IOException
076         */
077        public <K extends Serializable, V extends Serializable, T>
078            RemoteCacheResponse<T> dispatchRequest( RemoteCacheRequest<K, V> remoteCacheRequest )
079            throws IOException
080        {
081            try
082            {
083                byte[] requestAsByteArray = serializer.serialize( remoteCacheRequest );
084    
085                String url = addParameters( remoteCacheRequest, getRemoteHttpCacheAttributes().getUrl() );
086    
087                byte[] responseAsByteArray = processRequest( requestAsByteArray, url );
088    
089                RemoteCacheResponse<T> remoteCacheResponse = null;
090                try
091                {
092                    remoteCacheResponse = serializer.deSerialize( responseAsByteArray );
093                }
094                catch ( ClassNotFoundException e )
095                {
096                    log.error( "Couldn't deserialize the response.", e );
097                }
098                return remoteCacheResponse;
099            }
100            catch ( Exception e )
101            {
102                log.error( "Problem dispatching request.", e );
103                throw new IOException( e.getMessage() );
104            }
105        }
106    
107        /**
108         * @param requestAsByteArray
109         * @param url
110         * @return byte[] - the response
111         * @throws IOException
112         * @throws HttpException
113         */
114        protected byte[] processRequest( byte[] requestAsByteArray, String url )
115            throws IOException, HttpException
116        {
117            PostMethod post = new PostMethod( url );
118            RequestEntity requestEntity = new ByteArrayRequestEntity( requestAsByteArray );
119            post.setRequestEntity( requestEntity );
120            doWebserviceCall( post );
121            byte[] response = post.getResponseBody();
122            return response;
123        }
124    
125        /**
126         * @param remoteCacheRequest
127         * @param baseUrl
128         * @return String
129         */
130        protected <K extends Serializable, V extends Serializable> String addParameters( RemoteCacheRequest<K, V> remoteCacheRequest, String baseUrl )
131        {
132            StringBuffer url = new StringBuffer( baseUrl );
133    
134            try
135            {
136                if ( baseUrl != null && ( baseUrl.indexOf( "?" ) == -1 ) )
137                {
138                    url.append( "?" );
139                }
140                else
141                {
142                    url.append( "&" );
143                }
144    
145                if ( getRemoteHttpCacheAttributes().isIncludeCacheNameAsParameter() )
146                {
147                    if ( remoteCacheRequest.getCacheName() != null )
148                    {
149                        url.append( PARAMETER_CACHE_NAME + "="
150                            + URLEncoder.encode( remoteCacheRequest.getCacheName(), "UTF-8" ) );
151                    }
152                }
153                if ( getRemoteHttpCacheAttributes().isIncludeKeysAndPatternsAsParameter() )
154                {
155                    String keyValue = "";
156                    switch ( remoteCacheRequest.getRequestType() )
157                    {
158                        case GET:
159                            keyValue = remoteCacheRequest.getKey() + "";
160                            break;
161                        case REMOVE:
162                            keyValue = remoteCacheRequest.getKey() + "";
163                            break;
164                        case GET_MATCHING:
165                            keyValue = remoteCacheRequest.getPattern();
166                            break;
167                        case GET_MULTIPLE:
168                            keyValue = remoteCacheRequest.getKeySet() + "";
169                            break;
170                        case GET_GROUP_KEYS:
171                            keyValue = remoteCacheRequest.getKey() + "";
172                            break;
173                        case GET_GROUP_NAMES:
174                            keyValue = remoteCacheRequest.getKey() + "";
175                            break;
176                        case UPDATE:
177                            keyValue = remoteCacheRequest.getCacheElement().getKey() + "";
178                            break;
179                        default:
180                            break;
181                    }
182                    String encodedKeyValue = URLEncoder.encode( keyValue, "UTF-8" );
183                    url.append( "&" + PARAMETER_KEY + "=" + encodedKeyValue );
184                }
185                if ( getRemoteHttpCacheAttributes().isIncludeRequestTypeasAsParameter() )
186                {
187                    url.append( "&"
188                        + PARAMETER_REQUEST_TYPE
189                        + "="
190                        + URLEncoder.encode( remoteCacheRequest.getRequestType().toString(), "UTF-8" ) );
191                }
192            }
193            catch ( UnsupportedEncodingException e )
194            {
195                log.error( "Couldn't encode URL.", e );
196            }
197    
198            if ( log.isDebugEnabled() )
199            {
200                log.debug( "Url: " + url.toString() );
201            }
202    
203            return url.toString();
204        }
205    
206        /**
207         * Called before the executeMethod on the client.
208         * <p>
209         * @param post http method
210         * @return HttpState
211         * @throws IOException
212         */
213        @Override
214        public HttpState preProcessWebserviceCall( HttpMethod post )
215            throws IOException
216        {
217            // do nothing. Child can override.
218            return null;
219        }
220    
221        /**
222         * Called after the executeMethod on the client.
223         * <p>
224         * @param post http method
225         * @param httpState state
226         * @throws IOException
227         */
228        @Override
229        public void postProcessWebserviceCall( HttpMethod post, HttpState httpState )
230            throws IOException
231        {
232            // do nothing. Child can override.
233        }
234    }