001package org.apache.commons.jcs.auxiliary.remote.server;
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.rmi.Naming;
023import java.rmi.Remote;
024import java.rmi.RemoteException;
025import java.rmi.registry.Registry;
026
027import org.apache.commons.jcs.auxiliary.remote.RemoteUtils;
028import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031
032/**
033 * This class tries to keep the registry alive. If if is able to create a registry, it will also
034 * rebind the remote cache server.
035 */
036public class RegistryKeepAliveRunner
037    implements Runnable
038{
039    /** The logger */
040    private static final Log log = LogFactory.getLog( RegistryKeepAliveRunner.class );
041
042    /** The URL of the service to look for. */
043    private String namingURL;
044
045    /** The service name. */
046    private String serviceName;
047
048    /** the port on which to start the registry */
049    private int registryPort;
050
051    /** An optional event logger */
052    private ICacheEventLogger cacheEventLogger;
053
054    /** the registry */
055    private Registry registry;
056
057    /**
058     * @param registryHost - Hostname of the registry
059     * @param registryPort - the port on which to start the registry
060     * @param serviceName
061     */
062    public RegistryKeepAliveRunner( String registryHost, int registryPort, String serviceName )
063    {
064        this.namingURL = RemoteUtils.getNamingURL(registryHost, registryPort, serviceName);
065        this.serviceName = serviceName;
066        this.registryPort = registryPort;
067    }
068
069    /**
070     * Tries to lookup the server. If unsuccessful it will rebind the server using the factory
071     * rebind method.
072     * <p>
073     */
074    @Override
075    public void run()
076    {
077        checkAndRestoreIfNeeded();
078    }
079
080    /**
081     * Tries to lookup the server. If unsuccessful it will rebind the server using the factory
082     * rebind method.
083     */
084    protected void checkAndRestoreIfNeeded()
085    {
086        if ( log.isDebugEnabled() )
087        {
088            log.debug( "looking up server " + namingURL );
089        }
090        try
091        {
092            Object obj = Naming.lookup( namingURL );
093
094            // Successful connection to the remote server.
095            String message = "RMI registry looks fine.  Found [" + obj + "] in registry [" + namingURL + "]";
096            if ( cacheEventLogger != null )
097            {
098                cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "Naming.lookup", message );
099            }
100            if ( log.isDebugEnabled() )
101            {
102                log.debug( message );
103            }
104        }
105        catch ( Exception ex )
106        {
107            // Failed to connect to the remote server.
108            String message = "Problem finding server at [" + namingURL
109                + "].  Will attempt to start registry and rebind.";
110            log.error( message, ex );
111            if ( cacheEventLogger != null )
112            {
113                cacheEventLogger.logError( "RegistryKeepAliveRunner", "Naming.lookup", message + ":" + ex.getMessage() );
114            }
115            createAndRegister( serviceName );
116        }
117    }
118
119    /**
120     * Creates the registry and registers the server.
121     * <p>
122     * @param serviceName the service name
123     */
124    protected void createAndRegister( String serviceName )
125    {
126        createReqistry( serviceName );
127        registerServer( serviceName );
128    }
129
130    /**
131     * Try to create the registry. Log errors
132     * <p>
133     * @param serviceName the service name
134     */
135    protected void createReqistry( String serviceName )
136    {
137        // TODO: Refactor method signature. This is ugly but required to keep the binary API compatibility
138        this.registry = RemoteUtils.createRegistry(registryPort);
139
140        if ( cacheEventLogger != null )
141        {
142            if (this.registry != null)
143            {
144                cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "createRegistry",
145                        "Successfully created registry [" + serviceName + "]." );
146            }
147            else
148            {
149                cacheEventLogger.logError( "RegistryKeepAliveRunner", "createRegistry",
150                        "Could not start registry [" + serviceName + "]." );
151            }
152        }
153    }
154
155    /**
156     * Try to rebind the server.
157     * <p>
158     * @param serviceName the service name
159     */
160    protected void registerServer( String serviceName )
161    {
162        try
163        {
164            // try to rebind anyway
165            Remote server = RemoteCacheServerFactory.getRemoteCacheServer();
166
167            if ( server == null )
168            {
169                throw new RemoteException( "Cannot register the server until it is created." );
170            }
171
172            this.registry.rebind( serviceName, server );
173            String message = "Successfully rebound server to registry [" + serviceName + "].";
174            if ( cacheEventLogger != null )
175            {
176                cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "registerServer", message );
177            }
178            if ( log.isInfoEnabled() )
179            {
180                log.info( message );
181            }
182        }
183        catch ( RemoteException e )
184        {
185            String message = "Could not rebind server to registry [" + serviceName + "].";
186            log.error( message, e );
187            if ( cacheEventLogger != null )
188            {
189                cacheEventLogger.logError( "RegistryKeepAliveRunner", "registerServer", message + ":"
190                    + e.getMessage() );
191            }
192        }
193    }
194
195    /**
196     * Allows it to be injected.
197     * <p>
198     * @param cacheEventLogger
199     */
200    public void setCacheEventLogger( ICacheEventLogger cacheEventLogger )
201    {
202        this.cacheEventLogger = cacheEventLogger;
203    }
204}