Package clojure.osgi.internal

Source Code of clojure.osgi.internal.ExtenderTracker

package clojure.osgi.internal;

import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.ServiceReference;
import org.osgi.service.log.LogService;
import org.osgi.util.tracker.BundleTracker;
import org.osgi.util.tracker.ServiceTracker;

import clojure.lang.RT;
import clojure.lang.Var;
import clojure.osgi.RunnableWithException;

public class ExtenderTracker extends BundleTracker {
  private Set<Long> requireProcessed = new HashSet<Long>();
  private Set<Long> active = new HashSet<Long>();
  private ServiceTracker logTracker;
  private LogService log = new StreamLog(System.out);

  private enum CallbackType {
    START, STOP
  }

  public ExtenderTracker(BundleContext context) {
    super(context, Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING, null);

    logTracker = new ServiceTracker(context,
        org.osgi.service.log.LogService.class.getName(), null) {
      @Override
      public Object addingService(ServiceReference reference) {
        return log = (LogService) super.addingService(reference);
      }

      @Override
      public void removedService(ServiceReference reference,
          Object service) {
        super.removedService(reference, service);

        log = new StreamLog(System.out);
      }
    };

    logTracker.open();
  }

  public Object addingBundle(Bundle bundle, BundleEvent event) {
    if (!requireProcessed.contains(bundle.getBundleId())) {
      processRequire(bundle);
      requireProcessed.add(bundle.getBundleId());
    }

    if ((bundle.getState() == Bundle.STARTING || bundle.getState() == Bundle.ACTIVE)
        && !active.contains(bundle.getBundleId())) {

      try {
        invokeActivatorCallback(CallbackType.START, bundle);
      } finally {
        active.add(bundle.getBundleId());
      }

    } else if (bundle.getState() == Bundle.STOPPING
        && active.contains(bundle.getBundleId())) {
      try {
        invokeActivatorCallback(CallbackType.STOP, bundle);
      } finally {
        active.remove(bundle.getBundleId());
      }
    }

    return null;
  }

  private void processRequire(Bundle bundle) {
    String header = (String) bundle.getHeaders().get("Clojure-Require");

    if (header != null) {
      StringTokenizer lib = new StringTokenizer(header, ",");
      while (lib.hasMoreTokens()) {
        final String ns = lib.nextToken().trim();
                if (log != null)
          log.log(LogService.LOG_DEBUG, String.format(
              "requiring %s from bundle %s", ns, bundle));
        ClojureOSGi.require(bundle, ns);
      }
    }
  }

    private String callbackFunctionName(CallbackType callback, String header) {
    // TODO support callback function name customization. i.e.:
    // Clojure-ActivatorNamespace:
    // a.b.c.d;start-function="myStart";stop-function="myStop"
    switch (callback) {
    case START:
      return "bundle-start";

    case STOP:
      return "bundle-stop";

    default:
      throw new IllegalStateException();
    }
  }

  private void invokeActivatorCallback(CallbackType callback,
      final Bundle bundle) {
    final String ns = (String) bundle.getHeaders().get(
        "Clojure-ActivatorNamespace");
    if (ns != null) {
      final String callbackFunction = callbackFunctionName(callback, ns);
      final Var var = RT.var(ns, callbackFunction);
            if (var.isBound()) {
        try {
          ClojureOSGi.withBundle(bundle, new RunnableWithException() {
            public Object run() throws Exception {
              if (log != null)
                log.log(LogService.LOG_DEBUG,
                    String.format(
                        "invoking function %s/%s for bundle: %s",
                        ns, callbackFunction, bundle));

              var.invoke(bundle.getBundleContext());
             
              return null;
            }
          });

        } catch (Exception e) {
          throw new RuntimeException(e);
        }
      } else {
        throw new RuntimeException(String.format(
            "'%s' is not bound in '%s'", callbackFunction, ns));

            }
    }
  }

  public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) {

  }

  public void removedBundle(Bundle bundle, BundleEvent event, Object object) {

  }

  public void close() {
    logTracker.close();
    super.close();
  }

}
TOP

Related Classes of clojure.osgi.internal.ExtenderTracker

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.