diff --git a/src/main/java/org/alfresco/repo/content/MimetypeMap.java b/src/main/java/org/alfresco/repo/content/MimetypeMap.java index dc804191f3..2b33e6eb5b 100644 --- a/src/main/java/org/alfresco/repo/content/MimetypeMap.java +++ b/src/main/java/org/alfresco/repo/content/MimetypeMap.java @@ -2,7 +2,7 @@ * #%L * Alfresco Data model classes * %% - * Copyright (C) 2005 - 2019 Alfresco Software Limited + * Copyright (C) 2005 - 2020 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -34,6 +34,7 @@ import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.util.ConfigFileFinder; import org.alfresco.util.ConfigScheduler; import org.alfresco.util.PropertyCheck; +import org.alfresco.util.ShutdownIndicator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.tika.config.TikaConfig; @@ -553,6 +554,11 @@ public class MimetypeMap implements MimetypeService this.initialAndOnErrorCronExpression = initialAndOnErrorCronExpression; } + public void setShutdownIndicator(ShutdownIndicator shutdownIndicator) + { + configScheduler.setShutdownIndicator(shutdownIndicator); + } + /** * Initialises the map using the configuration service provided */ diff --git a/src/main/java/org/alfresco/util/ConfigScheduler.java b/src/main/java/org/alfresco/util/ConfigScheduler.java index fbde66a7df..35bd8c4bb7 100644 --- a/src/main/java/org/alfresco/util/ConfigScheduler.java +++ b/src/main/java/org/alfresco/util/ConfigScheduler.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2019 Alfresco Software Limited + * Copyright (C) 2005 - 2020 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -83,11 +83,23 @@ public abstract class ConfigScheduler protected Data data; private ThreadLocal threadData = ThreadLocal.withInitial(() -> data); + private ShutdownIndicator shutdownIndicator; + public ConfigScheduler(Object client) { jobName = client.getClass().getName()+"Job@"+Integer.toHexString(System.identityHashCode(client)); } + public void setShutdownIndicator(ShutdownIndicator shutdownIndicator) + { + this.shutdownIndicator = shutdownIndicator; + } + + private boolean shuttingDown() + { + return shutdownIndicator != null && shutdownIndicator.isShuttingDown(); + } + public abstract boolean readConfig() throws IOException; public abstract Data createData(); @@ -198,24 +210,31 @@ public abstract class ConfigScheduler */ public boolean readConfigAndReplace(boolean scheduledRead) { - boolean successReadingConfig; - log.debug((scheduledRead ? "Scheduled" : "Unscheduled")+" config read started"); - Data data = getData(); - try + // Config replacement is not done during shutdown. We cannot even log it without generating an INFO message. + + // If shutting down, we return true indicating there were not problems, as that will result in the next + // scheduled job taking place later where as false would switch to a more frequent retry sequence. + boolean successReadingConfig = true; + if (!shuttingDown()) { - Data newData = createData(); - threadData.set(newData); - successReadingConfig = readConfig(); - data = newData; - log.debug("Config read finished "+data+ - (successReadingConfig ? "" : ". Config replaced but there were problems")+"\n"); + log.debug((scheduledRead ? "Scheduled" : "Unscheduled") + " config read started"); + Data data = getData(); + try + { + Data newData = createData(); + threadData.set(newData); + successReadingConfig = readConfig(); + data = newData; + log.debug("Config read finished " + data + + (successReadingConfig ? "" : ". Config replaced but there were problems") + "\n"); + } + catch (Exception e) + { + successReadingConfig = false; + log.error("Config read failed. " + e.getMessage(), e); + } + setData(data); } - catch (Exception e) - { - successReadingConfig = false; - log.error("Config read failed. "+e.getMessage(), e); - } - setData(data); return successReadingConfig; } diff --git a/src/main/java/org/alfresco/util/ShutdownIndicator.java b/src/main/java/org/alfresco/util/ShutdownIndicator.java new file mode 100644 index 0000000000..e9b33f0561 --- /dev/null +++ b/src/main/java/org/alfresco/util/ShutdownIndicator.java @@ -0,0 +1,69 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2020 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.util; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ApplicationContextEvent; +import org.springframework.context.event.ContextClosedEvent; + +/** + * Listens to ApplicationEvents to provide a simple {@link #isShuttingDown()} method, so callers don't need to be + * Spring beans or listen to these events themselves. Intended for use by code that wishes to avoid ERROR log messages + * on shutdown. + * + * @author adavis + */ +public class ShutdownIndicator implements ApplicationContextAware, ApplicationListener +{ + private boolean shuttingDown; + private ApplicationContext applicationContext; + + public synchronized boolean isShuttingDown() + { + return shuttingDown; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + this.applicationContext = applicationContext; + } + + @Override + public void onApplicationEvent(ApplicationContextEvent event) + { + if (event instanceof ContextClosedEvent && event.getSource() == applicationContext) + { + synchronized (this) + { + shuttingDown = true; + } + } + } +}