All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.janusproject.kernel.services.hazelcast.HazelcastDistributedDataStructureService Maven / Gradle / Ivy

There is a newer version: 3.0.12.0
Show newest version
/*
 * $Id: io/janusproject/kernel/services/hazelcast/HazelcastDistributedDataStructureService.java v2.0.3.1 2016-01-24 00:05:13$
 *
 * Janus platform is an open-source multiagent platform.
 * More details on http://www.janusproject.io
 *
 * Copyright (C) 2014-2015 the original authors 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 io.janusproject.kernel.services.hazelcast;

import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.google.common.base.Objects;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Multiset;
import com.google.common.util.concurrent.Service;
import com.google.inject.Inject;
import com.hazelcast.core.EntryEvent;
import com.hazelcast.core.EntryListener;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import com.hazelcast.core.MapEvent;
import com.hazelcast.core.MultiMap;
import com.hazelcast.map.listener.MapListener;

import io.janusproject.services.AbstractDependentService;
import io.janusproject.services.distributeddata.DMap;
import io.janusproject.services.distributeddata.DMapListener;
import io.janusproject.services.distributeddata.DMultiMap;
import io.janusproject.services.distributeddata.DistributedDataStructureService;

/**
 * Service based on Hazelcast that permits to manage data structures
 * that are shared over a network.
 *
 * @author Sebastian Rodriguez
 * @author Nicolas Gaud
 * @author Stéphane Galland
 * @version 2.0.3.1 2016-01-24 00:05:13
 * @mavengroupid io.janusproject
 * @mavenartifactid io.janusproject.kernel
 */
public class HazelcastDistributedDataStructureService extends AbstractDependentService
		implements DistributedDataStructureService {

	@Inject
	private HazelcastInstance hazelcastInstance;

	@Override
	public final Class getServiceType() {
		return DistributedDataStructureService.class;
	}

	/** Change the hazelcast instance used by this factory.
	 *
	 * @param hazelcastInstance - reference to the Hazelcast engine.
	 */
	void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
		this.hazelcastInstance = hazelcastInstance;
	}

	@Override
	protected void doStart() {
		notifyStarted();
	}

	@Override
	protected void doStop() {
		notifyStopped();
	}

	@Override
	public  DMap getMap(String name) {
		IMap map = this.hazelcastInstance.getMap(name);
		if (map != null) {
			return new MapView<>(name, map);
		}
		return null;
	}

	@Override
	public  DMap getMap(String name, Comparator comparator) {
		IMap map = this.hazelcastInstance.getMap(name);
		if (map != null) {
			return new MapView<>(name, map);
		}
		return null;
	}

	@Override
	public  DMultiMap getMultiMap(String name) {
		MultiMap map = this.hazelcastInstance.getMultiMap(name);
		if (map != null) {
			return new MultiMapView<>(name, map);
		}
		return null;
	}

	@Override
	public  DMultiMap getMultiMap(String name, Comparator comparator) {
		MultiMap map = this.hazelcastInstance.getMultiMap(name);
		if (map != null) {
			return new MultiMapView<>(name, map);
		}
		return null;
	}

	/**
	 * @param  - type of the keys.
	 * @param  - type of the values.
	 * @author Stéphane Galland
	 * @version 2.0.3.1 2016-01-24 00:05:13
	 * @mavengroupid io.janusproject
	 * @mavenartifactid io.janusproject.kernel
	 */
	private static final class MapView implements DMap {

		private final String name;

		private final IMap map;

		MapView(String name, IMap map) {
			assert (map != null);
			this.name = name;
			this.map = map;
		}

		@Override
		public boolean isBackedCollection() {
			return false;
		}

		@Override
		public String getName() {
			return this.name;
		}

		@Override
		public void clear() {
			this.map.clear();
		}

		@Override
		public boolean containsKey(Object arg0) {
			return this.map.containsKey(arg0);
		}

		@Override
		public boolean containsValue(Object arg0) {
			return this.map.containsValue(arg0);
		}

		@Override
		public Set> entrySet() {
			return this.map.entrySet();
		}

		@Override
		public V get(Object arg0) {
			return this.map.get(arg0);
		}

		@Override
		public boolean isEmpty() {
			return this.map.isEmpty();
		}

		@Override
		public Set keySet() {
			return this.map.keySet();
		}

		@Override
		public V put(K arg0, V arg1) {
			return this.map.put(arg0, arg1);
		}

		@Override
		public void putAll(Map arg0) {
			this.map.putAll(arg0);
		}

		@Override
		public V remove(Object arg0) {
			return this.map.remove(arg0);
		}

		@Override
		public int size() {
			return this.map.size();
		}

		@Override
		public Collection values() {
			return this.map.values();
		}

		@Override
		public V putIfAbsent(K key, V value) {
			return this.map.putIfAbsent(key, value);
		}

		@Override
		public void addDMapListener(DMapListener listener) {
			EntryListenerWrapper w = new EntryListenerWrapper<>(listener);
			String k = this.map.addEntryListener((MapListener) w, true);
			w.setHazelcastListener(k);
		}

		@Override
		public void removeDMapListener(DMapListener listener) {
			if (listener instanceof EntryListenerWrapper) {
				String k = ((EntryListenerWrapper) listener).getHazelcastListener();
				if (k != null) {
					this.map.removeEntryListener(k);
				}
			}
		}

	}

	/**
	 * @param  - type of the keys.
	 * @param  - type of the values.
	 * @author Stéphane Galland
	 * @version 2.0.3.1 2016-01-24 00:05:13
	 * @mavengroupid io.janusproject
	 * @mavenartifactid io.janusproject.kernel
	 */
	@SuppressWarnings("unchecked")
	private static final class MultiMapView implements DMultiMap {

		private final String name;

		private final MultiMap map;

		MultiMapView(String name, MultiMap map) {
			this.name = name;
			assert (map != null);
			this.map = map;
		}

		@Override
		public boolean isBackedCollection() {
			return false;
		}

		@Override
		public String getName() {
			return this.name;
		}

		@Override
		public boolean put(K key, V value) {
			return this.map.put(key, value);
		}

		@Override
		public Collection get(K key) {
			return this.map.get(key);
		}

		@Override
		public boolean remove(Object key, Object value) {
			return this.map.remove(key, value);
		}

		@Override
		public Collection removeAll(Object key) {
			return this.map.remove(key);
		}

		@Override
		public Set keySet() {
			return this.map.keySet();
		}

		@Override
		public Multiset keys() {
			return new SetMultiset();
		}

		@Override
		public Collection values() {
			return this.map.values();
		}

		@Override
		public Collection> entries() {
			return this.map.entrySet();
		}

		@Override
		public boolean containsKey(Object key) {
			try {
				return this.map.containsKey((K) key);
			} catch (ClassCastException exception) {
				return false;
			}
		}

		@Override
		public boolean containsValue(Object value) {
			return this.map.containsValue(value);
		}

		@Override
		public boolean containsEntry(Object key, Object value) {
			try {
				return this.map.containsEntry((K) key, (V) value);
			} catch (ClassCastException exception) {
				return false;
			}
		}

		@Override
		public int size() {
			return this.map.size();
		}

		@Override
		public void clear() {
			this.map.clear();
		}

		@Override
		public int valueCount(K key) {
			return this.map.valueCount(key);
		}

		@Override
		public void addDMapListener(DMapListener listener) {
			EntryListenerWrapper w = new EntryListenerWrapper<>(listener);
			String k = this.map.addEntryListener(w, true);
			w.setHazelcastListener(k);
		}

		@Override
		public void removeDMapListener(DMapListener listener) {
			if (listener instanceof EntryListenerWrapper) {
				String k = ((EntryListenerWrapper) listener).getHazelcastListener();
				if (k != null) {
					this.map.removeEntryListener(k);
				}
			}
		}

		@Override
		public boolean isEmpty() {
			return this.map.size() == 0;
		}

		@Override
		public Collection replaceValues(K key, Iterable values) {
			Collection oldValues = this.map.remove(key);
			for (V value : values) {
				this.map.put(key, value);
			}
			return oldValues;
		}

		@Override
		public boolean putAll(Multimap multimap) {
			boolean changed = false;
			for (Entry value : multimap.entries()) {
				changed = this.map.put(value.getKey(), value.getValue()) && changed;
			}
			return changed;
		}

		@Override
		public boolean putAll(K key, Iterable values) {
			boolean changed = false;
			for (V value : values) {
				changed = this.map.put(key, value) && changed;
			}
			return changed;
		}

		@Override
		public Map> asMap() {
			return Multimaps.asMap(this);
		}

		/** Internal implementation of a multiset.
		 *
		 * @author Stéphane Galland
		 * @version 2.0.3.1 2016-01-24 00:05:13
		 * @mavengroupid io.janusproject
		 * @mavenartifactid io.janusproject.kernel
		 */
		private class SetMultiset implements Multiset {

			/** Construct.
			 */
			SetMultiset() {
				//
			}

			@Override
			public int size() {
				return MultiMapView.this.size();
			}

			@Override
			public boolean isEmpty() {
				return MultiMapView.this.isEmpty();
			}

			@Override
			public Object[] toArray() {
				Object[] tab = new Object[MultiMapView.this.size()];
				int i = 0;
				for (Map.Entry e : MultiMapView.this.entries()) {
					tab[i] = e.getKey();
					++i;
				}
				return tab;
			}

			@Override
			public  T[] toArray(T[] array) {
				T[] tab = array;
				if (tab == null || tab.length < MultiMapView.this.size()) {
					tab = (T[]) new Object[MultiMapView.this.size()];
					int i = 0;
					for (Map.Entry e : MultiMapView.this.entries()) {
						tab[i] = (T) e.getKey();
						++i;
					}
				}
				return tab;
			}

			@Override
			public void clear() {
				MultiMapView.this.clear();
			}

			@Override
			public int count(Object element) {
				int c = 0;
				for (Map.Entry e : MultiMapView.this.entries()) {
					if (Objects.equal(element, e.getKey())) {
						++c;
					}
				}
				return c;
			}

			@Override
			public int add(K element, int occurrences) {
				throw new UnsupportedOperationException();
			}

			@Override
			public boolean add(K element) {
				throw new UnsupportedOperationException();
			}

			@Override
			public boolean remove(Object element) {
				Collection values = MultiMapView.this.removeAll(element);
				return values != null && !values.isEmpty();
			}

			@Override
			public int remove(Object element, int occurrences) {
				if (occurrences < 0) {
					throw new IllegalArgumentException();
				}
				try {
					Collection values = MultiMapView.this.get((K) element);
					int old = values.size();
					Iterator iterator = values.iterator();
					for (int i = 0; i < occurrences && iterator.hasNext(); ++i) {
						iterator.next();
						iterator.remove();
					}
					return old;
				} catch (ClassCastException exception) {
					return 0;
				}
			}

			@Override
			public int setCount(K element, int count) {
				if (count < 0) {
					throw new IllegalArgumentException();
				}
				Collection values = MultiMapView.this.get(element);
				int old = values.size();
				if (count > old) {
					throw new UnsupportedOperationException();
				}
				try {
					Iterator iterator = values.iterator();
					int toRemove = old - count;
					for (int i = 0; i < toRemove && iterator.hasNext(); ++i) {
						iterator.next();
						iterator.remove();
					}
					return old;
				} catch (ClassCastException exception) {
					return 0;
				}
			}

			@Override
			public boolean setCount(K element, int oldCount, int newCount) {
				if (oldCount < 0 || newCount < 0) {
					throw new IllegalArgumentException();
				}
				Collection values = MultiMapView.this.get(element);
				int old = values.size();
				if (oldCount == old) {
					if (newCount > old) {
						throw new UnsupportedOperationException();
					}
					try {
						Iterator iterator = values.iterator();
						int toRemove = old - newCount;
						if (toRemove > 0) {
							for (int i = 0; i < toRemove && iterator.hasNext(); ++i) {
								iterator.next();
								iterator.remove();
							}
							return true;
						}
					} catch (ClassCastException exception) {
						//
					}
				}
				return false;
			}

			@Override
			public boolean addAll(Collection collection) {
				throw new UnsupportedOperationException();
			}

			@Override
			public Set elementSet() {
				return MultiMapView.this.keySet();
			}

			@Override
			public Set> entrySet() {
				throw new UnsupportedOperationException();
			}

			@Override
			public Iterator iterator() {
				final Iterator> entries = MultiMapView.this.entries().iterator();
				return new Iterator() {
					@Override
					public boolean hasNext() {
						return entries.hasNext();
					}

					@Override
					public K next() {
						return entries.next().getKey();
					}

					@Override
					public void remove() {
						entries.remove();
					}

				};
			}

			@Override
			public boolean contains(Object element) {
				return MultiMapView.this.containsKey(element);
			}

			@Override
			public boolean containsAll(Collection elements) {
				return MultiMapView.this.keySet().containsAll(elements);
			}

			@Override
			public boolean removeAll(Collection collection) {
				return MultiMapView.this.keySet().removeAll(collection);
			}

			@Override
			public boolean retainAll(Collection collection) {
				return MultiMapView.this.keySet().retainAll(collection);
			}

		}

	}

	/** Listener on the Hazelcast map events.
	 *
	 * @param  type of the keys.
	 * @param  type of the values.
	 * @author Stéphane Galland
	 * @version 2.0.3.1 2016-01-24 00:05:13
	 * @mavengroupid io.janusproject
	 * @mavenartifactid io.janusproject.kernel
	 */
	private static class EntryListenerWrapper implements EntryListener {

		private final DMapListener dmapListener;

		private String key;

		EntryListenerWrapper(DMapListener listener) {
			this.dmapListener = listener;
		}

		/** Replies the Hazelcast listener associated to this object.
		 *
		 * @return the hazelcast listener.
		 */
		public String getHazelcastListener() {
			return this.key;
		}

		/** Replies the Hazelcast listener associated to this object.
		 *
		 * @param hazelcastListener - the hazelcast listener.
		 */
		public void setHazelcastListener(String hazelcastListener) {
			this.key = hazelcastListener;
		}

		@Override
		public void entryAdded(EntryEvent event) {
			this.dmapListener.entryAdded(event.getKey(), event.getValue());
		}

		@Override
		public void entryEvicted(EntryEvent event) {
			if (event.getValue() != null) {
				this.dmapListener.entryRemoved(event.getKey(), event.getValue());
			} else {
				this.dmapListener.entryRemoved(event.getKey(), event.getOldValue());
			}
		}

		@Override
		public void entryRemoved(EntryEvent event) {
			if (event.getValue() != null) {
				this.dmapListener.entryRemoved(event.getKey(), event.getValue());
			} else {
				this.dmapListener.entryRemoved(event.getKey(), event.getOldValue());
			}
		}

		@Override
		public void entryUpdated(EntryEvent event) {
			this.dmapListener.entryUpdated(event.getKey(), event.getValue());
		}

		@Override
		public void mapCleared(MapEvent event) {
			this.dmapListener.mapCleared(true);
		}

		@Override
		public void mapEvicted(MapEvent event) {
			this.dmapListener.mapCleared(false);
		}

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy