Package org.iosgi.servicebus

Source Code of org.iosgi.servicebus.ServiceBus

/* 
* i-OSGi - Tunable Bundle Isolation for OSGi
* Copyright (C) 2011  Sven Schulz
*
* 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
package org.iosgi.servicebus;

import java.io.IOException;
import java.net.InetAddress;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.felix.ipojo.annotations.Component;
import org.apache.felix.ipojo.annotations.Invalidate;
import org.apache.felix.ipojo.annotations.Property;
import org.apache.felix.ipojo.annotations.Provides;
import org.apache.felix.ipojo.annotations.Requires;
import org.apache.felix.ipojo.annotations.Validate;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.NodeExistsException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.iosgi.util.Network;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.hooks.service.EventHook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.ethz.iks.r_osgi.RemoteOSGiException;
import ch.ethz.iks.r_osgi.RemoteOSGiService;
import ch.ethz.iks.r_osgi.RemoteServiceReference;
import ch.ethz.iks.r_osgi.URI;

/**
* @author Sven Schulz
*/
@Component(immediate = true)
@Provides(specifications = EventHook.class)
public class ServiceBus implements EventHook, Watcher {

  private static final Logger LOGGER = LoggerFactory
      .getLogger(ServiceBus.class);
  private static final String ROOT_PATH = "/iosgi/services";

  @Property(name = "serverPort", value = "2181")
  private int serverPort;

  @Property(name = "serverAddress", value = "")
  private String serverAddress;

  @Requires
  private RemoteOSGiService remoteOSGiSvc;

  @Requires
  private Network network;

  private ZooKeeper zk;
  private InetAddress localAddr;
  private int port;
  private Set<ServiceDescriptor> active;
  private BundleContext context;
  private Map<ServiceDescriptor, RemoteServiceReference> refByDesc;

  ServiceBus(BundleContext context) {
    this.context = context;
    active = new HashSet<ServiceDescriptor>();
    refByDesc = new HashMap<ServiceDescriptor, RemoteServiceReference>();
  }

  private void create(String path) throws KeeperException,
      InterruptedException {
    String[] nodes = path.split("/");
    StringBuilder currPath = new StringBuilder();
    for (String n : nodes) {
      if (n.isEmpty())
        continue;
      currPath.append("/").append(n);
      try {
        if (zk.exists(currPath.toString(), false) != null) {
          continue;
        }
        zk.create(currPath.toString(), new byte[0],
            Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
      } catch (NodeExistsException ke) {
        /* OK, that's fine! */
      }
    }
  }

  @Validate
  void activate() throws IOException, KeeperException, InterruptedException,
      InvalidSyntaxException {
    localAddr = network.getAddress();
    port = remoteOSGiSvc.getListeningPort("r-osgi");
    String zkAddr = (serverAddress.isEmpty() ? localAddr.getHostAddress()
        : serverAddress);
    LOGGER.debug("connecting to zookeeper server ({}:{})", zkAddr,
        serverPort);
    zk = new ZooKeeper(zkAddr + ":" + serverPort, 3000, this);
    create(ROOT_PATH);
    update();
    ServiceReference[] refs = context.getAllServiceReferences(null, null);
    for (ServiceReference ref : refs) {
      ServiceEvent evt = new ServiceEvent(ServiceEvent.REGISTERED, ref);
      process(evt);
    }
  }

  @Invalidate
  void deactivate() throws InterruptedException {
    zk.close();
  }

  @Override
  public void event(ServiceEvent event,
      @SuppressWarnings("rawtypes") Collection contexts) {
    process(event);
  }

  private void process(final ServiceEvent event) {
    ServiceReference ref = event.getServiceReference();
    if (ref.getProperty(RemoteOSGiService.R_OSGi_REGISTRATION) == null) {
      return;
    }
    Long sid = (Long) ref.getProperty(Constants.SERVICE_ID);
    ServiceDescriptor desc = new ServiceDescriptor(localAddr, port, sid);
    String path = ROOT_PATH + "/" + desc;
    switch (event.getType()) {
    case ServiceEvent.REGISTERED: {
      try {
        zk.create(path, new byte[0], Ids.OPEN_ACL_UNSAFE,
            CreateMode.EPHEMERAL);
      } catch (Exception e) {
        LOGGER.error("service node creation failed (Path: " + path
            + ")", e);
      }
      break;
    }
    case ServiceEvent.UNREGISTERING: {
      try {
        zk.delete(path, -1);
      } catch (Exception e) {
        LOGGER.error("service node deletion failed (Path: " + path
            + ")", e);
      }
      break;
    }
    default: {
      // TODO MODIFIED
    }
    }
  }

  private URI getAddress(ServiceDescriptor desc, boolean service) {
    StringBuilder b = new StringBuilder();
    b.append("r-osgi://").append(desc.getHost().getHostAddress())
        .append(':').append(desc.getPort());
    if (service) {
      b.append('#').append(desc.getServiceId());
    }
    return URI.create(b.toString());
  }

  private void connect(final ServiceDescriptor desc)
      throws RemoteOSGiException, IOException {
    URI uri = this.getAddress(desc, false);
    // ChannelEndpointManager cem = remoteOSGiSvc.getEndpointManager(uri);
    // if (cem == null) {
    remoteOSGiSvc.connect(uri);
    // }
  }

  private boolean isLocal(final ServiceDescriptor desc) {
    return desc.getHost().equals(this.localAddr)
        && desc.getPort() == this.port;
  }

  public synchronized void update() {
    Stat stat = new Stat();
    List<String> paths = null;
    try {
      paths = zk.getChildren(ROOT_PATH, this, stat);
    } catch (Exception e) {
      LOGGER.error("fetching service node list failed", e);
      return;
    }
    Set<ServiceDescriptor> stale = new HashSet<ServiceDescriptor>(active);
    for (String p : paths) {
      ServiceDescriptor desc = new ServiceDescriptor(p);
      if (isLocal(desc)) {
        continue;
      }
      if (!active.contains(desc)) {
        LOGGER.debug("connecting to {}", desc);
        try {
          connect(desc);
        } catch (Exception e) {
          LOGGER.error("failed to establish connection (Service-Descriptor: "
              + desc + ")");
        }
        LOGGER.debug("getting remote service ({})", desc);
        URI suri = this.getAddress(desc, true);
        RemoteServiceReference rref = null;
        int retries = 5;
        while (rref == null) {
          rref = remoteOSGiSvc.getRemoteServiceReference(suri);
          if (rref == null) {
            LOGGER.debug(
                "remote service unavailable ({}, #retries: {})",
                desc, retries--);
            try {
              Thread.sleep(1000);
            } catch (InterruptedException ie) {
              // Ignore
            }
            continue;
          }
        }
        active.add(desc);
        Object obj = remoteOSGiSvc.getRemoteService(rref);
        obj.hashCode();
        refByDesc.put(desc, rref);
      } else {
        stale.remove(desc);
      }
    }
    for (ServiceDescriptor desc : stale) {
      LOGGER.debug("ungetting remote service ({})", desc);
      active.remove(desc);
      RemoteServiceReference rref = refByDesc.remove(desc);
      try {
        remoteOSGiSvc.ungetRemoteService(rref);
      } catch (Exception e) {
        /* Ignore */
      }
    }
  }

  @Override
  public void process(final WatchedEvent evt) {
    switch (evt.getType()) {
    case NodeChildrenChanged: {
      update();
      break;
    }
    }
  }

}
TOP

Related Classes of org.iosgi.servicebus.ServiceBus

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.