/* * RHQ Management Platform * Copyright (C) 2005-2008 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.enterprise.server.core.comm; import java.io.Serializable; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.jboss.remoting.InvokerLocator; import org.rhq.core.domain.resource.Agent; import org.rhq.enterprise.communications.ServiceContainerConfigurationConstants; /** * Maintains a list of agents by holding string representations of their remote endpoints. This class implementation is * thread safe. Note that this class does not know agents by their name - only by their remote endpoints! * * @author John Mazzitelli */ public class KnownAgents implements Serializable { /** * the UID to identify the serializable version of this class */ private static final long serialVersionUID = 1L; /** * The true set of agents keyed on just "host:port" with the values being the full endpoints. We key on just the * base host/port to avoid having duplicates in the list that differ only by parameter values or protocol. Access to * this map must be done in a thread safe way. Note that the InvokerLocator is the actual object used to remotely * communicate with the agent - its string representation is stored in the domain model in * {@link Agent#getRemoteEndpoint()}. */ private final Map<String, InvokerLocator> m_agents; /** * Constructor for {@link KnownAgents}. */ public KnownAgents() { m_agents = new HashMap<String, InvokerLocator>(); } /** * Adds the given remote endpoint to the list of known agents. If the given endpoint does not represent an agent, * this method does nothing and simply returns. * * @param endpoint the endpoint to add if it refers to an agent * * @return <code>true</code> if the endpoint was an agent and it was added; <code>false</code> if the endpoint was * not an agent and nothing was added to the internal list of known agents */ public boolean addAgent(InvokerLocator endpoint) { boolean is_agent = isAgent(endpoint); if (is_agent) { synchronized (m_agents) { m_agents.put(getEndpointKey(endpoint), endpoint); } } return is_agent; } /** * Adds the given remote endpoint to the list of known agents. If the given endpoint does not represent an agent, * this method does nothing and simply returns. The given <code>endpoint</code> is a String so you can call this * method by directly using a value from {@link Agent#getRemoteEndpoint()}. * * @param endpoint the endpoint to add if it refers to an agent * * @return <code>true</code> if the endpoint was an agent and it was added; <code>false</code> if the endpoint was * not an agent and nothing was added to the internal list of known agents * * @throws RuntimeException if the endpoint was malformed and invalid */ public boolean addAgent(String endpoint) { try { return addAgent(new InvokerLocator(endpoint)); } catch (MalformedURLException e) { throw new RuntimeException(e); // this should rarely occur } } /** * Removes the given remote endpoint from the list of known agents. If the given endpoint does not already exist, * this method does nothing and simply returns <code>false</code>. * * @param endpoint the endpoint to remove * * @return <code>true</code> if the agent existed and was removed; <code>false</code> otherwise */ public boolean removeAgent(InvokerLocator endpoint) { InvokerLocator removed_agent; synchronized (m_agents) { removed_agent = m_agents.remove(getEndpointKey(endpoint)); } return removed_agent != null; } /** * Removes the given remote endpoint from the list of known agents. If the given endpoint does not already exist, * this method does nothing and simply returns <code>false</code>. The given <code>endpoint</code> is a String so * you can call this method by directly using a value from {@link Agent#getRemoteEndpoint()}. * * @param endpoint the endpoint to remove * * @return <code>true</code> if the agent existed and was removed; <code>false</code> otherwise * * @throws RuntimeException if the endpoint was malformed and invalid */ public boolean removeAgent(String endpoint) { try { return removeAgent(new InvokerLocator(endpoint)); } catch (MalformedURLException e) { throw new RuntimeException(e); // this should rarely occur } } /** * Given a specific host and port, this will return the associated agent. Note that the host must match exactly (no * reverse DNS or virtual host IP matching is done with the given host and the known hosts names). * * @param host the host of the agent to retrieve * @param port the port of the agent to retrieve * * @return the agent listening on the port on the given host; <code>null</code> if no known agent exists in the list */ public InvokerLocator getAgent(String host, int port) { synchronized (m_agents) { return m_agents.get(getEndpointKey(host, port)); } } /** * Returns a list of all the known agents. * * @return list of all known agents' endpoints */ public List<InvokerLocator> getAllAgents() { List<InvokerLocator> ret_list; synchronized (m_agents) { ret_list = new ArrayList<InvokerLocator>(m_agents.values()); } return ret_list; } /** * Empties the internal list of agents. */ public void removeAllAgents() { synchronized (m_agents) { m_agents.clear(); } } /** * This returns <code>true</code> if the given remote endpoint is from an agent. If not, <code>false</code> is * returned. * * @param locator the locator of the remote endpoint that is to be checked * * @return <code>true</code> if the locator represents an agent */ private boolean isAgent(InvokerLocator locator) { Map parameters = locator.getParameters(); if ((parameters == null) || (parameters.size() == 0)) { return false; } String rhqtype = (String) parameters.get(ServiceContainerConfigurationConstants.CONNECTOR_RHQTYPE); return ServiceContainerConfigurationConstants.RHQTYPE_AGENT.equals(rhqtype); } /** * Returns the endpoint key that includes base information of just the host and port (i.e. minus protocol along with * any and all query string parameters). * * @param endpoint the full endpoint * * @return the endpoint's base information */ private String getEndpointKey(InvokerLocator endpoint) { return getEndpointKey(endpoint.getHost(), endpoint.getPort()); } /** * Returns the endpoint key based on the given host and port. * * @param host the agent's host * @param port the agent's port * * @return the endpoint's base information */ private String getEndpointKey(String host, int port) { return host + ":" + port; } }