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 public Optional<Value<C, A>> value(K key) { 093 return Optional.ofNullable(entries.get(key)); 094 } 095 096 /** 097 * Store the given data. 098 * 099 * @param key the key 100 * @param channel the channel 101 * @param associated the associated 102 * @return the channel manager 103 */ 104 public ChannelManager<K, C, A> put(K key, C channel, A associated) { 105 entries.put(key, new Value<>(channel, associated)); 106 return this; 107 } 108 109 /** 110 * Store the given data. 111 * 112 * @param key the key 113 * @param channel the channel 114 * @return the channel manager 115 */ 116 public ChannelManager<K, C, A> put(K key, C channel) { 117 put(key, channel, null); 118 return this; 119 } 120 121 /** 122 * Creates a new channel without adding it to the channel manager. 123 * After fully initializing the channel, it should be added to the 124 * manager using {@link #put(K, C)}. 125 * 126 * @param key the key 127 * @return the c 128 */ 129 public C createChannel(K key) { 130 return supplier.apply(key); 131 } 132 133 /** 134 * Returns the {@link Channel} for the given name, creating it using 135 * the supplier passed to the constructor if it doesn't exist yet. 136 * 137 * @param key the key 138 * @return the channel 139 */ 140 public C channelGet(K key) { 141 return computeIfAbsent(key, supplier); 142 } 143 144 /** 145 * Returns the {@link Channel} for the given name, creating it using 146 * the given supplier if it doesn't exist yet. 147 * 148 * @param key the key 149 * @param supplier the supplier 150 * @return the channel 151 */ 152 @SuppressWarnings({ "PMD.AssignmentInOperand", 153 "PMD.DataflowAnomalyAnalysis" }) 154 public C computeIfAbsent(K key, Function<K, C> supplier) { 155 return entries.computeIfAbsent(key, 156 k -> new Value<>(supplier.apply(k), null)).channel(); 157 } 158 159 /** 160 * Associate the entry for the channel with the given data. The entry 161 * for the channel must already exist. 162 * 163 * @param key the key 164 * @param data the data 165 * @return the channel manager 166 */ 167 public ChannelManager<K, C, A> associate(K key, A data) { 168 Optional.ofNullable(entries.computeIfPresent(key, 169 (k, existing) -> new Value<>(existing.channel(), data))); 170 return this; 171 } 172 173 /** 174 * Removes the channel with the given name. 175 * 176 * @param name the name 177 */ 178 public void remove(String name) { 179 entries.remove(name); 180 } 181}