001/*
002 * #%L
003 * Netarchivesuite - monitor
004 * %%
005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library,
006 *             the National Library of France and the Austrian National Library.
007 * %%
008 * This program is free software: you can redistribute it and/or modify
009 * it under the terms of the GNU Lesser General Public License as
010 * published by the Free Software Foundation, either version 2.1 of the
011 * License, or (at your option) any later version.
012 * 
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Lesser Public License for more details.
017 * 
018 * You should have received a copy of the GNU General Lesser Public
019 * License along with this program.  If not, see
020 * <http://www.gnu.org/licenses/lgpl-2.1.html>.
021 * #L%
022 */
023
024package dk.netarkivet.monitor.jmx;
025
026import java.util.HashMap;
027import java.util.Map;
028
029import org.slf4j.Logger;
030import org.slf4j.LoggerFactory;
031
032import dk.netarkivet.common.exceptions.ArgumentNotValid;
033
034/** Adds caching to another JMXProxyFactoryConnectionFactory. */
035public class CachingProxyConnectionFactory implements JMXProxyConnectionFactory {
036    /** The JMXProxyFactoryConnectionFactory, this class acts as a cache for. */
037    private final JMXProxyConnectionFactory wrappedFactory;
038
039    /** The log. */
040    public static final Logger log = LoggerFactory.getLogger(CachingProxyConnectionFactory.class);
041    
042    /**
043     * Encapsulates the unit of information for checking the cache. That is, all information used as arguments for the
044     * JMXProxyFactoryConnectionFactory.getConnection method.
045     */
046    static class CacheKey {
047        String server;
048        int port, rmiPort;
049        String userName, password;
050
051        /**
052         * Constructor for this class.
053         *
054         * @param server The server name.
055         * @param port The JMX port number.
056         * @param rmiPort The RMI callback number.
057         * @param userName The JMX user name.
058         * @param password The JMX password.
059         */
060        public CacheKey(String server, int port, int rmiPort, String userName, String password) {
061            this.server = server;
062            this.port = port;
063            this.rmiPort = rmiPort;
064            this.userName = userName;
065            this.password = password;
066        }
067
068        /**
069         * Equals method, that overrides the Object.equals method.
070         *
071         * @param o anObject
072         * @return true, if o is equal to this object; else false
073         * @see Object#equals(java.lang.Object)
074         */
075        public boolean equals(Object o) {
076            if (this == o) {
077                return true;
078            }
079            if (o == null || getClass() != o.getClass()) {
080                return false;
081            }
082
083            CacheKey cacheKey = (CacheKey) o;
084
085            if (port != cacheKey.port) {
086                return false;
087            }
088            if (rmiPort != cacheKey.rmiPort) {
089                return false;
090            }
091            if (!password.equals(cacheKey.password)) {
092                return false;
093            }
094            if (!server.equals(cacheKey.server)) {
095                return false;
096            }
097            if (!userName.equals(cacheKey.userName)) {
098                return false;
099            }
100
101            return true;
102        }
103
104        /**
105         * hashCode method, that overrides the Object.hashCode method.
106         *
107         * @return the hashcode for this object
108         * @see Object#hashCode()
109         */
110        public int hashCode() {
111            int result;
112            result = server.hashCode();
113            result = 31 * result + port;
114            result = 31 * result + rmiPort;
115            result = 31 * result + userName.hashCode();
116            result = 31 * result + password.hashCode();
117            return result;
118        }
119    }
120
121    private Map<CacheKey, JMXProxyConnection> cache = new HashMap<CacheKey, JMXProxyConnection>();
122
123    /**
124     * Registers the factory to wrap and initializes connection cache.
125     *
126     * @param wrappedFactory The factory to add caching to.
127     */
128    public CachingProxyConnectionFactory(JMXProxyConnectionFactory wrappedFactory) {
129        this.wrappedFactory = wrappedFactory;
130    }
131
132    /**
133     * If (server,port,userName) has been seen before, looks up the cached connection associated with these values.
134     * Otherwise passes the request on the the wrapped factory, caching the result for future reuse.
135     *
136     * @see JMXProxyConnectionFactory#getConnection(String, int, int, String, String)
137     */
138    public JMXProxyConnection getConnection(String server, int port, int rmiPort, String userName, String password) {
139        ArgumentNotValid.checkNotNullOrEmpty(server, "server");
140        ArgumentNotValid.checkNotNullOrEmpty(userName, "userName");
141        ArgumentNotValid.checkNotNullOrEmpty(password, "password");
142        
143        CacheKey key = new CacheKey(server, port, rmiPort, userName, password);
144        if (cache.containsKey(key)) {
145            JMXProxyConnection jmxProxyConnection = cache.get(key);
146            if (jmxProxyConnection != null && jmxProxyConnection.isLive()) {
147                log.debug("Retrieving a cached JMXProxyConnection to server {}, port {}, rmiPort {}", server, port, rmiPort);
148                return jmxProxyConnection;
149            }
150        }
151        
152        JMXProxyConnection newConnection = wrappedFactory.getConnection(server, port, rmiPort, userName, password);
153        cache.put(key, newConnection);
154        log.info("Caching a new JMXProxyConnection to server {}, port {}, rmiPort {}", server, port, rmiPort);
155        return newConnection;
156    }
157
158}