View Javadoc
1   package org.apache.commons.jcs3.auxiliary.remote;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.IOException;
23  import java.util.ArrayList;
24  
25  import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes;
26  import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheListener;
27  import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType;
28  import org.apache.commons.jcs3.engine.ZombieCacheServiceNonLocal;
29  import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
30  import org.apache.commons.jcs3.engine.stats.StatElement;
31  import org.apache.commons.jcs3.engine.stats.Stats;
32  import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
33  import org.apache.commons.jcs3.engine.stats.behavior.IStats;
34  import org.apache.commons.jcs3.log.Log;
35  import org.apache.commons.jcs3.log.LogManager;
36  
37  /**
38   * Client proxy for an RMI remote cache.
39   * <p>
40   * This handles gets, updates, and removes. It also initiates failover recovery when an error is
41   * encountered.
42   */
43  public class RemoteCache<K, V>
44      extends AbstractRemoteAuxiliaryCache<K, V>
45  {
46      /** The logger. */
47      private static final Log log = LogManager.getLog( RemoteCache.class );
48  
49      /** for error notifications */
50      private final RemoteCacheMonitor monitor;
51  
52      /** back link for failover initiation */
53      private AbstractRemoteCacheNoWaitFacade<K, V> facade;
54  
55      /**
56       * Constructor for the RemoteCache object. This object communicates with a remote cache server.
57       * One of these exists for each region. This also holds a reference to a listener. The same
58       * listener is used for all regions for one remote server. Holding a reference to the listener
59       * allows this object to know the listener id assigned by the remote cache.
60       * <p>
61       * @param cattr the cache configuration
62       * @param remote the remote cache server handle
63       * @param listener a listener
64       * @param monitor the cache monitor
65       */
66      public RemoteCache( final IRemoteCacheAttributes cattr,
67          final ICacheServiceNonLocal<K, V> remote,
68          final IRemoteCacheListener<K, V> listener,
69          final RemoteCacheMonitor monitor )
70      {
71          super( cattr, remote, listener );
72          this.monitor = monitor;
73  
74          RemoteUtils.configureGlobalCustomSocketFactory( getRemoteCacheAttributes().getRmiSocketFactoryTimeoutMillis() );
75      }
76  
77      /**
78       * @return IStats object
79       */
80      @Override
81      public IStats getStatistics()
82      {
83          final IStats stats = new Stats();
84          stats.setTypeName( "Remote Cache" );
85  
86          final ArrayList<IStatElement<?>> elems = new ArrayList<>();
87  
88          elems.add(new StatElement<>( "Remote Host:Port", getIPAddressForService() ) );
89          elems.add(new StatElement<>( "Remote Type", this.getRemoteCacheAttributes().getRemoteTypeName() ) );
90  
91  //      if ( this.getRemoteCacheAttributes().getRemoteType() == RemoteType.CLUSTER )
92  //      {
93  //          // something cluster specific
94  //      }
95  
96          // get the stats from the super too
97          final IStats sStats = super.getStatistics();
98          elems.addAll(sStats.getStatElements());
99  
100         stats.setStatElements( elems );
101 
102         return stats;
103     }
104 
105     /**
106      * Set facade
107      *
108      * @param facade the facade to set
109      */
110     protected void setFacade(final AbstractRemoteCacheNoWaitFacade<K, V> facade)
111     {
112         this.facade = facade;
113     }
114 
115     /**
116      * Get facade
117      *
118      * @return the facade
119      */
120     protected AbstractRemoteCacheNoWaitFacade<K, V> getFacade()
121     {
122         return facade;
123     }
124 
125     /**
126      * Handles exception by disabling the remote cache service before re-throwing the exception in
127      * the form of an IOException.
128      * <p>
129      * @param ex
130      * @param msg
131      * @param eventName
132      * @throws IOException
133      */
134     @Override
135     protected void handleException( final Exception ex, final String msg, final String eventName )
136         throws IOException
137     {
138         final String message = "Disabling remote cache due to error: " + msg;
139 
140         logError( cacheName, "", message );
141         log.error( message, ex );
142 
143         // we should not switch if the existing is a zombie.
144         if ( !( getRemoteCacheService() instanceof ZombieCacheServiceNonLocal ) )
145         {
146             // TODO make configurable
147             setRemoteCacheService( new ZombieCacheServiceNonLocal<>( getRemoteCacheAttributes().getZombieQueueMaxSize() ) );
148         }
149         // may want to flush if region specifies
150         // Notify the cache monitor about the error, and kick off the recovery
151         // process.
152         monitor.notifyError();
153 
154         log.debug( "Initiating failover, rcnwf = {0}", facade );
155 
156         if ( facade != null && facade.getAuxiliaryCacheAttributes().getRemoteType() == RemoteType.LOCAL )
157         {
158             log.debug( "Found facade, calling failover" );
159             // may need to remove the noWait index here. It will be 0 if it is
160             // local since there is only 1 possible listener.
161             facade.failover( facade.getPrimaryServer() );
162         }
163 
164         if ( ex instanceof IOException )
165         {
166             throw (IOException) ex;
167         }
168         throw new IOException( ex );
169     }
170 
171     /**
172      * Debugging info.
173      * <p>
174      * @return basic info about the RemoteCache
175      */
176     @Override
177     public String toString()
178     {
179         return "RemoteCache: " + cacheName + " attributes = " + getRemoteCacheAttributes();
180     }
181 
182     /**
183      * Gets the extra info for the event log.
184      * <p>
185      * @return disk location
186      */
187     @Override
188     public String getEventLoggingExtraInfo()
189     {
190         return getIPAddressForService();
191     }
192 
193     /**
194      * IP address for the service, if one is stored.
195      * <p>
196      * Protected for testing.
197      * <p>
198      * @return String
199      */
200     protected String getIPAddressForService()
201     {
202         String ipAddress = "(null)";
203         if (this.getRemoteCacheAttributes().getRemoteLocation() != null)
204         {
205             ipAddress = this.getRemoteCacheAttributes().getRemoteLocation().toString();
206         }
207         return ipAddress;
208     }
209 }