com.alibaba.nacos.common.tls.TlsFileWatcher Maven / Gradle / Ivy
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.nacos.common.tls;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.common.executor.ExecutorFactory;
import com.alibaba.nacos.common.executor.NameThreadFactory;
import com.alibaba.nacos.common.utils.ClassUtils;
import com.alibaba.nacos.common.utils.IoUtils;
import com.alibaba.nacos.common.utils.MD5Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Certificate file update monitoring
*
* Considering that the current client needs to support jdk 1.6 and module dependencies ,
* the WatchFileCenter in the core module is not used
*
* @author wangwei
*/
public final class TlsFileWatcher {
private static final Logger LOGGER = LoggerFactory.getLogger(TlsFileWatcher.class);
private AtomicBoolean started = new AtomicBoolean(false);
private final int checkInterval = TlsSystemConfig.tlsFileCheckInterval;
private Map fileMd5Map = new HashMap<>();
private ConcurrentHashMap watchFilesMap = new ConcurrentHashMap<>();
private final ScheduledExecutorService service = ExecutorFactory.Managed
.newSingleScheduledExecutorService(ClassUtils.getCanonicalName(TlsFileWatcher.class),
new NameThreadFactory("com.alibaba.nacos.core.common.tls"));
private static TlsFileWatcher tlsFileWatcher = new TlsFileWatcher();
private TlsFileWatcher() {
start();
}
public static TlsFileWatcher getInstance() {
return tlsFileWatcher;
}
/**
* Add file change listener for specified path.
*
* @param fileChangeListener listener
* @param filePaths file paths
* @throws IOException If an I/O error occurs
*/
public void addFileChangeListener(FileChangeListener fileChangeListener, String... filePaths) throws IOException {
for (String filePath : filePaths) {
if (filePath != null && new File(filePath).exists()) {
watchFilesMap.put(filePath, fileChangeListener);
InputStream in = null;
try {
in = new FileInputStream(filePath);
fileMd5Map.put(filePath, MD5Utils.md5Hex(IoUtils.toString(in, Constants.ENCODE), Constants.ENCODE));
} finally {
IoUtils.closeQuietly(in);
}
}
}
}
/**
* start file watch task. Notify when the MD5 of file changed
*/
public void start() {
if (started.compareAndSet(false, true)) {
service.scheduleAtFixedRate(() -> {
for (Map.Entry item : watchFilesMap.entrySet()) {
String filePath = item.getKey();
String newHash;
InputStream in = null;
try {
in = new FileInputStream(filePath);
newHash = MD5Utils.md5Hex(IoUtils.toString(in, Constants.ENCODE), Constants.ENCODE);
} catch (Exception exception) {
LOGGER.warn(" service has exception when calculate the file MD5. " + exception);
continue;
} finally {
IoUtils.closeQuietly(in);
}
if (!newHash.equals(fileMd5Map.get(filePath))) {
LOGGER.info(filePath + " file hash changed, need reload ssl context");
fileMd5Map.put(filePath, newHash);
item.getValue().onChanged(filePath);
LOGGER.info(filePath + " onChanged success!");
}
}
}, 1, checkInterval, TimeUnit.MINUTES);
}
}
public interface FileChangeListener {
/**
* listener onChanged event.
*
* @param filePath Path of changed file
*/
void onChanged(String filePath);
}
}