001/* 002 * VM-Operator 003 * Copyright (C) 2023 Michael N. Lipp 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <https://www.gnu.org/licenses/>. 017 */ 018 019package org.jdrupes.vmoperator.manager.events; 020 021import java.util.Collection; 022import java.util.Map; 023import java.util.Optional; 024import java.util.Set; 025import java.util.concurrent.ConcurrentHashMap; 026import java.util.function.Function; 027import org.jgrapes.core.Channel; 028 029/** 030 * Provides an actively managed implementation of the {@link ChannelDictionary}. 031 * 032 * The {@link ChannelManager} can be used for housekeeping by any component 033 * that creates channels. It can be shared between this component and 034 * some other component, preferably passing it as {@link ChannelDictionary} 035 * (the read-only view) to the second component. Alternatively, the other 036 * component can use a {@link ChannelTracker} to track the mappings using 037 * events. 038 * 039 * @param <K> the key type 040 * @param <C> the channel type 041 * @param <A> the type of the associated data 042 */ 043public class ChannelManager<K, C extends Channel, A> 044 implements ChannelDictionary<K, C, A> { 045 046 private final Map<K, Value<C, A>> entries = new ConcurrentHashMap<>(); 047 private final Function<K, C> supplier; 048 049 /** 050 * Instantiates a new channel manager. 051 * 052 * @param supplier the supplier that creates new channels 053 */ 054 public ChannelManager(Function<K, C> supplier) { 055 this.supplier = supplier; 056 } 057 058 /** 059 * Instantiates a new channel manager without a default supplier. 060 */ 061 public ChannelManager() { 062 this(k -> null); 063 } 064 065 /** 066 * Return all keys. 067 * 068 * @return the keys. 069 */ 070 @Override 071 public Set<K> keys() { 072 return entries.keySet(); 073 } 074 075 /** 076 * Return all known values. 077 * 078 * @return the collection 079 */ 080 @Override 081 public Collection<Value<C, A>> values() { 082 return entries.values(); 083 } 084 085 /** 086 * Returns the channel and associates data registered for the key 087 * or an empty optional if no mapping exists. 088 * 089 * @param key the key 090 * @return the result 091 */ 092 @Override 093 public Optional<Value<C, A>> value(K key) { 094 return Optional.ofNullable(entries.get(key)); 095 } 096 097 /** 098 * Store the given data. 099 * 100 * @param key the key 101 * @param channel the channel 102 * @param associated the associated 103 * @return the channel manager 104 */ 105 public ChannelManager<K, C, A> put(K key, C channel, A associated) { 106 entries.put(key, new Value<>(channel, associated)); 107 return this; 108 } 109 110 /** 111 * Store the given data. 112 * 113 * @param key the key 114 * @param channel the channel 115 * @return the channel manager 116 */ 117 public ChannelManager<K, C, A> put(K key, C channel) { 118 put(key, channel, null); 119 return this; 120 } 121 122 /** 123 * Creates a new channel without adding it to the channel manager. 124 * After fully initializing the channel, it should be added to the 125 * manager using {@link #put(K, C)}. 126 * 127 * @param key the key 128 * @return the c 129 */ 130 public C createChannel(K key) { 131 return supplier.apply(key); 132 } 133 134 /** 135 * Returns the {@link Channel} for the given name, creating it using 136 * the supplier passed to the constructor if it doesn't exist yet. 137 * 138 * @param key the key 139 * @return the channel 140 */ 141 public C channelGet(K key) { 142 return computeIfAbsent(key, supplier); 143 } 144 145 /** 146 * Returns the {@link Channel} for the given name, creating it using 147 * the given supplier if it doesn't exist yet. 148 * 149 * @param key the key 150 * @param supplier the supplier 151 * @return the channel 152 */ 153 public C computeIfAbsent(K key, Function<K, C> supplier) { 154 return entries.computeIfAbsent(key, 155 k -> new Value<>(supplier.apply(k), null)).channel(); 156 } 157 158 /** 159 * Associate the entry for the channel with the given data. The entry 160 * for the channel must already exist. 161 * 162 * @param key the key 163 * @param data the data 164 * @return the channel manager 165 */ 166 public ChannelManager<K, C, A> associate(K key, A data) { 167 Optional.ofNullable(entries.computeIfPresent(key, 168 (k, existing) -> new Value<>(existing.channel(), data))); 169 return this; 170 } 171 172 /** 173 * Removes the channel with the given name. 174 * 175 * @param name the name 176 */ 177 public void remove(K name) { 178 entries.remove(name); 179 } 180}