PluginManager.java
- /*
- * GovWay - A customizable API Gateway
- * https://govway.org
- *
- * Copyright (c) 2005-2025 Link.it srl (https://link.it).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3, as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- package org.openspcoop2.monitor.engine.dynamic;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Date;
- import java.util.HashMap;
- import java.util.List;
- import org.apache.commons.lang.StringUtils;
- import org.openspcoop2.core.commons.CoreException;
- import org.openspcoop2.core.config.RegistroPlugin;
- import org.openspcoop2.core.config.RegistroPlugins;
- import org.openspcoop2.core.config.constants.StatoFunzionalita;
- import org.openspcoop2.generic_project.exception.NotFoundException;
- import org.openspcoop2.core.plugins.constants.TipoPlugin;
- import org.openspcoop2.utils.SemaphoreLock;
- import org.openspcoop2.utils.UtilsException;
- import org.openspcoop2.utils.date.DateManager;
- import org.slf4j.Logger;
- /**
- * PluginManager
- *
- * @author Poli Andrea (apoli@link.it)
- * @author $Author$
- * @version $Rev$, $Date$
- */
- public class PluginManager {
- private IRegistroPluginsReader registroPluginsReader;
-
- private Date expireDate;
- private int expireSeconds;
- private final org.openspcoop2.utils.Semaphore lockExpire = new org.openspcoop2.utils.Semaphore("PluginManager-expire");
-
- private PluginsImage pluginsImage = new PluginsImage();
- private PluginsImage pluginsImageSwitchOld = null;
- private final org.openspcoop2.utils.Semaphore lockImage = new org.openspcoop2.utils.Semaphore("PluginManager-image");
- protected PluginManager(IRegistroPluginsReader registroPluginsReader, int expireSeconds) {
- this.registroPluginsReader = registroPluginsReader;
- this.expireSeconds = expireSeconds;
- }
- private void checkUpdate(Logger log) {
- try {
- Date nowDate = DateManager.getDate();
- if(this.expireDate==null || nowDate.after(this.expireDate)) {
- this.update(log, nowDate);
- }
- }catch(Exception t) {
- log.error("Update plugin image failed: "+t.getMessage(),t);
- }
- }
- public void updateFromConsoleConfig(Logger log) {
- try {
- if(this.expireDate!=null) {
- Date expired = new Date(this.expireDate.getTime()+1);
- this.update(log, expired);
- }
- }catch(Exception t) {
- log.error("Update plugin image failed: "+t.getMessage(),t);
- }
- }
- private void update(Logger log, Date nowDate) throws UtilsException, CoreException {
-
- boolean update = false;
-
- SemaphoreLock lock = this.lockExpire.acquire("updateExpireDate");
- try {
- if(this.expireDate==null || nowDate.after(this.expireDate)) {
- this.expireDate = new Date(nowDate.getTime()+(this.expireSeconds*1000));
- update = true;
- // l'aggiornamento effettivo lo faccio fuori dal synchronized per non bloccare le chiamate a _findClass, intanto che l'immagine viene aggiornata
- // gli altri thread che entrano in questo metodo trovano la lor nowDate inferiore ad expireDate
- }
- }finally {
- this.lockExpire.release(lock, "updateExpireDate");
- }
-
- if(update) {
- RegistroPlugins registro = null;
- try {
- registro = this.registroPluginsReader.getRegistroPlugins();
- }catch (NotFoundException notFound) {
- log.debug(notFound.getMessage(),notFound);
- }
- this.update(log, registro);
- }
- }
-
- private void update(Logger log, RegistroPlugins pluginsParam) throws UtilsException {
-
- SemaphoreLock lock = this.lockImage.acquire("update");
- try {
-
- RegistroPlugins plugins = null;
- if(pluginsParam!=null) {
- plugins = pluginsParam;
- }
- else {
- plugins = new RegistroPlugins();
- }
-
- // verifico prima quelli da eliminare
- List<String> pluginDaEliminare = new ArrayList<>();
- if(this.pluginsImage!=null && !this.pluginsImage.plugins.isEmpty()) {
- for (String pluginName : this.pluginsImage.plugins.keySet()) {
- boolean found = false;
- if(plugins.sizePluginList()>0) {
- for (RegistroPlugin pluginNew : plugins.getPluginList()) {
- if(pluginNew.getNome().equals(pluginName)) {
- found = true;
- break;
- }
- }
- }
- if(!found) {
- pluginDaEliminare.add(pluginName);
- }
- }
- }
-
- // Nuova immagine
- PluginsImage newImage = null;
- if(plugins.sizePluginList()>0) {
- newImage = new PluginsImage();
- HashMap<String, String> mapPosizioniToNomi = new HashMap<>();
- for (RegistroPlugin pluginNew : plugins.getPluginList()) {
-
- if(!StatoFunzionalita.ABILITATO.equals(pluginNew.getStato())) {
- continue;
- }
- if(pluginNew.sizeArchivioList()<=0) {
- continue; // vuoto
- }
-
- String posPad = StringUtils.leftPad(pluginNew.getPosizione()+"", 10);
- mapPosizioniToNomi.put(posPad, pluginNew.getNome());
-
- // check se esiste
- if(this.pluginsImage!=null && this.pluginsImage.plugins.containsKey(pluginNew.getNome())) {
-
- // check se e' stato aggiornato
- Plugin active = this.pluginsImage.plugins.get(pluginNew.getNome());
- if(pluginNew.getData().after(active.getDate())) {
-
- // Da aggiornare
-
- pluginDaEliminare.add(pluginNew.getNome()); // elimino nella vecchia immagine
-
- Plugin pluginNewInstance = null;
- try {
- pluginNewInstance = new Plugin(pluginNew);
- }catch(Exception e) {
- log.error("Errore durante l'istanziazione del plugin '"+pluginNew.getNome()+"': "+e.getMessage(),e);
- }
- if(pluginNewInstance!=null) {
- newImage.plugins.put(pluginNew.getNome(), pluginNewInstance);
- }
-
- }
- else {
-
- // non modificato
- newImage.plugins.put(pluginNew.getNome(), active);
-
- }
-
- }
- else {
- Plugin pluginNewInstance = null;
- try {
- pluginNewInstance = new Plugin(pluginNew);
- }catch(Exception e) {
- log.error("Errore durante l'istanziazione del plugin '"+pluginNew.getNome()+"': "+e.getMessage(),e);
- }
- if(pluginNewInstance!=null) {
- newImage.plugins.put(pluginNew.getNome(), pluginNewInstance);
- }
- }
-
- }
-
-
- // ordino per posizione
- if(!mapPosizioniToNomi.isEmpty()) {
- List<String> posizioni = new ArrayList<>();
- posizioni.addAll(mapPosizioniToNomi.keySet());
- Collections.sort(posizioni);
- for (String pos : posizioni) {
- newImage.pluginsActiveOrdered.add(mapPosizioniToNomi.get(pos));
- }
- }
- }
-
- // effettuo switch
- this.pluginsImageSwitchOld = this.pluginsImage;
- this.pluginsImage = newImage;
-
- // Effettuo la chiusura di quelli da eliminare
- if(!pluginDaEliminare.isEmpty()) {
- for (String pluginName : pluginDaEliminare) {
- try {
- this.pluginsImageSwitchOld.plugins.get(pluginName).close();
- }catch(Exception t) {
- // ignore
- }
- }
- }
- this.pluginsImageSwitchOld = null;
-
- }finally {
- this.lockImage.release(lock, "update");
- }
-
- }
-
- public void close() {
-
- // Chiusura di tutti
- SemaphoreLock lock = this.lockImage.acquireThrowRuntime("close");
- try {
-
- if(this.pluginsImage!=null && this.pluginsImage.plugins.size()>0) {
- for (Plugin plugin : this.pluginsImage.plugins.values()) {
- try {
- plugin.close();
- }catch(Exception t) {
- // close
- }
- }
- }
-
- if(this.pluginsImageSwitchOld!=null &&
- this.pluginsImageSwitchOld.plugins.size()>0) {
- for (Plugin plugin : this.pluginsImageSwitchOld.plugins.values()) {
- try {
- plugin.close();
- }catch(Exception t) {
- // close
- }
- }
- }
-
- }finally {
- this.lockImage.release(lock, "close");
- }
- }
-
- public Class<?> findClass(Logger log, TipoPlugin tipoClasseDaRicercare, String className) throws ClassNotFoundException {
- return this.findClassEngine(log, tipoClasseDaRicercare, null, className, true);
- }
- public Class<?> findClass(Logger log, TipoPlugin tipoClasseDaRicercare, String className, boolean searchDefaultClassLoader) throws ClassNotFoundException {
- return this.findClassEngine(log, tipoClasseDaRicercare, null, className, searchDefaultClassLoader);
- }
-
- public Class<?> findClass(Logger log, String tipoClasseDaRicercare, String className) throws ClassNotFoundException {
- return this.findClassEngine(log, null, tipoClasseDaRicercare, className, true);
- }
- public Class<?> findClass(Logger log, String tipoClasseDaRicercare, String className, boolean searchDefaultClassLoader) throws ClassNotFoundException {
- return this.findClassEngine(log, null, tipoClasseDaRicercare, className, searchDefaultClassLoader);
- }
-
-
-
- private Class<?> findClassEngine(Logger log, TipoPlugin tipoClasseDaRicercare,String tipoClasseCustomDaRicercare, String className, boolean searchDefaultClassLoader) throws ClassNotFoundException {
- checkUpdate(log);
-
- // Se server gestire tramite una cache
- // Se abilitato prima cerco sempre nel classloader attuale.
- // Il classloader dinamico verrà utilizzato SOLAMENTE se il tipo non viene risolto prima tramite i meccanismi standard.
- // Questo behaviour permette di avere poi un synchronized sul semaforo del classloader dinamico solamente quando serve davvero,
- // visto che il caricamento dinamico delle classi è molto diffuso all'interno dell'architettura di GovWay.
- ClassNotFoundException notFound = null;
- if(searchDefaultClassLoader) {
- try {
- return Class.forName(className);
- }catch(ClassNotFoundException e) {
- notFound = e;
- }
- }
-
- if(this.pluginsImage!=null) { // potrebbe essere disabilitato
- PluginsImage image = this.pluginsImage; // lo assegno, in modo che se avviene un update, cambia il riferimento
-
- if(!image.pluginsActiveOrdered.isEmpty()) {
- Class<?> c = findClassEngine(image, tipoClasseDaRicercare, tipoClasseCustomDaRicercare, className);
- if(c!=null) {
- return c;
- }
- }
- }
-
- if(notFound!=null) {
- throw notFound;
- }
- return null;
- }
- private Class<?> findClassEngine(PluginsImage image, TipoPlugin tipoClasseDaRicercare, String tipoClasseCustomDaRicercare, String className){
- List<String> listPluginsActiveOrdered = image.pluginsActiveOrdered;
- for (String pluginName : listPluginsActiveOrdered) {
-
- Plugin plugin = image.plugins.get(pluginName);
- if(plugin!=null) {
- Class<?> c = findClassEngineByPlugin(plugin, tipoClasseDaRicercare, tipoClasseCustomDaRicercare, className);
- if(c!=null) {
- return c;
- }
- }
-
- }
- return null;
- }
- private Class<?> findClassEngineByPlugin(Plugin plugin, TipoPlugin tipoClasseDaRicercare, String tipoClasseCustomDaRicercare, String className){
- ClassLoader classLoader = null;
- if(tipoClasseDaRicercare!=null) {
- classLoader = plugin.getClassLoader(tipoClasseDaRicercare);
- }else {
- classLoader = plugin.getClassLoader(tipoClasseCustomDaRicercare);
- }
- if(classLoader!=null) {
- Class<?> c = null;
- try {
- c = classLoader.loadClass(className);
- }catch(ClassNotFoundException cNotFound) {
- // ignore
- }
- if(c!=null) {
- return c;
- }
- }
- return null;
- }
- }
- class PluginsImage {
-
- HashMap<String, Plugin> plugins = new HashMap<>();
- List<String> pluginsActiveOrdered = new ArrayList<>();
-
- }