001package org.apache.commons.jcs3.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
022import java.io.IOException;
023import java.nio.charset.Charset;
024import java.nio.charset.StandardCharsets;
025
026import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheDispatcher;
027import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheRequest;
028import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheResponse;
029import org.apache.commons.jcs3.log.Log;
030import org.apache.commons.jcs3.log.LogManager;
031import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
032import org.apache.http.HttpException;
033import org.apache.http.HttpResponse;
034import org.apache.http.client.methods.HttpUriRequest;
035import org.apache.http.client.methods.RequestBuilder;
036import org.apache.http.entity.ByteArrayEntity;
037import org.apache.http.util.EntityUtils;
038
039/** Calls the service. */
040public class RemoteHttpCacheDispatcher
041    extends AbstractHttpClient
042    implements IRemoteCacheDispatcher
043{
044    /** Parameter encoding */
045    private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
046
047    /** Named of the parameter */
048    private static final String PARAMETER_REQUEST_TYPE = "RequestType";
049
050    /** Named of the parameter */
051    private static final String PARAMETER_KEY = "Key";
052
053    /** Named of the parameter */
054    private static final String PARAMETER_CACHE_NAME = "CacheName";
055
056    /** The Logger. */
057    private static final Log log = LogManager.getLog( RemoteHttpCacheDispatcher.class );
058
059    /** This needs to be standard, since the other side is standard */
060    private final StandardSerializer serializer = new StandardSerializer();
061
062    /**
063     * @param remoteHttpCacheAttributes
064     */
065    public RemoteHttpCacheDispatcher( final RemoteHttpCacheAttributes remoteHttpCacheAttributes )
066    {
067        super( remoteHttpCacheAttributes );
068    }
069
070    /**
071     * All requests will go through this method.
072     * <p>
073     * TODO consider taking in a URL instead of using the one in the configuration.
074     * <p>
075     * @param remoteCacheRequest
076     * @return RemoteCacheResponse
077     * @throws IOException
078     */
079    @Override
080    public <K, V, T>
081        RemoteCacheResponse<T> dispatchRequest( final RemoteCacheRequest<K, V> remoteCacheRequest )
082        throws IOException
083    {
084        try
085        {
086            final byte[] requestAsByteArray = serializer.serialize( remoteCacheRequest );
087
088            final byte[] responseAsByteArray = processRequest( requestAsByteArray,
089                    remoteCacheRequest,
090                    getRemoteHttpCacheAttributes().getUrl());
091
092            RemoteCacheResponse<T> remoteCacheResponse = null;
093            try
094            {
095                remoteCacheResponse = serializer.deSerialize( responseAsByteArray, null );
096            }
097            catch ( final ClassNotFoundException e )
098            {
099                log.error( "Couldn't deserialize the response.", e );
100            }
101            return remoteCacheResponse;
102        }
103        catch ( final Exception e )
104        {
105            throw new IOException("Problem dispatching request.", e);
106        }
107    }
108
109    /**
110     * Process single request
111     *
112     * @param requestAsByteArray request body
113     * @param remoteCacheRequest the cache request
114     * @param url target url
115     *
116     * @return byte[] - the response
117     *
118     * @throws IOException
119     * @throws HttpException
120     */
121    protected <K, V> byte[] processRequest( final byte[] requestAsByteArray,
122            final RemoteCacheRequest<K, V> remoteCacheRequest, final String url )
123        throws IOException, HttpException
124    {
125        final RequestBuilder builder = RequestBuilder.post( url ).setCharset( DEFAULT_ENCODING );
126
127        if ( getRemoteHttpCacheAttributes().isIncludeCacheNameAsParameter()
128            && remoteCacheRequest.getCacheName() != null )
129        {
130            builder.addParameter( PARAMETER_CACHE_NAME, remoteCacheRequest.getCacheName() );
131        }
132        if ( getRemoteHttpCacheAttributes().isIncludeKeysAndPatternsAsParameter() )
133        {
134            String keyValue = "";
135            switch ( remoteCacheRequest.getRequestType() )
136            {
137                case GET:
138                case REMOVE:
139                case GET_KEYSET:
140                    keyValue = remoteCacheRequest.getKey().toString();
141                    break;
142                case GET_MATCHING:
143                    keyValue = remoteCacheRequest.getPattern();
144                    break;
145                case GET_MULTIPLE:
146                    keyValue = remoteCacheRequest.getKeySet().toString();
147                    break;
148                case UPDATE:
149                    keyValue = remoteCacheRequest.getCacheElement().getKey().toString();
150                    break;
151                default:
152                    break;
153            }
154            builder.addParameter( PARAMETER_KEY, keyValue );
155        }
156        if ( getRemoteHttpCacheAttributes().isIncludeRequestTypeasAsParameter() )
157        {
158            builder.addParameter( PARAMETER_REQUEST_TYPE,
159                remoteCacheRequest.getRequestType().toString() );
160        }
161
162        builder.setEntity(new ByteArrayEntity( requestAsByteArray ));
163        final HttpResponse httpResponse = doWebserviceCall( builder );
164        return EntityUtils.toByteArray( httpResponse.getEntity() );
165    }
166
167    /**
168     * Called before the execute call on the client.
169     * <p>
170     * @param requestBuilder http method request builder
171     *
172     * @throws IOException
173     */
174    @Override
175    protected void preProcessWebserviceCall( final RequestBuilder requestBuilder )
176        throws IOException
177    {
178        // do nothing. Child can override.
179    }
180
181    /**
182     * Called after the execute call on the client.
183     * <p>
184     * @param request http request
185     * @param httpState result of execution
186     *
187     * @throws IOException
188     */
189    @Override
190    protected void postProcessWebserviceCall( final HttpUriRequest request, final HttpResponse httpState )
191        throws IOException
192    {
193        // do nothing. Child can override.
194    }
195}