Java tutorial
/* * 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.eagle.alert.coordinator.trigger; import org.apache.eagle.alert.engine.coordinator.PolicyDefinition; import org.apache.eagle.alert.service.IMetadataServiceClient; import com.google.common.base.Stopwatch; import org.apache.commons.collections.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; import java.util.concurrent.TimeUnit; /** * Poll policy change and notify listeners. */ public class DynamicPolicyLoader implements Runnable { private static Logger LOG = LoggerFactory.getLogger(DynamicPolicyLoader.class); private IMetadataServiceClient client; // initial cachedPolicies should be empty private Map<String, PolicyDefinition> cachedPolicies = new HashMap<>(); private List<PolicyChangeListener> listeners = new ArrayList<>(); public DynamicPolicyLoader(IMetadataServiceClient client) { this.client = client; } public synchronized void addPolicyChangeListener(PolicyChangeListener listener) { listeners.add(listener); } /** * When it is run at the first time, due to cachedPolicies being empty, all existing policies are expected * to be addedPolicies. */ @SuppressWarnings("unchecked") @Override public void run() { // we should catch every exception to avoid zombile thread try { final Stopwatch watch = Stopwatch.createStarted(); LOG.info("Starting to load policies"); List<PolicyDefinition> current = client.listPolicies(); Map<String, PolicyDefinition> currPolicies = new HashMap<>(); current.forEach(pe -> currPolicies.put(pe.getName(), pe)); Collection<String> addedPolicies = CollectionUtils.subtract(currPolicies.keySet(), cachedPolicies.keySet()); Collection<String> removedPolicies = CollectionUtils.subtract(cachedPolicies.keySet(), currPolicies.keySet()); Collection<String> potentiallyModifiedPolicies = CollectionUtils.intersection(currPolicies.keySet(), cachedPolicies.keySet()); List<String> reallyModifiedPolicies = new ArrayList<>(); for (String updatedPolicy : potentiallyModifiedPolicies) { if (currPolicies.get(updatedPolicy) != null && !currPolicies.get(updatedPolicy).equals(cachedPolicies.get(updatedPolicy))) { reallyModifiedPolicies.add(updatedPolicy); } } boolean policyChanged = false; if (addedPolicies.size() != 0 || removedPolicies.size() != 0 || reallyModifiedPolicies.size() != 0) { policyChanged = true; } if (!policyChanged) { LOG.info("No policy (totally {}) changed since last round", current.size()); return; } synchronized (this) { for (PolicyChangeListener listener : listeners) { listener.onPolicyChange(current, addedPolicies, removedPolicies, reallyModifiedPolicies); } } watch.stop(); LOG.info("Finished loading {} policies, added: {}, removed: {}, modified: {}, taken: {} ms", current.size(), addedPolicies.size(), removedPolicies.size(), potentiallyModifiedPolicies.size(), watch.elapsed(TimeUnit.MILLISECONDS)); // reset cached policies cachedPolicies = currPolicies; } catch (Throwable t) { LOG.warn("Error loading policy, but continue to run", t); } } }