| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license |
| * agreements. See the NOTICE file distributed with this work for additional information regarding |
| * copyright ownership. The ASF licenses this file to You 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.apache.geode.management.internal.configuration.callbacks; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| import org.apache.commons.io.FileUtils; |
| import org.apache.logging.log4j.Logger; |
| |
| import org.apache.geode.cache.EntryEvent; |
| import org.apache.geode.cache.util.CacheListenerAdapter; |
| import org.apache.geode.distributed.DistributedMember; |
| import org.apache.geode.distributed.internal.InternalConfigurationPersistenceService; |
| import org.apache.geode.internal.cache.InternalCache; |
| import org.apache.geode.logging.internal.log4j.api.LogService; |
| import org.apache.geode.management.internal.configuration.domain.Configuration; |
| |
| /**** |
| * CacheListener on ConfigRegion on Locators to write the configuration changes to file-system. |
| * |
| */ |
| public class ConfigurationChangeListener extends CacheListenerAdapter<String, Configuration> { |
| private static final Logger logger = LogService.getLogger(); |
| |
| private final InternalConfigurationPersistenceService sharedConfig; |
| private final InternalCache cache; |
| |
| public ConfigurationChangeListener(InternalConfigurationPersistenceService sharedConfig, |
| InternalCache cache) { |
| this.sharedConfig = sharedConfig; |
| this.cache = cache; |
| } |
| |
| // Don't process the event locally. The action of adding or removing a jar should already have |
| // been performed by DeployCommand or UndeployCommand. |
| @Override |
| public void afterUpdate(EntryEvent<String, Configuration> event) { |
| super.afterUpdate(event); |
| if (event.isOriginRemote()) { |
| addOrRemoveJarFromFilesystem(event); |
| } |
| } |
| |
| @Override |
| public void afterCreate(EntryEvent<String, Configuration> event) { |
| super.afterCreate(event); |
| if (event.isOriginRemote()) { |
| addOrRemoveJarFromFilesystem(event); |
| } |
| } |
| |
| // Here we first remove any jars which are not used anymore and then we re-add all of the |
| // necessary jars again. This may appear a bit blunt but it also accounts for the situation |
| // where a jar is only being updated - i.e. the name does not change, only the content. |
| private void addOrRemoveJarFromFilesystem(EntryEvent<String, Configuration> event) { |
| String group = event.getKey(); |
| Configuration newConfig = event.getNewValue(); |
| Configuration oldConfig = event.getOldValue(); |
| Set<String> newJars = newConfig.getJarNames(); |
| Set<String> oldJars = (oldConfig == null) ? new HashSet<>() : oldConfig.getJarNames(); |
| |
| Set<String> jarsRemoved = new HashSet<>(oldJars); |
| jarsRemoved.removeAll(newJars); |
| |
| for (String jarRemoved : jarsRemoved) { |
| File jar = sharedConfig.getPathToJarOnThisLocator(group, jarRemoved).toFile(); |
| if (jar.exists()) { |
| try { |
| FileUtils.forceDelete(jar); |
| } catch (IOException e) { |
| logger.error( |
| "Exception occurred while attempting to delete a jar from the filesystem: {}", |
| jarRemoved, e); |
| } |
| } |
| } |
| |
| String triggerMemberId = (String) event.getCallbackArgument(); |
| if (triggerMemberId == null || newJars.isEmpty()) { |
| return; |
| } |
| |
| DistributedMember locator = getDistributedMember(triggerMemberId); |
| for (String jarAdded : newJars) { |
| try { |
| sharedConfig.downloadJarFromLocator(group, jarAdded, locator); |
| } catch (Exception e) { |
| logger.error("Unable to add jar: " + jarAdded, e); |
| } |
| } |
| } |
| |
| private DistributedMember getDistributedMember(String memberName) { |
| Set<DistributedMember> locators = new HashSet<>( |
| cache.getDistributionManager().getAllHostedLocatorsWithSharedConfiguration().keySet()); |
| return locators.stream() |
| .filter(x -> x.getId().equals(memberName)) |
| .findFirst() |
| .orElse(null); |
| } |
| } |