Skip to content

Commit f0c7f32

Browse files
authored
Merge pull request #1377 from GeoWebCache/backport-1375-to-1.26.x
[Backport 1.26.x] Support loading the xml configuration from a read-only filesystem
2 parents 4984457 + 4f995ba commit f0c7f32

File tree

3 files changed

+90
-16
lines changed

3 files changed

+90
-16
lines changed

geowebcache/core/src/main/java/org/geowebcache/config/XMLConfiguration.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -791,14 +791,15 @@ private static Node applyTransform(Node oldRootNode, String xslFilename) {
791791

792792
@Override
793793
public void afterPropertiesSet() throws GeoWebCacheException {
794-
794+
if (!resourceProvider.hasInput()) {
795+
throw new ConfigurationException(
796+
String.format("The configuration resource provider is unable to provide a configuration file"));
797+
}
795798
if (gridSetBroker == null) {
796799
throw new IllegalStateException("GridSetBroker has not been set");
797800
}
798801

799-
if (resourceProvider.hasInput()) {
800-
this.setGwcConfig(loadConfiguration());
801-
}
802+
this.setGwcConfig(loadConfiguration());
802803

803804
log.config("Initializing GridSets from " + getIdentifier());
804805

geowebcache/core/src/main/java/org/geowebcache/config/XMLFileResourceProvider.java

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.geowebcache.util.ApplicationContextProvider;
3434
import org.geowebcache.util.GWCVars;
3535
import org.springframework.context.ApplicationContext;
36+
import org.springframework.lang.NonNull;
3637
import org.springframework.web.context.WebApplicationContext;
3738

3839
/** Default implementation of ConfigurationResourceProvider that uses the file system. */
@@ -49,9 +50,11 @@ public class XMLFileResourceProvider implements ConfigurationResourceProvider {
4950
private final WebApplicationContext context;
5051

5152
/** Location of the configuration file */
53+
@NonNull
5254
private final File configDirectory;
5355

5456
/** Name of the configuration file */
57+
@NonNull
5558
private final String configFileName;
5659

5760
private String templateLocation;
@@ -135,11 +138,27 @@ public XMLFileResourceProvider(
135138
this(configFileName, appCtx, getConfigDirVar(appCtx), storageDirFinder);
136139
}
137140

141+
/**
142+
* {@inheritDoc}
143+
*
144+
* <p>If the configuration file doesn't exist and {@link #hasInput() == true}, the file will be first created from
145+
* the {@link #setTemplate(String) template}
146+
*
147+
* @throws IOException if the file can't be created or copied from the template
148+
*/
138149
@Override
139150
public InputStream in() throws IOException {
140151
return new FileInputStream(findOrCreateConfFile());
141152
}
142153

154+
/**
155+
* {@inheritDoc}
156+
*
157+
* <p>If the configuration file doesn't exist and {@link #hasOutput() == true}, the file will be first created from
158+
* the {@link #setTemplate(String) template}
159+
*
160+
* @throws IOException if the file can't be created or copied from the template
161+
*/
143162
@Override
144163
public OutputStream out() throws IOException {
145164
return new FileOutputStream(findOrCreateConfFile());
@@ -165,22 +184,13 @@ public void setTemplate(final String templateLocation) {
165184
}
166185

167186
private File findConfigFile() throws IOException {
168-
if (null == configDirectory) {
169-
throw new IllegalStateException();
170-
}
171187

172188
if (!configDirectory.exists() && !configDirectory.mkdirs()) {
173189
throw new IOException("TileLayerConfiguration directory does not exist and cannot be created: '"
174190
+ configDirectory.getAbsolutePath()
175191
+ "'");
176192
}
177-
if (!configDirectory.canWrite()) {
178-
throw new IOException(
179-
"TileLayerConfiguration directory is not writable: '" + configDirectory.getAbsolutePath() + "'");
180-
}
181-
182-
File xmlFile = new File(configDirectory, configFileName);
183-
return xmlFile;
193+
return new File(configDirectory, configFileName);
184194
}
185195

186196
@Override
@@ -200,6 +210,11 @@ private File findOrCreateConfFile() throws IOException {
200210
if (xmlFile.exists()) {
201211
log.config("Found configuration file in " + configDirectory.getAbsolutePath());
202212
} else if (templateLocation != null) {
213+
if (!configDirectory.canWrite()) {
214+
throw new IOException("TileLayerConfiguration directory is not writable: '"
215+
+ configDirectory.getAbsolutePath() + "'");
216+
}
217+
203218
log.warning("Found no configuration file in config directory, will create one at '"
204219
+ xmlFile.getAbsolutePath()
205220
+ "' from template "
@@ -249,17 +264,40 @@ private void backUpConfig(final File xmlFile) throws IOException {
249264
log.fine("Config backup done");
250265
}
251266

267+
/**
268+
* Determines if the config file exists and is readable, or doesn't exist but can be created.
269+
*
270+
* <p>Calling this method has no side effects. The target file either exists, or can be created throught the
271+
* {@link #setTemplate(String) template}, if a template has been set. In such case, it'll be created by either
272+
* {@link #in()} or {@link #out()}.
273+
*/
252274
@Override
253275
public boolean hasInput() {
254276
try {
255-
return findOrCreateConfFile().exists();
277+
File file = findConfigFile();
278+
return file.exists() || (templateLocation != null && configDirectory.canWrite());
256279
} catch (IOException e) {
280+
log.log(Level.WARNING, "Error obtaining config file", e);
257281
return false;
258282
}
259283
}
260284

285+
/**
286+
* Determines if the configuration can be {@link #out() written} to the {@link #getLocation() output file}.
287+
*
288+
* <p>Calling this method has no side effects. The target file may or may not exist. The target directory must be
289+
* writable, and so must the target file in case it does exist.
290+
*
291+
* @return {@code true} if the {@link #getLocation() configuration file} can be written to.
292+
*/
261293
@Override
262294
public boolean hasOutput() {
263-
return true;
295+
try {
296+
File file = findConfigFile();
297+
return configDirectory.canWrite() && (!file.exists() || file.canWrite());
298+
} catch (IOException e) {
299+
log.log(Level.WARNING, "Error obtaining config file", e);
300+
return false;
301+
}
264302
}
265303
}

geowebcache/core/src/test/java/org/geowebcache/config/XMLConfigurationTest.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static org.easymock.EasyMock.replay;
1919
import static org.hamcrest.MatcherAssert.assertThat;
2020
import static org.hamcrest.Matchers.containsInAnyOrder;
21+
import static org.hamcrest.Matchers.greaterThan;
2122
import static org.hamcrest.Matchers.is;
2223
import static org.hamcrest.Matchers.notNullValue;
2324
import static org.junit.Assert.assertArrayEquals;
@@ -27,13 +28,15 @@
2728
import static org.junit.Assert.assertNotNull;
2829
import static org.junit.Assert.assertNotSame;
2930
import static org.junit.Assert.assertSame;
31+
import static org.junit.Assert.assertThrows;
3032
import static org.junit.Assert.assertTrue;
3133
import static org.junit.Assert.fail;
3234
import static org.mockito.Mockito.mock;
3335
import static org.mockito.Mockito.when;
3436

3537
import java.io.File;
3638
import java.io.FileInputStream;
39+
import java.io.IOException;
3740
import java.net.URL;
3841
import java.util.ArrayList;
3942
import java.util.Arrays;
@@ -47,6 +50,7 @@
4750
import java.util.logging.Logger;
4851
import org.apache.commons.io.FileUtils;
4952
import org.geotools.util.logging.Logging;
53+
import org.geowebcache.GeoWebCacheException;
5054
import org.geowebcache.GeoWebCacheExtensions;
5155
import org.geowebcache.MockWepAppContextRule;
5256
import org.geowebcache.config.legends.LegendRawInfo;
@@ -64,6 +68,7 @@
6468
import org.geowebcache.layer.TileLayer;
6569
import org.geowebcache.layer.wms.WMSLayer;
6670
import org.geowebcache.util.TestUtils;
71+
import org.junit.Assume;
6772
import org.junit.Before;
6873
import org.junit.Rule;
6974
import org.junit.Test;
@@ -557,4 +562,34 @@ public void testWmtsCiteStrictComplianceIsActivated() throws Exception {
557562
// CITE strict compliance should be activated for WMTS
558563
assertThat(config.isWmtsCiteCompliant(), is(true));
559564
}
565+
566+
@Test
567+
public void loadFromReadOnlyDirectory() throws GeoWebCacheException {
568+
Assume.assumeTrue(
569+
"Ignore if setWritable(false) does not succeed, may happen on Windows", configDir.setWritable(false));
570+
assertThat(configFile.exists(), is(true));
571+
try {
572+
config = new XMLConfiguration(null, configDir.getAbsolutePath());
573+
config.setGridSetBroker(gridSetBroker);
574+
config.afterPropertiesSet();
575+
assertThat(config.getLayerCount(), is(greaterThan(0)));
576+
} finally {
577+
configDir.setWritable(true);
578+
}
579+
}
580+
581+
@Test
582+
public void loadFromEmptyReadOnlyDirectoryFails() throws GeoWebCacheException, IOException {
583+
File roEmptyDir = this.temp.newFolder();
584+
Assume.assumeTrue(
585+
"Ignore if setWritable(false) does not succeed, may happen on Windows", roEmptyDir.setWritable(false));
586+
try {
587+
config = new XMLConfiguration(null, roEmptyDir.getAbsolutePath());
588+
config.setGridSetBroker(gridSetBroker);
589+
590+
assertThrows(ConfigurationException.class, () -> config.afterPropertiesSet());
591+
} finally {
592+
roEmptyDir.setWritable(true);
593+
}
594+
}
560595
}

0 commit comments

Comments
 (0)