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.io.Serializable;
024import java.util.concurrent.ConcurrentHashMap;
025
026import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheMonitor;
027import org.apache.commons.jcs3.auxiliary.remote.http.client.behavior.IRemoteHttpCacheClient;
028import org.apache.commons.jcs3.engine.CacheStatus;
029
030/**
031 * Upon the notification of a connection error, the monitor changes to operate in a time driven
032 * mode. That is, it attempts to recover the connections on a periodic basis. When all failed
033 * connections are restored, it changes back to the failure driven mode.
034 */
035public class RemoteHttpCacheMonitor extends AbstractAuxiliaryCacheMonitor
036{
037    /** Set of remote caches to monitor. This are added on error, if not before. */
038    private final ConcurrentHashMap<RemoteHttpCache<?, ?>, RemoteHttpCache<?, ?>> remoteHttpCaches;
039
040    /** Factory instance */
041    private final RemoteHttpCacheFactory factory;
042
043    /**
044     * Constructor for the RemoteCacheMonitor object
045     *
046     * @param factory the factory to set
047     */
048    public RemoteHttpCacheMonitor(final RemoteHttpCacheFactory factory)
049    {
050        super("JCS-RemoteHttpCacheMonitor");
051        this.factory = factory;
052        this.remoteHttpCaches = new ConcurrentHashMap<>();
053        setIdlePeriod(3000L);
054    }
055
056    /**
057     * Notifies the cache monitor that an error occurred, and kicks off the error recovery process.
058     * <p>
059     * @param remoteCache
060     */
061    public void notifyError( final RemoteHttpCache<?, ?> remoteCache )
062    {
063        if ( log.isInfoEnabled() )
064        {
065            log.info( "Notified of an error. " + remoteCache );
066        }
067
068        remoteHttpCaches.put( remoteCache, remoteCache );
069        notifyError();
070    }
071
072    /**
073     * Clean up all resources before shutdown
074     */
075    @Override
076    protected void dispose()
077    {
078        this.remoteHttpCaches.clear();
079    }
080
081    // Avoid the use of any synchronization in the process of monitoring for
082    // performance reasons.
083    // If exception is thrown owing to synchronization,
084    // just skip the monitoring until the next round.
085    /** Main processing method for the RemoteHttpCacheMonitor object */
086    @Override
087    protected void doWork()
088    {
089        // If no factory has been set, skip
090        if (factory == null)
091        {
092            return;
093        }
094
095        // If any cache is in error, it strongly suggests all caches
096        // managed by the same RmicCacheManager instance are in error. So we fix
097        // them once and for all.
098        for (final RemoteHttpCache<?, ?> remoteCache : this.remoteHttpCaches.values())
099        {
100            try
101            {
102                if ( remoteCache.getStatus() == CacheStatus.ERROR )
103                {
104                    final RemoteHttpCacheAttributes attributes = remoteCache.getRemoteHttpCacheAttributes();
105
106                    final IRemoteHttpCacheClient<Serializable, Serializable> remoteService =
107                            factory.createRemoteHttpCacheClientForAttributes( attributes );
108
109                    if ( log.isInfoEnabled() )
110                    {
111                        log.info( "Performing Alive check on service " + remoteService );
112                    }
113                    // If we can't fix them, just skip and re-try in
114                    // the next round.
115                    if ( remoteService.isAlive() )
116                    {
117                        remoteCache.fixCache( remoteService );
118                    }
119                    else
120                    {
121                        allright.set(false);
122                    }
123                    break;
124                }
125            }
126            catch ( final IOException ex )
127            {
128                allright.set(false);
129                // Problem encountered in fixing the caches managed by a
130                // RemoteCacheManager instance.
131                // Soldier on to the next RemoteHttpCache.
132                log.error( ex );
133            }
134        }
135    }
136}