View Javadoc
1   package org.apache.commons.jcs.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.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
26  import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener;
27  import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType;
28  import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal;
29  import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
30  import org.apache.commons.jcs.engine.stats.StatElement;
31  import org.apache.commons.jcs.engine.stats.Stats;
32  import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
33  import org.apache.commons.jcs.engine.stats.behavior.IStats;
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
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 = LogFactory.getLog( RemoteCache.class );
48  
49      /** for error notifications */
50      private 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( IRemoteCacheAttributes cattr,
67          ICacheServiceNonLocal<K, V> remote,
68          IRemoteCacheListener<K, V> listener,
69          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          IStats stats = new Stats();
84          stats.setTypeName( "Remote Cache" );
85  
86          ArrayList<IStatElement<?>> elems = new ArrayList<IStatElement<?>>();
87  
88          elems.add(new StatElement<String>( "Remote Host:Port", getIPAddressForService() ) );
89          elems.add(new StatElement<String>( "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          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(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( Exception ex, String msg, String eventName )
136         throws IOException
137     {
138         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() == null || !( getRemoteCacheService() instanceof ZombieCacheServiceNonLocal ) )
145         {
146             // TODO make configurable
147             setRemoteCacheService( new ZombieCacheServiceNonLocal<K, V>( 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         if ( log.isDebugEnabled() )
155         {
156             log.debug( "Initiating failover, rcnwf = " + facade );
157         }
158 
159         if ( facade != null && facade.getAuxiliaryCacheAttributes().getRemoteType() == RemoteType.LOCAL )
160         {
161             if ( log.isDebugEnabled() )
162             {
163                 log.debug( "Found facade, calling failover" );
164             }
165             // may need to remove the noWait index here. It will be 0 if it is
166             // local since there is only 1 possible listener.
167             facade.failover( facade.getPrimaryServer() );
168         }
169 
170         if ( ex instanceof IOException )
171         {
172             throw (IOException) ex;
173         }
174         throw new IOException( ex );
175     }
176 
177     /**
178      * Debugging info.
179      * <p>
180      * @return basic info about the RemoteCache
181      */
182     @Override
183     public String toString()
184     {
185         return "RemoteCache: " + cacheName + " attributes = " + getRemoteCacheAttributes();
186     }
187 
188     /**
189      * Gets the extra info for the event log.
190      * <p>
191      * @return disk location
192      */
193     @Override
194     public String getEventLoggingExtraInfo()
195     {
196         return getIPAddressForService();
197     }
198 
199     /**
200      * IP address for the service, if one is stored.
201      * <p>
202      * Protected for testing.
203      * <p>
204      * @return String
205      */
206     protected String getIPAddressForService()
207     {
208         String ipAddress = "(null)";
209         if (this.getRemoteCacheAttributes().getRemoteLocation() != null)
210         {
211             ipAddress = this.getRemoteCacheAttributes().getRemoteLocation().toString();
212         }
213         return ipAddress;
214     }
215 }