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 @Override 066 public Set<K> keys() { 067 return entries.keySet(); 068 } 069 070 /** 071 * Return all known values. 072 * 073 * @return the collection 074 */ 075 @Override 076 public Collection<Value<C, A>> values() { 077 return entries.values(); 078 } 079 080 /** 081 * Returns the channel and associates data registered for the key 082 * or an empty optional if no mapping exists. 083 * 084 * @param key the key 085 * @return the result 086 */ 087 public Optional<Value<C, A>> value(K key) { 088 return Optional.ofNullable(entries.get(key)); 089 } 090 091 /** 092 * Store the given data. 093 * 094 * @param key the key 095 * @param channel the channel 096 * @param associated the associated 097 * @return the channel manager 098 */ 099 public ChannelManager<K, C, A> put(K key, C channel, A associated) { 100 entries.put(key, new Value<>(channel, associated)); 101 return this; 102 } 103 104 /** 105 * Store the given data. 106 * 107 * @param key the key 108 * @param channel the channel 109 * @return the channel manager 110 */ 111 public ChannelManager<K, C, A> put(K key, C channel) { 112 put(key, channel, null); 113 return this; 114 } 115 116 /** 117 * Returns the {@link Channel} for the given name, creating it using 118 * the supplier passed to the constructor if it doesn't exist yet. 119 * 120 * @param key the key 121 * @return the channel 122 */ 123 public C channelGet(K key) { 124 return computeIfAbsent(key, supplier); 125 } 126 127 /** 128 * Returns the {@link Channel} for the given name, creating it using 129 * the given supplier if it doesn't exist yet. 130 * 131 * @param key the key 132 * @param supplier the supplier 133 * @return the channel 134 */ 135 @SuppressWarnings({ "PMD.AssignmentInOperand", 136 "PMD.DataflowAnomalyAnalysis" }) 137 public C computeIfAbsent(K key, Function<K, C> supplier) { 138 return entries.computeIfAbsent(key, 139 k -> new Value<>(supplier.apply(k), null)).channel(); 140 } 141 142 /** 143 * Associate the entry for the channel with the given data. The entry 144 * for the channel must already exist. 145 * 146 * @param key the key 147 * @param data the data 148 * @return the channel manager 149 */ 150 public ChannelManager<K, C, A> associate(K key, A data) { 151 Optional.ofNullable(entries.computeIfPresent(key, 152 (k, existing) -> new Value<>(existing.channel(), data))); 153 return this; 154 } 155 156 /** 157 * Removes the channel with the given name. 158 * 159 * @param name the name 160 */ 161 public void remove(String name) { 162 entries.remove(name); 163 } 164}