mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
REPO-5110 readConfigAndReplace NPE on shutdown (#246)
Suppresses reading of new config if the system is shutting down.
This commit is contained in:
@@ -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
|
||||
*/
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
69
src/main/java/org/alfresco/util/ShutdownIndicator.java
Normal file
69
src/main/java/org/alfresco/util/ShutdownIndicator.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user