REPO-5110 readConfigAndReplace NPE on shutdown (#246)

Suppresses reading of new config if the system is shutting down.
This commit is contained in:
Alan Davis
2020-05-01 13:54:52 +01:00
committed by GitHub
parent 19629b85a3
commit e0317d681b
3 changed files with 112 additions and 18 deletions

View File

@@ -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
*/

View File

@@ -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<Data>
protected Data data;
private ThreadLocal<Data> 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<Data>
*/
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;
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
* #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<ApplicationContextEvent>
{
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;
}
}
}
}