Package org.apache.aries.quiesce.manager.impl

Source Code of org.apache.aries.quiesce.manager.impl.QuiesceManagerImpl$QuiesceCallbackImpl

/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.aries.quiesce.manager.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.aries.quiesce.manager.QuiesceCallback;
import org.apache.aries.quiesce.manager.QuiesceManager;
import org.apache.aries.quiesce.participant.QuiesceParticipant;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class QuiesceManagerImpl implements QuiesceManager {
 
  /** Logger */
    private static final Logger LOGGER = LoggerFactory.getLogger(QuiesceManagerImpl.class.getName());
    /** The default timeout to use */
    private static int defaultTimeout = 60000;
    /** The container's {@link BundleContext} */
    private BundleContext bundleContext = null;
    /** The thread pool to execute timeout commands */
    private ScheduledExecutorService timeoutExecutor = Executors.newScheduledThreadPool(10);
    /** The thread pool to execute quiesce commands */
    private ExecutorService executor = new ThreadPoolExecutor(0, 10, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),new ThreadFactory() {
   
    public Thread newThread(Runnable arg0) {
      Thread t = new Thread(arg0, "Quiesce Manager Thread");
      t.setDaemon(true);
      return t;
    }
  });
    /** The map of bundles that are currently being quiesced */
    private static ConcurrentHashMap<Long, Bundle> bundleMap = new ConcurrentHashMap<Long, Bundle>();


    public QuiesceManagerImpl(BundleContext bc) {
      bundleContext = bc;
    }
   
    /**
     * Attempts to quiesce all bundles in the list. After the timeout has elapsed,
     * or if successfully quiesced before that, the bundles are stopped. This method
     * is non-blocking. Calling objects wishing to track the state of the bundles
     * need to listen for the resulting stop events.
     */
    public void quiesce(long timeout, List<Bundle> bundles) {
      if (bundles != null && !!!bundles.isEmpty()) {
      //check that bundle b is not already quiescing
      Iterator<Bundle> it = bundles.iterator();
      Set<Bundle> bundlesToQuiesce = new HashSet<Bundle>();
      while(it.hasNext()) {
        Bundle b = it.next();
        Bundle priorBundle = bundleMap.putIfAbsent(b.getBundleId(), b);
        if (priorBundle == null) {
          bundlesToQuiesce.add(b);
        }else{
          LOGGER.warn("Already quiescing bundle "+ b.getSymbolicName());
        }
          }
      Runnable command = new BundleQuiescer(bundlesToQuiesce, timeout, bundleMap);
      executor.execute(command);
      }
    }

    /**
     * Attempts to quiesce all bundles in the list, using the default timeout.
     * After the timeout has elapsed, or if successfully quiesced before that,
     * the bundles are stopped. This method is non-blocking. Calling objects
     * wishing to track the state of the bundles need to listen for the
     * resulting stop events.
     */
    public void quiesce(List<Bundle> bundlesToQuiesce) {
      quiesce(defaultTimeout, bundlesToQuiesce);
    }
 
    private static boolean stopBundle(Bundle bundleToStop) {
      try {
        bundleToStop.stop();
        bundleMap.remove(bundleToStop.getBundleId());
      }catch (BundleException be) {
        return false;
      }
      return true;
    }

    /**
     * BundleQuiescer is used for each bundle to quiesce. It creates a callback object for each
     * participant. Well-behaved participants will be non-blocking on their quiesce method.
     * When all callbacks for the participants have completed, this thread will get an
     * interrupt, so it sleeps until it hits the timeout. When complete it stops the bundle
     * and removes the bundles from the list of those that are being quiesced.
     */
    private class BundleQuiescer implements Runnable {
   
      private Set<Bundle> bundlesToQuiesce;
      private long timeout;
     
      public BundleQuiescer(Set<Bundle> bundlesToQuiesce, long timeout, ConcurrentHashMap<Long, Bundle> bundleMap) {
        this.bundlesToQuiesce = new HashSet<Bundle>(bundlesToQuiesce);
        this.timeout = timeout;
      }

      public void run() {
        try {
        if (bundleContext != null) {
          ServiceReference[] serviceRefs = bundleContext.getServiceReferences(QuiesceParticipant.class.getName(), null);
          if (serviceRefs != null) {
            List<QuiesceParticipant> participants = new ArrayList<QuiesceParticipant>();
            final List<QuiesceCallbackImpl> callbacks = new ArrayList<QuiesceCallbackImpl>();
            Set<Bundle> copyOfBundles = new HashSet<Bundle>(bundlesToQuiesce);
            Timer timer = new Timer();
           
            //Create callback objects for all participants
            for( ServiceReference sr : serviceRefs ) {
              QuiesceParticipant participant = (QuiesceParticipant) bundleContext.getService(sr);
              participants.add(participant);
              callbacks.add(new QuiesceCallbackImpl(copyOfBundles, callbacks, timer));
            }
           
            //Quiesce each participant and wait for an interrupt from a callback
            //object when all are quiesced, or the timeout to be reached
            for( int i=0; i<participants.size(); i++ ) {
              QuiesceParticipant participant = participants.get(i);
              QuiesceCallbackImpl callback = callbacks.get(i);
              List<Bundle> participantBundles = new ArrayList<Bundle>();
              //deep copy
              for (Bundle b : copyOfBundles) {
                participantBundles.add(b);
              }
              participant.quiesce(callback, participantBundles);
            }
            timer.schedule(new TimerTask() {

              @Override
              public void run() {
                //stop bundles
                //go through callbacks and cancel all bundles
                for ( Enumeration<Bundle> remainingBundles = bundleMap.elements(); remainingBundles.hasMoreElements(); ) {
                  Bundle b = remainingBundles.nextElement();
                  LOGGER.warn("Could not quiesce, so stopping bundle "+ b.getSymbolicName());
                  stopBundle(b);
                }
                /*
                for ( QuiesceCallbackImpl cb : callbacks ) {
                  System.out.println("Clearing callback");
                  cb.clear();
                  }
                  */
              }
             
            }, timeout);
          }else{
            LOGGER.warn("No participants, so stopping bundles");
            for ( Enumeration<Bundle> remainingBundles = bundleMap.elements(); remainingBundles.hasMoreElements(); ) {
              Bundle b = remainingBundles.nextElement();
              stopBundle(b);
            }
          }
        }
      } catch (InvalidSyntaxException e) {
        LOGGER.warn("Exception trying to get service references for quiesce participants "+ e.getMessage());
      }
    }
  }
    /**
     * Callback object provided for each participant for each quiesce call
     * from the quiesce manager.
     */
    private static class QuiesceCallbackImpl implements QuiesceCallback {
      //Must be a copy
      private final Set<Bundle> toQuiesce;
      //Must not be a copy
      private final List<QuiesceCallbackImpl> allCallbacks;
      //Timer so we can cancel the alarm if all done
      private final Timer timer;
     
      public QuiesceCallbackImpl(Collection<Bundle> toQuiesce, List<QuiesceCallbackImpl> allCallbacks, Timer timer)
      {
        this.toQuiesce = new HashSet<Bundle>(toQuiesce);
        this.allCallbacks = allCallbacks;
        this.timer = timer;
      }

      public void clear() {
      // TODO Auto-generated method stub
     
    }

    /**
       * Removes the bundles from the list of those to quiesce.
       * If the list is now empty, this callback object is finished (i.e.
       * the participant linked to this object has quiesced all the bundles
       * requested). 
       *
       * If all other participants have also completed, then the
       * calling BundleQuieser thread is interrupted.
       */
      public void bundleQuiesced(Bundle... bundlesQuiesced) {
       
        synchronized (allCallbacks) {
        for(Bundle b : bundlesQuiesced) {
          if(toQuiesce.remove(b)) {
            if(checkOthers(b)){
             QuiesceManagerImpl.stopBundle(b);
             if(allCallbacksComplete()){
               timer.cancel();
             }
            }
          }
        }
      }
      }

    private boolean checkOthers(Bundle b) {
      boolean allDone = true;
      Iterator<QuiesceCallbackImpl> it = allCallbacks.iterator();
      while (allDone && it.hasNext()) {
        allDone = !!!it.next().toQuiesce.contains(b);
      }
      return allDone;
    }
   
    private boolean allCallbacksComplete() {
      boolean allDone = true;
      Iterator<QuiesceCallbackImpl> it = allCallbacks.iterator();
      while (allDone && it.hasNext()) {
        allDone = !!!it.next().toQuiesce.isEmpty();
      }
      return allDone;
    }   
    }
}
TOP

Related Classes of org.apache.aries.quiesce.manager.impl.QuiesceManagerImpl$QuiesceCallbackImpl

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.