Package org.vertx.java.core.eventbus.impl.hazelcast

Source Code of org.vertx.java.core.eventbus.impl.hazelcast.HazelcastSubsMap

/*
* Copyright 2011-2012 the original author or authors.
*
* 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.vertx.java.core.eventbus.impl.hazelcast;

import com.hazelcast.core.EntryEvent;
import com.hazelcast.core.EntryListener;
import org.vertx.java.core.AsyncResult;
import org.vertx.java.core.AsyncResultHandler;
import org.vertx.java.core.Handler;
import org.vertx.java.core.eventbus.impl.ServerIDs;
import org.vertx.java.core.eventbus.impl.SubsMap;
import org.vertx.java.core.impl.BlockingAction;
import org.vertx.java.core.impl.DefaultFutureResult;
import org.vertx.java.core.impl.VertxInternal;
import org.vertx.java.core.logging.Logger;
import org.vertx.java.core.logging.impl.LoggerFactory;
import org.vertx.java.core.net.impl.ServerID;

import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
* @author <a href="http://tfox.org">Tim Fox</a>
*/
public class HazelcastSubsMap implements SubsMap, EntryListener<String, HazelcastServerID> {

  private static final Logger log = LoggerFactory.getLogger(HazelcastSubsMap.class);

  private final VertxInternal vertx;
  private final com.hazelcast.core.MultiMap<String, HazelcastServerID> map;

  /*
   The Hazelcast near cache is very slow so we use our own one.
   Keeping it in sync is a little tricky. As entries are added or removed the EntryListener will be called
   but when the node joins the cluster it isn't provided the initial state via the EntryListener
   Therefore the first time get is called for a subscription we *always* get the subs from
   Hazelcast (this is what the initialised flag is for), then consider that the initial state.
   While the get is in progress the entry listener may be being called, so we merge any
   pre-existing entries so we don't lose any. Hazelcast doesn't seem to have any consistent
   way to get an initial state plus a stream of updates.
    */
  private ConcurrentMap<String, ServerIDs> cache = new ConcurrentHashMap<>();

  public HazelcastSubsMap(VertxInternal vertx, com.hazelcast.core.MultiMap<String, HazelcastServerID> map) {
    this.vertx = vertx;
    this.map = map;
    map.addEntryListener(this, true);
  }

  public void removeAllForServerID(final ServerID serverID, final Handler<AsyncResult<Void>> completionHandler) {
    new BlockingAction<Void>(vertx, completionHandler) {
      public Void action() {
        for (Map.Entry<String, HazelcastServerID> entry: map.entrySet()) {
          HazelcastServerID hid = entry.getValue();
          if (hid.serverID.equals(serverID)) {
            map.remove(entry.getKey(), hid);
          }
        }
        return null;
      }
    }.run();
  }

  @Override
  public void put(final String subName, final ServerID serverID, final Handler<AsyncResult<Void>> completionHandler) {
    new BlockingAction<Void>(vertx, completionHandler) {
      public Void action() {
        map.put(subName, new HazelcastServerID(serverID));
        return null;
      }
    }.run();
  }

  @Override
  public void get(final String subName, final Handler<AsyncResult<ServerIDs>> completionHandler) {
    ServerIDs entries = cache.get(subName);
    DefaultFutureResult<ServerIDs> result = new DefaultFutureResult<>();
    if (entries != null && entries.isInitialised()) {
      result.setResult(entries).setHandler(completionHandler);
    } else {
      new BlockingAction<Collection<HazelcastServerID>>(vertx, new AsyncResultHandler<Collection<HazelcastServerID>>() {
        public void handle(AsyncResult<Collection<HazelcastServerID>> result) {
          DefaultFutureResult<ServerIDs> sresult = new DefaultFutureResult<>();
          if (result.succeeded()) {
            Collection<HazelcastServerID> entries = result.result();
            ServerIDs sids;
            if (entries != null) {
              sids = new ServerIDs(entries.size());
              for (HazelcastServerID hid: entries) {
                sids.add(hid.serverID);
              }
            } else {
              sids = new ServerIDs(0);
            }
            ServerIDs prev = cache.putIfAbsent(subName, sids);
            if (prev != null) {
              // Merge them
              prev.merge(sids);
              sids = prev;
            }
            sids.setInitialised();
            sresult.setResult(sids);
          } else {
            sresult.setFailure(result.cause());
          }
          sresult.setHandler(completionHandler);
        }
      }) {
        public Collection<HazelcastServerID> action() {
          return map.get(subName);
        }
      }.run();
    }
  }

  @Override
  public void remove(final String subName, final ServerID serverID, final Handler<AsyncResult<Void>> completionHandler) {
    new BlockingAction<Void>(vertx, completionHandler) {
      public Void action() {
        map.remove(subName, new HazelcastServerID(serverID));
        return null;
      }
    }.run();
  }

  @Override
  public void entryAdded(EntryEvent<String, HazelcastServerID> entry) {
    addEntry(entry.getKey(), entry.getValue().serverID);
  }

  private void addEntry(String key, ServerID value) {
    ServerIDs entries = cache.get(key);
    if (entries == null) {
      entries = new ServerIDs(1);
      ServerIDs prev = cache.putIfAbsent(key, entries);
      if (prev != null) {
        entries = prev;
      }
    }
    entries.add(value);
  }

  @Override
  public void entryRemoved(EntryEvent<String, HazelcastServerID> entry) {
    removeEntry(entry.getKey(), entry.getValue().serverID);
  }

  private void removeEntry(String key, ServerID value) {
    ServerIDs entries = cache.get(key);
    if (entries != null) {
      entries.remove(value);
      if (entries.isEmpty()) {
        cache.remove(key);
      }
    }
  }

  @Override
  public void entryUpdated(EntryEvent<String, HazelcastServerID> entry) {
    String key = entry.getKey();
    ServerIDs entries = cache.get(key);
    if (entries != null) {
      entries.add(entry.getValue().serverID);
    }
  }

  @Override
  public void entryEvicted(EntryEvent<String, HazelcastServerID> entry) {
    entryRemoved(entry);
  }



}
TOP

Related Classes of org.vertx.java.core.eventbus.impl.hazelcast.HazelcastSubsMap

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.