diff --git a/pom.xml b/pom.xml
index cbdc15a..8097b3f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
WebServiceShell
edu.iris
webserviceshell
- 2.4.8-SNAPSHOT
+ 2.4.9
jar
http://iris.edu
diff --git a/src/main/java/edu/iris/wss/framework/AppConfigurator.java b/src/main/java/edu/iris/wss/framework/AppConfigurator.java
index ff1ec1d..bfc472b 100644
--- a/src/main/java/edu/iris/wss/framework/AppConfigurator.java
+++ b/src/main/java/edu/iris/wss/framework/AppConfigurator.java
@@ -24,10 +24,13 @@
import edu.iris.wss.provider.IrisProcessMarker;
import edu.iris.wss.provider.IrisProcessor;
import edu.iris.wss.provider.IrisSingleton;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
@@ -51,11 +54,11 @@
public class AppConfigurator {
public static final Logger logger = Logger.getLogger(AppConfigurator.class);
- public static final String wssVersion = "2.4.8-SNAPSHOT";
+ public static final String wssVersion = "2.4.9";
public static final String wssDigestRealmnameSignature = "wss.digest.realmname";
- private static final String DEFAULT_SERVICE_FILE_NAME = "META-INF/service.cfg";
+ protected static final String DEFAULT_SERVICE_FILE_NAME = "META-INF/service.cfg";
public static final String SERVICE_CFG_NAME_SUFFIX = "-service.cfg";
public static final String ENDPOINT_TO_PROPERTIES_DELIMITER = ".";
@@ -634,7 +637,8 @@ public static Properties loadPropertiesFile(String configBase,
+ configFileName);
try {
- configurationProps.load(new FileInputStream(configFileName));
+ InputStream inStream = new FileInputStream(configFileName);
+ loadWithBackslashFix(configurationProps, inStream);
userConfig = true;
} catch (IOException ex) {
logger.warn("***** could not read cfg file: " + configFileName);
@@ -660,7 +664,7 @@ public static Properties loadPropertiesFile(String configBase,
logger.info("Attempting to load default application"
+ " configuration from here: " + defaultCfgName);
- configurationProps.load(inStream);
+ loadWithBackslashFix(configurationProps, inStream);
logger.info("Default application properties loaded, file: "
+ defaultCfgName);
@@ -669,6 +673,36 @@ public static Properties loadPropertiesFile(String configBase,
return configurationProps;
}
+ public static void loadWithBackslashFix(Properties prop, InputStream is)
+ throws IOException {
+ // before loading check for any character after any backslash
+ // and before the end of line, and remove it
+ StringBuilder sb = new StringBuilder();
+ InputStreamReader isr = new InputStreamReader(is);
+ BufferedReader br = new BufferedReader(isr);
+ String readLine = "";
+ while ((readLine = br.readLine()) != null) {
+ int idxback = readLine.indexOf("\\");
+ int idxEOL = readLine.length() - 1;
+
+ if(idxback > -1) {
+ if (idxEOL > idxback) {
+ // fixit
+ readLine = readLine.substring(0,idxback+1);
+ int fidxback = readLine.indexOf("\\");
+ int fidxEOL = readLine.length() - 1;
+ }
+ }
+ // put back the EOL since readLine removed it
+ sb.append(readLine).append("\n");
+ }
+
+ ByteArrayInputStream sbis = new ByteArrayInputStream(
+ sb.toString().getBytes("UTF-8"));
+
+ prop.load(sbis);
+ }
+
public void loadConfigurationParameters(Properties inputProps)
throws Exception {
diff --git a/src/test/java/edu/iris/wss/framework/AppConfig_loadPropertiesFileTest.java b/src/test/java/edu/iris/wss/framework/AppConfig_loadPropertiesFileTest.java
new file mode 100644
index 0000000..d5baafd
--- /dev/null
+++ b/src/test/java/edu/iris/wss/framework/AppConfig_loadPropertiesFileTest.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 2018 IRIS DMC supported by the National Science Foundation.
+ *
+ * This file is part of the Web Service Shell (WSS).
+ *
+ * The WSS 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.
+ *
+ * The WSS 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.
+ *
+ * A copy of the GNU Lesser General Public License is available at
+ * .
+ ******************************************************************************/
+
+package edu.iris.wss.framework;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+import java.util.Properties;
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author mike
+ */
+public class AppConfig_loadPropertiesFileTest {
+ public static final String THIS_CLASS_NAME = AppConfig_loadPropertiesFileTest.class.getSimpleName();
+ public static final Logger LOGGER = Logger.getLogger(THIS_CLASS_NAME);
+
+ private static final String MEDIA_PARAM = "myFORMTname";
+
+ private static final String SERVICE_CONTEXT = "/loadproptest";
+ private static final String ENDPOINT_NAME = "process";
+
+ private String okFN, notokFN;
+
+ public AppConfig_loadPropertiesFileTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ // define WSS config dir for this test
+ System.setProperty(Util.WSS_OS_CONFIG_DIR,
+ "target"
+ + File.separator + "test-classes"
+ + File.separator + THIS_CLASS_NAME);
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ String className = "edu.iris.wss.endpoints.DummyNameEndpoint";
+
+ String flaw = "";
+ okFN = FileCreaterHelper.createFileInWssFolder(SERVICE_CONTEXT,
+ "-ok"+AppConfigurator.SERVICE_CFG_NAME_SUFFIX,
+ createServiceCfgStr(ENDPOINT_NAME, className, flaw),
+ false);
+
+ // insert a hard-to-see problem after a backslash in a list
+ flaw = " ";
+ notokFN = FileCreaterHelper.createFileInWssFolder(SERVICE_CONTEXT,
+ "-notok"+AppConfigurator.SERVICE_CFG_NAME_SUFFIX,
+ createServiceCfgStr(ENDPOINT_NAME, className, flaw),
+ false);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testload_withFlaw() throws Exception {
+
+ // file read from https://www.mkyong.com/java/java-read-a-text-file-line-by-line/
+ RandomAccessFile okfile = new RandomAccessFile(okFN, "r");
+ FileChannel okchannel = okfile.getChannel();
+ RandomAccessFile notokfile = new RandomAccessFile(notokFN, "r");
+ FileChannel notokchannel = notokfile.getChannel();
+
+ // the files should be different, the not ok file should have
+ // a flaw string after a backslass
+ assertEquals(true, okchannel.size() != notokchannel.size());
+
+ okchannel.close();
+ okfile.close();
+ notokchannel.close();
+ notokfile.close();
+
+ Properties props_ok =
+ AppConfigurator.loadPropertiesFile(SERVICE_CONTEXT.substring(1),
+ this.getClass(), "-ok"+AppConfigurator.SERVICE_CFG_NAME_SUFFIX,
+ AppConfigurator.DEFAULT_SERVICE_FILE_NAME);
+
+ Properties props_notok =
+ AppConfigurator.loadPropertiesFile(SERVICE_CONTEXT.substring(1),
+ this.getClass(), "-notok"+AppConfigurator.SERVICE_CFG_NAME_SUFFIX,
+ AppConfigurator.DEFAULT_SERVICE_FILE_NAME);
+
+ // the properties shoud be the same after the fix is applied when the
+ // properties are loaded
+ assertEquals(true, props_ok.keySet().equals(props_notok.keySet()));
+ }
+
+ @Test
+ public void testload_withNoBase() throws Exception {
+ String testDefaultResource = "META-INF/service_withFlaw.cfg";
+
+ InputStream inStream = this.getClass().getClassLoader()
+ .getResourceAsStream(testDefaultResource);
+
+ Properties props_notok = new Properties();
+ props_notok.load(inStream);
+
+ // this loads the default cfg when it can't find the primary
+ Properties props_ok =
+ AppConfigurator.loadPropertiesFile("wrongbase_force_to_default",
+ this.getClass(), "-ok"+AppConfigurator.SERVICE_CFG_NAME_SUFFIX,
+ testDefaultResource);
+
+ // the properties should be different after the fixed load
+ assertEquals(false, props_ok.keySet().equals(props_notok.keySet()));
+ }
+
+ private static String createServiceCfgStr(String endpointName,
+ String endpointClass, String flaw) {
+ String s = String.join("\n",
+ "# ---------------- globals",
+ "",
+ "appName=" + THIS_CLASS_NAME,
+ "version=0.1",
+ "",
+ "corsEnabled=false",
+ "",
+ "# LOG4J or JMS",
+ "loggingMethod=LOG4J",
+ "",
+ "# If present, an instance of the singleton class will be created at application start",
+ "singletonClassName=edu.iris.wss.framework.UnitTestDestroySingleton",
+ "",
+ "# ---------------- endpoints",
+ "",
+ endpointName + ".endpointClassName=" + endpointClass,
+ endpointName + ".usageLog",
+ endpointName + ".postEnabled=true",
+ endpointName + ".logMiniseedExtents = false",
+ endpointName + ".use404For204=false",
+ endpointName + ".formatTypes = \\",
+ " text: text/plain,\\",
+ " json: application/json, \\" + flaw,
+ " miniseed: application/vnd.fdsn.mseed, \\",
+ " geocsv: text/plain",
+ endpointName + ".mediaParameter = " + MEDIA_PARAM,
+ ""
+ );
+
+ return s;
+ }
+}
diff --git a/src/test/resources/META-INF/service_withFlaw.cfg b/src/test/resources/META-INF/service_withFlaw.cfg
new file mode 100644
index 0000000..6b32a1b
--- /dev/null
+++ b/src/test/resources/META-INF/service_withFlaw.cfg
@@ -0,0 +1,59 @@
+# ---------------- globals
+
+appName=dummy-service
+version=dummy-version-2.x
+
+# CORS is enabled by default, set to false to disable CORS processing
+##corsEnabled=false
+
+# a URL providing information about the application, documentation on usage, etc.
+##rootServiceDoc=http://service.iris.edu/
+rootServiceDoc=file:///nofolder/nofolder/nodocfile.html
+
+# LOG4J or JMS
+loggingMethod=LOG4J
+
+# the default is 60 seconds - time delay between SIGTERM until SIGKILL on command line processes
+##sigkillDelay=30
+
+# If present, an instance of the singleton class will be created at application start
+##singletonClassName=edu.iris.wss.provider.TestSingleton
+
+# ---------------- endpoints
+
+# may be a user class that extends IrisProcessor
+# by default, set to s set to edu.iris.wss.endpoints.CmdProcessor
+# can use edu.iris.wss.endpoints.ProxyResource to return content
+dummyEP.endpointClassName=edu.iris.wss.endpoints.CmdProcessor
+
+dummyEP.handlerProgram=/somefolder/somefolder/some_handler.sh
+
+# Timeout in seconds for command line processes
+dummyEP.handlerTimeout=40
+
+# A valid folder with write access for command line processes
+dummyEP.handlerWorkingDirectory=/tmp
+
+# usageLog is true by default, set this to false to disable usage logging
+##dummyEP.usageLog=false
+
+dummyEP.formatTypes = \
+ miniseed: application/vnd.fdsn.mseed, \
+ mseed: application/vnd.fdsn.mseed, \
+ json: application/json, \
+ geocsv: text/csv, \zzzpy
+ text: text/plain,\
+ texttree: text/plain,\
+ xml: application/xml
+
+# false by default, true enables POST processing
+dummyEP.postEnabled=true
+
+# false by default, enables additional miniseed processing and logging
+##dummyEP.logMiniseedExtents=true
+
+# false by default, enable this to return HTTP 404 in lieu of 204, NO CONTENT
+dummyEP.use404For204=true
+
+# required when endpointClassName is set to edu.iris.wss.endpoints.ProxyResource
+##dummyEP.proxyURL=http://geows.ds.iris.edu/geows-uf/v2/intermagnet-2-swagger.json
\ No newline at end of file