All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.solr.pkg.PackageListeners Maven / Gradle / Ivy

There is a newer version: 9.7.0
Show newest version
/*
 * 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.solr.pkg;

import java.lang.invoke.MethodHandles;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import org.apache.solr.common.MapWriter;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrCore;
import org.apache.solr.logging.MDCLoggingContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PackageListeners {
  private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

  public static final String PACKAGE_VERSIONS = "PKG_VERSIONS";
  private final SolrCore core;

  public PackageListeners(SolrCore core) {
    this.core = core;
  }

  // this registry only keeps a weak reference because it does not want to
  // cause a memory leak if the listener forgets to unregister itself
  private List> listeners = new CopyOnWriteArrayList<>();

  public synchronized void addListener(Listener listener) {
    listeners.add(new SoftReference<>(listener));
  }

  public synchronized void addListener(Listener listener, boolean addFirst) {
    if (addFirst) {
      listeners.add(0, new SoftReference<>(listener));
    } else {
      addListener(listener);
    }
  }

  public synchronized void removeListener(Listener listener) {
    Iterator> it = listeners.iterator();
    while (it.hasNext()) {
      Reference ref = it.next();
      Listener pkgListener = ref.get();
      if (pkgListener == null || pkgListener == listener) {
        it.remove();
      }
    }
  }

  synchronized void packagesUpdated(List pkgs) {
    MDCLoggingContext.setCore(core);
    Listener.Ctx ctx = new Listener.Ctx();
    try {
      for (SolrPackageLoader.SolrPackage pkgInfo : pkgs) {
        invokeListeners(pkgInfo, ctx);
      }
    } finally {
      ctx.runLaterTasks(r -> core.getCoreContainer().runAsync(r));
      MDCLoggingContext.clear();
    }
  }

  private synchronized void invokeListeners(SolrPackageLoader.SolrPackage pkg, Listener.Ctx ctx) {
    for (Reference ref : listeners) {
      Listener listener = ref.get();
      if (listener == null) continue;
      if (listener.packageName() == null || listener.packageName().equals(pkg.name())) {
        listener.changed(pkg, ctx);
      }
    }
  }

  public List getListeners() {
    List result = new ArrayList<>();
    for (Reference ref : listeners) {
      Listener l = ref.get();
      if (l != null) {
        result.add(l);
      }
    }
    return result;
  }

  public interface Listener {
    /** Name of the package or null to listen to all package changes */
    String packageName();

    /** fetch the package versions of class names */
    Map packageDetails();

    /** A callback when the package is updated */
    void changed(SolrPackageLoader.SolrPackage pkg, Ctx ctx);

    default MapWriter getPackageVersion(PluginInfo.ClassName cName) {
      return null;
    }

    class Ctx {
      private Map runLater;

      /**
       * If there are multiple packages to be updated and there are multiple listeners, This is
       * executed after all of the {@link Listener#changed(SolrPackageLoader.SolrPackage, Ctx)}
       * calls are invoked. The name is a unique identifier that can be used by consumers to avoid
       * duplicate If no deduplication is required, use null as the name
       */
      public void runLater(String name, Runnable runnable) {
        if (runLater == null) runLater = new LinkedHashMap<>();
        if (name == null) {
          name = runnable.getClass().getSimpleName() + "@" + runnable.hashCode();
        }
        runLater.put(name, runnable);
      }

      private void runLaterTasks(Consumer runnableExecutor) {
        if (runLater == null) return;
        for (Runnable r : runLater.values()) {
          runnableExecutor.accept(r);
        }
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy