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 org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheFactory;
023import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
024import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
025import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheNoWait;
026import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheClient;
027import org.apache.commons.jcs3.auxiliary.remote.http.client.behavior.IRemoteHttpCacheClient;
028import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType;
029import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
030import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
031import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
032import org.apache.commons.jcs3.log.Log;
033import org.apache.commons.jcs3.log.LogManager;
034import org.apache.commons.jcs3.utils.config.OptionConverter;
035
036/**
037 * The RemoteCacheFactory creates remote caches for the cache hub. It returns a no wait facade which
038 * is a wrapper around a no wait. The no wait object is either an active connection to a remote
039 * cache or a balking zombie if the remote cache is not accessible. It should be transparent to the
040 * clients.
041 */
042public class RemoteHttpCacheFactory
043    extends AbstractAuxiliaryCacheFactory
044{
045    /** The logger */
046    private static final Log log = LogManager.getLog( RemoteHttpCacheFactory.class );
047
048    /** Monitor thread instance */
049    private RemoteHttpCacheMonitor monitor;
050
051    /**
052     * For LOCAL clients we get a handle to all the failovers, but we do not register a listener
053     * with them. We create the RemoteCacheManager, but we do not get a cache.
054     * <p>
055     * The failover runner will get a cache from the manager. When the primary is restored it will
056     * tell the manager for the failover to deregister the listener.
057     * <p>
058     * @param iaca
059     * @param cacheMgr
060     * @param cacheEventLogger
061     * @param elementSerializer
062     * @return AuxiliaryCache
063     */
064    @Override
065    public <K, V> AuxiliaryCache<K, V> createCache( final AuxiliaryCacheAttributes iaca, final ICompositeCacheManager cacheMgr,
066                                       final ICacheEventLogger cacheEventLogger, final IElementSerializer elementSerializer )
067    {
068        final RemoteHttpCacheAttributes rca = (RemoteHttpCacheAttributes) iaca;
069
070        // TODO, use the configured value.
071        rca.setRemoteType( RemoteType.LOCAL );
072
073        final RemoteHttpClientListener<K, V> listener = new RemoteHttpClientListener<>( rca, cacheMgr, elementSerializer );
074
075        final IRemoteHttpCacheClient<K, V> remoteService = createRemoteHttpCacheClientForAttributes(rca);
076
077        final IRemoteCacheClient<K, V> remoteCacheClient =
078                new RemoteHttpCache<>( rca, remoteService, listener, monitor );
079        remoteCacheClient.setCacheEventLogger( cacheEventLogger );
080        remoteCacheClient.setElementSerializer( elementSerializer );
081
082        final RemoteCacheNoWait<K, V> remoteCacheNoWait = new RemoteCacheNoWait<>( remoteCacheClient );
083        remoteCacheNoWait.setCacheEventLogger( cacheEventLogger );
084        remoteCacheNoWait.setElementSerializer( elementSerializer );
085
086        return remoteCacheNoWait;
087    }
088
089    /**
090     * This is an extension point. The manager and other classes will only create
091     * RemoteHttpCacheClient through this method.
092
093     * @param cattr the cache configuration
094     * @return the client instance
095     */
096    protected <V, K> IRemoteHttpCacheClient<K, V> createRemoteHttpCacheClientForAttributes(final RemoteHttpCacheAttributes cattr)
097    {
098        IRemoteHttpCacheClient<K, V> remoteService = OptionConverter.instantiateByClassName( cattr
099                        .getRemoteHttpClientClassName(), null );
100
101        if ( remoteService == null )
102        {
103            log.info( "Creating the default client for {0}",
104                    cattr::getCacheName);
105            remoteService = new RemoteHttpCacheClient<>();
106        }
107
108        remoteService.initialize( cattr );
109        return remoteService;
110    }
111
112    /**
113     * @see org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheFactory#initialize()
114     */
115    @Override
116    public void initialize()
117    {
118        super.initialize();
119        monitor = new RemoteHttpCacheMonitor(this);
120        monitor.setDaemon(true);
121        monitor.start();
122    }
123
124    /**
125     * @see org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheFactory#dispose()
126     */
127    @Override
128    public void dispose()
129    {
130        if (monitor != null)
131        {
132            monitor.notifyShutdown();
133            try
134            {
135                monitor.join(5000);
136            }
137            catch (final InterruptedException e)
138            {
139                // swallow
140            }
141            monitor = null;
142        }
143
144        super.dispose();
145    }
146}