Home » geronimo-2.2-source-release » org.apache.geronimo.gjndi.binding » [javadoc | source]

    1   /**
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    */
   17   package org.apache.geronimo.gjndi.binding;
   18   
   19   import java.util.HashSet;
   20   import java.util.LinkedHashMap;
   21   import java.util.Map;
   22   import java.util.Set;
   23   
   24   import javax.naming.Context;
   25   import javax.naming.NamingException;
   26   
   27   import org.slf4j.Logger;
   28   import org.slf4j.LoggerFactory;
   29   import org.apache.geronimo.gbean.AbstractName;
   30   import org.apache.geronimo.gbean.AbstractNameQuery;
   31   import org.apache.geronimo.gbean.GBeanInfo;
   32   import org.apache.geronimo.gbean.GBeanInfoBuilder;
   33   import org.apache.geronimo.gbean.GBeanLifecycle;
   34   import org.apache.geronimo.kernel.GBeanNotFoundException;
   35   import org.apache.geronimo.kernel.Kernel;
   36   import org.apache.geronimo.kernel.lifecycle.LifecycleAdapter;
   37   import org.apache.geronimo.kernel.lifecycle.LifecycleListener;
   38   
   39   /**
   40    * @version $Rev$ $Date$
   41    */
   42   public class GBeanBinding implements GBeanLifecycle {
   43       private static final Logger log = LoggerFactory.getLogger(GBeanBinding.class);
   44   
   45       private final Context context;
   46       private final String name;
   47       private final AbstractNameQuery abstractNameQuery;
   48       private final Kernel kernel;
   49   
   50       private final LifecycleListener listener = new GBeanLifecycleListener();
   51       private final LinkedHashMap<AbstractName, Object> bindings = new LinkedHashMap<AbstractName, Object>();
   52   
   53       public GBeanBinding(Context context, String name, AbstractNameQuery abstractNameQuery, Kernel kernel) {
   54           this.context = context;
   55           this.name = name;
   56           this.abstractNameQuery = abstractNameQuery;
   57           this.kernel = kernel;
   58       }
   59   
   60       public synchronized void doStart() {
   61           kernel.getLifecycleMonitor().addLifecycleListener(listener, abstractNameQuery);
   62           Set<AbstractName> set = kernel.listGBeans(abstractNameQuery);
   63           for (AbstractName abstractName : set) {
   64               try {
   65                   if (kernel.isRunning(abstractName)) {
   66                       addBinding(abstractName);
   67                   }
   68               } catch (NamingException e) {
   69                   log.error("Error adding binding for " + abstractName, e);
   70               }
   71           }
   72   
   73       }
   74   
   75       public void doStop() {
   76           destroy();
   77       }
   78   
   79       public void doFail() {
   80           destroy();
   81       }
   82   
   83       private synchronized void destroy() {
   84           kernel.getLifecycleMonitor().removeLifecycleListener(listener);
   85           Set<AbstractName> abstractNames = new HashSet<AbstractName>(bindings.keySet());
   86           for (AbstractName abstractName : abstractNames) {
   87               removeBinding(abstractName);
   88           }
   89           bindings.clear();
   90       }
   91   
   92       private class GBeanLifecycleListener extends LifecycleAdapter {
   93           public void running(AbstractName abstractName) {
   94               try {
   95                   addBinding(abstractName);
   96               } catch (NamingException e) {
   97                   log.error("Error adding binding for " + abstractName);
   98               }
   99           }
  100   
  101           public void stopping(AbstractName abstractName) {
  102               removeBinding(abstractName);
  103           }
  104   
  105           public void stopped(AbstractName abstractName) {
  106               removeBinding(abstractName);
  107           }
  108   
  109           public void failed(AbstractName abstractName) {
  110               removeBinding(abstractName);
  111           }
  112   
  113           public void unloaded(AbstractName abstractName) {
  114               removeBinding(abstractName);
  115           }
  116       }
  117   
  118       /**
  119        * Binds the specified gbean.  This method uses createBindingName and preprocessValue before binding the object.
  120        *
  121        * @param abstractName the abstract name of the gbean to bind
  122        * @throws NamingException if an error occurs during binding
  123        */
  124       protected synchronized void addBinding(AbstractName abstractName) throws NamingException {
  125           if (bindings.containsKey(abstractName)) {
  126               // previously bound
  127               return;
  128           }
  129   
  130           // get the gbean
  131           Object instance;
  132           try {
  133               instance = kernel.getGBean(abstractName);
  134           } catch (GBeanNotFoundException e) {
  135               throw (NamingException)new NamingException("GBean not found: " + abstractName).initCause(e);
  136           }
  137   
  138           // preprocess the instance
  139           instance = preprocessVaue(abstractName, instance);
  140   
  141           addBinding(abstractName, instance);
  142       }
  143   
  144       private synchronized void addBinding(AbstractName abstractName, Object value) throws NamingException {
  145           if (bindings.isEmpty()) {
  146               context.bind(name, value);
  147           }
  148           bindings.put(abstractName, value);
  149       }
  150   
  151       /**
  152        * Unbinds the specified gbean.
  153        *
  154        * @param abstractName the abstract name of the gbean to unbind
  155        */
  156       protected synchronized void removeBinding(AbstractName abstractName) {
  157           Map.Entry entry = first(bindings);
  158           if (entry != null && entry.getKey().equals(abstractName)) {
  159               Object oldValue = bindings.remove(abstractName);
  160               entry = first(bindings);
  161               if (entry != null) {
  162                   Object newAbstractName = entry.getValue();
  163                   Object newValue = entry.getValue();
  164                   try {
  165                       context.rebind(name, newValue);
  166                   } catch (NamingException e) {
  167                       boolean unbound = unbind(abstractName, oldValue);
  168                       // avoid double logging
  169                       if (unbound) log.error("Unable to rebind binding " + name + " to " + newAbstractName);
  170                   }
  171               } else {
  172                   unbind(abstractName, oldValue);
  173               }
  174           } else {
  175               bindings.remove(abstractName);
  176           }
  177       }
  178   
  179       private boolean unbind(AbstractName abstractName, Object value) {
  180           // first check if we are still bound
  181           try {
  182               if (context.lookup(name) != value) {
  183                   return true;
  184               }
  185           } catch (NamingException ignored) {
  186               // binding doesn't exist
  187               return true;
  188           }
  189   
  190           try {
  191               context.unbind(name);
  192               return true;
  193           } catch (NamingException e1) {
  194               log.error("Unable to remove binding " + name + " to " + abstractName, e1);
  195           }
  196           return false;
  197       }
  198   
  199       private static Map.Entry first(LinkedHashMap map) {
  200           if (map.isEmpty()) return null;
  201           return (Map.Entry) map.entrySet().iterator().next();
  202       }
  203   
  204       /**
  205        * Preprocess the value before it is bound.  This is usefult for wrapping values with reference objects.
  206        * By default, this method simply return the value.
  207        *
  208        * @param abstractName the abstract name of the gbean to bind
  209        * @param value        the gbean instance
  210        * @return the value to bind
  211        */
  212       protected Object preprocessVaue(AbstractName abstractName, Object value) throws NamingException {
  213           return value;
  214       }
  215   
  216       public static final GBeanInfo GBEAN_INFO;
  217   
  218       public static GBeanInfo getGBeanInfo() {
  219           return GBEAN_INFO;
  220       }
  221   
  222       static {
  223           GBeanInfoBuilder builder = GBeanInfoBuilder.createStatic(GBeanBinding.class, "GBeanBinding");
  224           builder.addReference("Context", Context.class);
  225           builder.addAttribute("name", String.class, true);
  226           builder.addAttribute("abstractNameQuery", AbstractNameQuery.class, true);
  227           builder.setConstructor(new String[]{"Context", "name", "abstractNameQuery", "kernel"});
  228           GBEAN_INFO = builder.getBeanInfo();
  229       }
  230   }

Home » geronimo-2.2-source-release » org.apache.geronimo.gjndi.binding » [javadoc | source]