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.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.List;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
30  import org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheListener;
31  import org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheService;
32  import org.apache.jcs.engine.stats.StatElement;
33  import org.apache.jcs.engine.stats.Stats;
34  import org.apache.jcs.engine.stats.behavior.IStatElement;
35  import org.apache.jcs.engine.stats.behavior.IStats;
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
44      extends AbstractRemoteAuxiliaryCache
45  {
46      /** Don't change. */
47      private static final long serialVersionUID = -5329231850422826460L;
48  
49      /** The logger. */
50      private final static Log log = LogFactory.getLog( RemoteCache.class );
51  
52      /**
53       * Constructor for the RemoteCache object. This object communicates with a remote cache server.
54       * One of these exists for each region. This also holds a reference to a listener. The same
55       * listener is used for all regions for one remote server. Holding a reference to the listener
56       * allows this object to know the listener id assigned by the remote cache.
57       * <p>
58       * @param cattr
59       * @param remote
60       * @param listener
61       */
62      public RemoteCache( IRemoteCacheAttributes cattr, IRemoteCacheService remote, IRemoteCacheListener listener )
63      {
64          super( cattr, remote, listener );
65  
66          RemoteUtils.configureGlobalCustomSocketFactory( getRemoteCacheAttributes().getRmiSocketFactoryTimeoutMillis() );
67      }
68  
69      /**
70       * @return IStats object
71       */
72      @Override
73      public IStats getStatistics()
74      {
75          IStats stats = new Stats();
76          stats.setTypeName( "Remote Cache No Wait" );
77  
78          ArrayList<IStatElement> elems = new ArrayList<IStatElement>();
79  
80          IStatElement se = null;
81  
82          se = new StatElement();
83          se.setName( "Remote Host:Port" );
84          se.setData( getIPAddressForService() );
85          elems.add( se );
86  
87          se = new StatElement();
88          se.setName( "Remote Type" );
89          se.setData( this.getRemoteCacheAttributes().getRemoteTypeName() + "" );
90          elems.add( se );
91  
92          if ( this.getRemoteCacheAttributes().getRemoteType() == IRemoteCacheAttributes.CLUSTER )
93          {
94              // something cluster specific
95          }
96  
97          // get the stats from the super too
98          // get as array, convert to list, add list to our outer list
99          IStats sStats = super.getStatistics();
100         IStatElement[] sSEs = sStats.getStatElements();
101         List<IStatElement> sL = Arrays.asList( sSEs );
102         elems.addAll( sL );
103 
104         // get an array and put them in the Stats object
105         IStatElement[] ses = elems.toArray( new StatElement[0] );
106         stats.setStatElements( ses );
107 
108         return stats;
109     }
110 
111     /**
112      * Handles exception by disabling the remote cache service before re-throwing the exception in
113      * the form of an IOException.
114      * <p>
115      * @param ex
116      * @param msg
117      * @param eventName
118      * @throws IOException
119      */
120     @Override
121     protected void handleException( Exception ex, String msg, String eventName )
122         throws IOException
123     {
124         String message = "Disabling remote cache due to error: " + msg;
125 
126         logError( cacheName, "", message );
127         log.error( message, ex );
128 
129         // we should not switch if the existing is a zombie.
130         if ( getRemoteCacheService() == null || !( getRemoteCacheService() instanceof ZombieRemoteCacheService ) )
131         {
132             // TODO make configurable
133             setRemoteCacheService( new ZombieRemoteCacheService( getRemoteCacheAttributes().getZombieQueueMaxSize() ) );
134         }
135         // may want to flush if region specifies
136         // Notify the cache monitor about the error, and kick off the recovery
137         // process.
138         RemoteCacheMonitor.getInstance().notifyError();
139 
140         // initiate failover if local
141         RemoteCacheNoWaitFacade rcnwf = (RemoteCacheNoWaitFacade) RemoteCacheFactory.getFacades()
142             .get( getRemoteCacheAttributes().getCacheName() );
143 
144         if ( log.isDebugEnabled() )
145         {
146             log.debug( "Initiating failover, rcnf = " + rcnwf );
147         }
148 
149         if ( rcnwf != null && rcnwf.remoteCacheAttributes.getRemoteType() == RemoteCacheAttributes.LOCAL )
150         {
151             if ( log.isDebugEnabled() )
152             {
153                 log.debug( "Found facade, calling failover" );
154             }
155             // may need to remove the noWait index here. It will be 0 if it is
156             // local since there is only 1 possible listener.
157             rcnwf.failover( 0 );
158         }
159 
160         if ( ex instanceof IOException )
161         {
162             throw (IOException) ex;
163         }
164         throw new IOException( ex.getMessage() );
165     }
166 
167     /**
168      * Debugging info.
169      * <p>
170      * @return basic info about the RemoteCache
171      */
172     @Override
173     public String toString()
174     {
175         return "RemoteCache: " + cacheName + " attributes = " + getRemoteCacheAttributes();
176     }
177 
178     /**
179      * Gets the extra info for the event log.
180      * <p>
181      * @return disk location
182      */
183     @Override
184     public String getEventLoggingExtraInfo()
185     {
186         return getIPAddressForService();
187     }
188 
189     /**
190      * IP address for the service, if one is stored.
191      * <p>
192      * Protected for testing.
193      * <p>
194      * @return String
195      */
196     protected String getIPAddressForService()
197     {
198         String ipAddress = this.getRemoteCacheAttributes().getRemoteHost() + ":"
199             + this.getRemoteCacheAttributes().getRemotePort();
200         return ipAddress;
201     }
202 }