Package org.jboss.services.binding.impl

Source Code of org.jboss.services.binding.impl.PojoServiceBindingStore

/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.services.binding.impl;

import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.jboss.logging.Logger;
import org.jboss.services.binding.DuplicateServiceException;
import org.jboss.services.binding.NoSuchBindingException;
import org.jboss.services.binding.ServiceBinding;
import org.jboss.services.binding.ServiceBindingMetadata;
import org.jboss.services.binding.ServiceBindingStore;

/**
* A Pojo implementation of {@link ServiceBindingStore}.
*
* @author Brian Stansberry
* @version $Revision: 88905 $
*/
public class PojoServiceBindingStore
   implements ServiceBindingStore
{
   private static final Logger log = Logger.getLogger(PojoServiceBindingStore.class);
  
   /** Dummy value to make ConcurrentHashMap act like a Set */
   private static final Object VALUE = new Object();
  
   // ------------------------------------------------------------ Constructors
  
   /** All bindings */
   private final ConcurrentMap<ServiceBindingKey, ServiceBinding> bindings =
      new ConcurrentHashMap<ServiceBindingKey, ServiceBinding>(16, (float) .75, 2);
  
   /** Injected binding sets*/
   private final ConcurrentMap<String, ServiceBindingSet> bindingSets =
      new ConcurrentHashMap<String, ServiceBindingSet>(16, (float) .75, 2);
  
   /** Injected base bindings whose ports are incremented for each set */
   private final Map<ServiceBindingMetadata, Object> standardBindings =
      new ConcurrentHashMap<ServiceBindingMetadata, Object>(16, (float) .75, 2);
  
   private boolean started;
   // ------------------------------------------------------------ Constructors
  
   /**
    * Creates a new PojoServiceBindingStore
    */
   public PojoServiceBindingStore() {}
  
   public PojoServiceBindingStore(Set<ServiceBindingSet> bindingSets, Set<ServiceBindingMetadata> standardBindings)
   {
      setServiceBindingSetsInternal(bindingSets);
      setStandardBindingsInternal(standardBindings);
   }
  
   // ----------------------------------------------------- ServiceBindingStore
  
   public synchronized void addServiceBinding(String serverName, ServiceBindingMetadata metadata)
      throws DuplicateServiceException, UnknownHostException
   {     
      addServiceBindingInternal(serverName, metadata, true);
     
      log.debug("added binding " + metadata.getFullyQualifiedName() + " to " + serverName);
   }

   public synchronized ServiceBinding getServiceBinding(String serverName, String serviceName, String bindingName)
         throws NoSuchBindingException
   {
      ServiceBinding binding = bindings.get(new ServiceBindingKey(serverName, serviceName, bindingName));
      if (binding == null)
      {
         throw new NoSuchBindingException(serverName, serviceName, bindingName);
      }
      return binding;
   }
  
   public synchronized Set<ServiceBinding> getServiceBindings(String serverName)
   {
      validateServerName(serverName);
     
      Set<ServiceBinding> result = new HashSet<ServiceBinding>();
      for (Map.Entry<ServiceBindingKey, ServiceBinding> entry : bindings.entrySet())
      {
         if (serverName.equals(entry.getKey().serverName))
         {
            result.add(entry.getValue());
         }
      }
     
      return result;
   }

   public synchronized void removeServiceBinding(String serverName, ServiceBindingMetadata metadata)
   {
      validateServerName(serverName);
      bindings.remove(new ServiceBindingKey(serverName, metadata));
     
      // For management purposes, treat this as an override
      ServiceBindingSet bindingSet = bindingSets.get(serverName);
      bindingSet.getOverrideBindings().remove(metadata);
   }

   public synchronized String getDefaultHostName(String serverName)
   {
      validateServerName(serverName);
      return bindingSets.get(serverName).getDefaultHostName();
   }

   public synchronized int getDefaultPortOffset(String serverName)
   {
      validateServerName(serverName);
      return bindingSets.get(serverName).getPortOffset();
   }
  
   // ------------------------------------------------------------------ Public
  
   /**
    * Sets the base set of bindings that should be associated with each binding set,
    * adjusted to conform to the binding set's defaultHostName and offset.
    *
    * @param bindings the set of base bindings. May be <code>null</code>
    * @throws DuplicateServiceException
    * @throws UnknownHostException
    *
    * @throws IllegalStateException if invoked after {@link #start()}
    */
   public synchronized void setStandardBindings(Set<ServiceBindingMetadata> bindings) throws UnknownHostException, DuplicateServiceException
   {     
      setStandardBindingsInternal(bindings);
     
      if (started)
      {
         log.debug("updated standard bindings injected");
         if (log.isTraceEnabled())
         {
            for (ServiceBindingMetadata sbm : bindings)
            {
               log.trace(sbm.getFullyQualifiedName() + " port is " + sbm.getPort() + " " + sbm.isFixedHostName() + "/" + sbm.isFixedPort());
            }
         }
        
         establishBindings();
      }
   }
  
   public synchronized void setServiceBindingSets(Set<ServiceBindingSet> sets) throws UnknownHostException, DuplicateServiceException
   {     
      setServiceBindingSetsInternal(sets);    
     
      if (started)
      {
         log.debug("updated ServiceBindingSets injected");
         if (log.isTraceEnabled())
         {
            for (ServiceBindingSet set : sets)
            {
               log.trace(set.getName() + " offset is " + set.getPortOffset() + " defaultHostName is " + set.getDefaultHostName());
               java.util.Set<ServiceBindingMetadata> ovr = set.getOverrideBindings();
               for (ServiceBindingMetadata sbm : ovr)
               {
                  log.trace(sbm.getFullyQualifiedName() + " port is " + sbm.getPort() + " " + sbm.isFixedHostName() + "/" + sbm.isFixedPort());
               }
            }
         }
         establishBindings();
      }
   }
  
   /**
    * Builds the runtime sets of bindings from the injected base bindings
    * and ServiceBindingSets.
    *
    * @throws DuplicateServiceException
    * @throws UnknownHostException
    */
   public void start() throws DuplicateServiceException, UnknownHostException
   {
      establishBindings();
     
      this.started = true;
   }
  
   public void stop()
   {
      this.bindings.clear();
           
      this.started = false;
   }
  
   // -------------------------------------------------------------- Management

   /**
    * Gets the base set of bindings that should be associated with each binding set,
    * but with that binding set's {@link ServiceBindingSet#getPortOffset() port offset}
    * applied to the port value.
    *
    * @return the set of base bindings
    */
   public Set<ServiceBindingMetadata> getStandardBindings()
   {
      return new HashSet<ServiceBindingMetadata>(standardBindings.keySet());
   }
  
   /**
    * See {@link #getServiceBindingSets()}
    *
    * @return the binding sets
    *
    * @deprecated use {@link #getServiceBindingSets()}
    */
   public Set<ServiceBindingSet> getBindingSets()
   {
      return getServiceBindingSets();
   }
  
   /**
    * Gets the {@link ServiceBindingSet}s associated with this store.
    *
    * @return  the binding sets. Will not return <code>null</code>
    */
   public Set<ServiceBindingSet> getServiceBindingSets()
   {
      return new HashSet<ServiceBindingSet>(bindingSets.values());
   }
  
   /**
    * Add a ServiceBinding to all binding sets in the store. For each binding
    * set, a new ServiceBinding is added whose serviceName and bindingName
    * properties match the passed binding. If <the given <code>binding</code>'s
    * <code>fixeHostName</code> property is <code>false</code>, the new binding's
    * hostName matches the target set's {@link #getDefaultHostName(String) default host name}.
    * If <code>binding</code>'s <code>fixedPort</code> property is <code>false</code>,
    * the new binding's port is derived by taking the port from the passed binding
    * and incrementing it by the target set's
    * {@link #getDefaultPortOffset(String) default port offset}.
    *
    * @param metadata metadata about the binding to add
    *
    * @throws DuplicateServiceException thrown if a configuration for the
    *    <serverName, serviceName> pair already exists.
    */
   public synchronized void addServiceBinding(ServiceBindingMetadata metadata) throws DuplicateServiceException
   {
      // Add to the runtime objects
      for (ServiceBindingSet bindingSet : bindingSets.values())
      {
         try
         {
            addServiceBindingInternal(bindingSet.getName(), metadata, false);
         }
         catch (UnknownHostException e)
         {
            String hostName = metadata.isFixedHostName() ? metadata.getHostName() : bindingSet.getDefaultHostName();
            throw new IllegalStateException("Cannot convert " + hostName + " into an InetAddress");
         }
      }
     
      // Add to the managed object map
      standardBindings.put(metadata, VALUE);
   }
  
   /**
    * Creates a new {@link ServiceBindingMetadata} from the given params
    * and calls {@link #addServiceBinding(ServiceBindingMetadata)}.
    *
    * @param serviceName the name of the service. Cannot be <code>null</code>
    * @param bindingName name qualifier for the binding within the service.
    *                    May be <code>null</code>
    * @param hostName hostname or IP address to which the binding should be
    *                 bound. Use <code>null</code> to indicate the host name
    *                 should be the default host name for each binding set
    * @param serviceConfig the configuration to add
    * @param fixed <code>true</code> if the binding's port should remain fixed
    *              when added to each binding set; <code>false</code> if it
    *              should be offset by the binding set's port offset
    *
    * @throws DuplicateServiceException thrown if a configuration for the
    *    <serverName, serviceName> pair already exists.
    */
   public synchronized void addServiceBinding(String serviceName, String bindingName, String hostName, int port, boolean fixedPort)
      throws DuplicateServiceException, UnknownHostException
   {
      addServiceBinding(serviceName, bindingName, null, hostName, port, false, fixedPort);
   }
  
   /**
    * Creates a new {@link ServiceBindingMetadata} from the given params
    * and calls {@link #addServiceBinding(ServiceBindingMetadata)}.
    *
    * @param serviceName the name of the service. Cannot be <code>null</code>
    * @param bindingName name qualifier for the binding within the service.
    *                    May be <code>null</code>
    * @param description helpful description of the binding; may be <code>null</code>
    * @param hostName hostname or IP address to which the binding should be
    *                 bound. Often <code>null</code> since the host name typically
    *                 comes from the default host name for each binding set
    * @param port  port the binding should use
    * @param fixedHostName <code>true</code> if the binding's <code>hostName</code>
    *              should remain fixed when added to each binding set;
    *              <code>false</code> if it should be changed to the binding set's
    *              default host name
    * @param fixedPort <code>true</code> if the binding's port should remain fixed
    *              when added to each binding set; <code>false</code> if it
    *              should be offset by the binding set's port offset
    *
    * @throws DuplicateServiceException thrown if a configuration for the
    *    <serverName, serviceName> pair already exists.
    */
   public synchronized void addServiceBinding(String serviceName, String bindingName, String description, String hostName, int port, boolean fixedHostName, boolean fixedPort)
      throws DuplicateServiceException, UnknownHostException
   {
      ServiceBindingMetadata metadata = new ServiceBindingMetadata();
      metadata.setServiceName(serviceName);
      metadata.setBindingName(bindingName);
      metadata.setHostName(hostName);
      metadata.setPort(port);
      metadata.setFixedPort(fixedPort);
     
      addServiceBinding(metadata);
   }

   /**
    * Remove a service configuration from all binding sets in the store.
    *
    * @param metadata the binding
    */
   public synchronized void removeServiceBinding(ServiceBindingMetadata metadata)
   {
      // Remove from runtime sets
      for (String serverName : bindingSets.keySet())
      {
         removeServiceBinding(serverName, metadata);
      }
     
      // Remove from managed set
      standardBindings.remove(metadata);
   }

   /**
    * Remove a service configuration from all binding sets in the store.
    *
    * @param serviceName the name of the service. Cannot be <code>null</code>
    * @param bindingName name qualifier for the binding within the service.
    *                    May be <code>null</code>
    */
   public synchronized void removeServiceBinding(String serviceName, String bindingName)
   {
      ServiceBindingMetadata metadata = new ServiceBindingMetadata(serviceName, bindingName);
      removeServiceBinding(metadata);
   }
  
   // ------------------------------------------------------------------ Private

   private static boolean safeEquals(Object a, Object b)
   {     
      return (a == b || (a != null && a.equals(b)));
   }
  
   private void validateServerName(String serverName)
   {
      if (bindingSets.containsKey(serverName) == false)
         throw new IllegalArgumentException("unknown serverName " +serverName);
   }

   private void setServiceBindingSetsInternal(Set<ServiceBindingSet> sets)
   {
      this.bindingSets.clear();
     
      if (sets != null)
      {     
         for (ServiceBindingSet bindingSet : sets)
         {
            this.bindingSets.put(bindingSet.getName(), bindingSet);
         }
      }
   }

   private void setStandardBindingsInternal(Set<ServiceBindingMetadata> bindings)
   {
      standardBindings.clear();
      if (bindings != null)
      {
         for (ServiceBindingMetadata binding : bindings)
         {
            standardBindings.put(binding, VALUE);
         }
      }
   }
  
   private void establishBindings() throws UnknownHostException, DuplicateServiceException
   {
      synchronized (this)
      {
         this.bindings.clear();
        
         // Establish the override bindings first, so when we add the
         // fixed and portOffset, we get DuplicateServiceException
         for (ServiceBindingSet bindingSet : bindingSets.values())
         {
            for (ServiceBindingMetadata binding : bindingSet.getOverrideBindings())
            {
               addServiceBindingInternal(bindingSet.getName(), binding, false);
            }
         }
        
         // Establish the standard bindings  
         for (ServiceBindingMetadata metadata : standardBindings.keySet())
         {
            for (ServiceBindingSet bindingSet : bindingSets.values())
            {
               try
               {
                  addServiceBindingInternal(bindingSet.getName(), metadata, false);
               }
               catch (DuplicateServiceException e)
               {
                  if (bindingSet.getOverrideBindings().contains(metadata) == false)
                  {
                     throw e;
                  }
               }
            }
         }
      }
   }
  
   private void addServiceBindingInternal(String serverName, ServiceBindingMetadata metadata, boolean addToBindingSet)
      throws DuplicateServiceException, UnknownHostException
   {     
      validateServerName(serverName);
      ServiceBindingSet bindingSet = bindingSets.get(serverName);
      ServiceBinding binding = new ServiceBinding(metadata, bindingSet.getDefaultHostName(), bindingSet.getPortOffset());
      ServiceBinding oldBinding = bindings.putIfAbsent(new ServiceBindingKey(serverName, metadata), binding);
      if (oldBinding != null &&
            (safeEquals(oldBinding.getHostName(), binding.getHostName()) == false
               || oldBinding.getPort() != binding.getPort()))
      {
         throw new DuplicateServiceException(serverName, binding);
      }
     
      if (addToBindingSet)
      {
         // For management purposes, treat this as an override
         bindingSet.getOverrideBindings().add(metadata);
      }
   }

   private static class ServiceBindingKey
   {
      private final String serverName;
      private final String serviceName;
      private final String bindingName;
     
      private ServiceBindingKey(String serverName, ServiceBindingMetadata binding)
      {
         if (serverName == null)
         {
            throw new IllegalArgumentException("serverName is null");
         }
         if (binding == null)
         {
            throw new IllegalArgumentException("binding is null");
         }
         if (binding.getServiceName() == null)
         {
            throw new IllegalStateException("binding's serviceName is null");
         }
        
         this.serverName = serverName;
         this.serviceName = binding.getServiceName();
         this.bindingName = binding.getBindingName();
      }
     
      private ServiceBindingKey(String serverName, String serviceName, String bindingName)
      {
         if (serverName == null)
         {
            throw new IllegalArgumentException("serverName is null");
         }

         if (serviceName == null)
         {
            throw new IllegalArgumentException("serviceName is null");
         }
        
         this.serverName  = serverName;
         this.serviceName = ServiceBindingMetadata.canonicalizeServiceName(serviceName);
         this.bindingName = bindingName;
      }

      @Override
      public boolean equals(Object obj)
      {
         if (obj instanceof ServiceBindingKey)
         {
            ServiceBindingKey other = (ServiceBindingKey) obj;
            return (this.serverName.equals(other.serverName)
                    && this.serviceName.equals(other.serviceName)
                    && safeEquals(this.bindingName, other.bindingName));
         }
         return false;
      }

      @Override
      public int hashCode()
      {
         int result = 17;
         result += 23 * this.serverName.hashCode();
         result += 23 * this.serviceName.hashCode();
         result += 23 * (this.bindingName == null ? 0 : this.bindingName.hashCode());
         return result;
      }
     
   }

}
TOP

Related Classes of org.jboss.services.binding.impl.PojoServiceBindingStore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.