View Javadoc

1   package org.apache.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.io.Serializable;
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.List;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
31  import org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheListener;
32  import org.apache.jcs.auxiliary.remote.server.behavior.RemoteType;
33  import org.apache.jcs.engine.ZombieCacheServiceNonLocal;
34  import org.apache.jcs.engine.behavior.ICacheServiceNonLocal;
35  import org.apache.jcs.engine.stats.StatElement;
36  import org.apache.jcs.engine.stats.Stats;
37  import org.apache.jcs.engine.stats.behavior.IStatElement;
38  import org.apache.jcs.engine.stats.behavior.IStats;
39  
40  /**
41   * Client proxy for an RMI remote cache.
42   * <p>
43   * This handles gets, updates, and removes. It also initiates failover recovery when an error is
44   * encountered.
45   */
46  public class RemoteCache<K extends Serializable, V extends Serializable>
47      extends AbstractRemoteAuxiliaryCache<K, V>
48  {
49      /** Don't change. */
50      private static final long serialVersionUID = -5329231850422826460L;
51  
52      /** The logger. */
53      private final static Log log = LogFactory.getLog( RemoteCache.class );
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
62       * @param remote
63       * @param listener
64       */
65      public RemoteCache( IRemoteCacheAttributes cattr, ICacheServiceNonLocal<K, V> remote, IRemoteCacheListener<K, V> listener )
66      {
67          super( cattr, remote, listener );
68  
69          RemoteUtils.configureGlobalCustomSocketFactory( getRemoteCacheAttributes().getRmiSocketFactoryTimeoutMillis() );
70      }
71  
72      /**
73       * @return IStats object
74       */
75      @Override
76      public IStats getStatistics()
77      {
78          IStats stats = new Stats();
79          stats.setTypeName( "Remote Cache No Wait" );
80  
81          ArrayList<IStatElement> elems = new ArrayList<IStatElement>();
82  
83          IStatElement se = null;
84  
85          se = new StatElement();
86          se.setName( "Remote Host:Port" );
87          se.setData( getIPAddressForService() );
88          elems.add( se );
89  
90          se = new StatElement();
91          se.setName( "Remote Type" );
92          se.setData( this.getRemoteCacheAttributes().getRemoteTypeName() + "" );
93          elems.add( se );
94  
95          if ( this.getRemoteCacheAttributes().getRemoteType() == RemoteType.CLUSTER )
96          {
97              // something cluster specific
98          }
99  
100         // get the stats from the super too
101         // get as array, convert to list, add list to our outer list
102         IStats sStats = super.getStatistics();
103         IStatElement[] sSEs = sStats.getStatElements();
104         List<IStatElement> sL = Arrays.asList( sSEs );
105         elems.addAll( sL );
106 
107         // get an array and put them in the Stats object
108         IStatElement[] ses = elems.toArray( new StatElement[0] );
109         stats.setStatElements( ses );
110 
111         return stats;
112     }
113 
114     /**
115      * Handles exception by disabling the remote cache service before re-throwing the exception in
116      * the form of an IOException.
117      * <p>
118      * @param ex
119      * @param msg
120      * @param eventName
121      * @throws IOException
122      */
123     @Override
124     protected void handleException( Exception ex, String msg, String eventName )
125         throws IOException
126     {
127         String message = "Disabling remote cache due to error: " + msg;
128 
129         logError( cacheName, "", message );
130         log.error( message, ex );
131 
132         // we should not switch if the existing is a zombie.
133         if ( getRemoteCacheService() == null || !( getRemoteCacheService() instanceof ZombieCacheServiceNonLocal ) )
134         {
135             // TODO make configurable
136             setRemoteCacheService( new ZombieCacheServiceNonLocal<K, V>( getRemoteCacheAttributes().getZombieQueueMaxSize() ) );
137         }
138         // may want to flush if region specifies
139         // Notify the cache monitor about the error, and kick off the recovery
140         // process.
141         RemoteCacheMonitor.getInstance().notifyError();
142 
143         // initiate failover if local
144         @SuppressWarnings("unchecked") // Need to cast because of common map for all facades
145         RemoteCacheNoWaitFacade<K, V> rcnwf = (RemoteCacheNoWaitFacade<K, V>)RemoteCacheFactory.getFacades()
146             .get( getRemoteCacheAttributes().getCacheName() );
147 
148         if ( log.isDebugEnabled() )
149         {
150             log.debug( "Initiating failover, rcnf = " + rcnwf );
151         }
152 
153         if ( rcnwf != null && rcnwf.remoteCacheAttributes.getRemoteType() == RemoteType.LOCAL )
154         {
155             if ( log.isDebugEnabled() )
156             {
157                 log.debug( "Found facade, calling failover" );
158             }
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             rcnwf.failover( 0 );
162         }
163 
164         if ( ex instanceof IOException )
165         {
166             throw (IOException) ex;
167         }
168         throw new IOException( ex.getMessage() );
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 = this.getRemoteCacheAttributes().getRemoteHost() + ":"
203             + this.getRemoteCacheAttributes().getRemotePort();
204         return ipAddress;
205     }
206 }