diff --git a/pom.xml b/pom.xml index 30844d370..2db0ef6e9 100644 --- a/pom.xml +++ b/pom.xml @@ -14,6 +14,7 @@ Program (CITE). http://opengeospatial.github.io/teamengine/ + 2006 Apache License, Version 2.0 @@ -574,6 +575,34 @@ + + license + + + + org.codehaus.mojo + license-maven-plugin + 2.4.0 + + + first + + update-file-header + + process-sources + + apache_v2 + + src/main/java + src/main/resources + + + + + + + + diff --git a/teamengine-core/src/main/java/com/occamlab/te/CtlEarlReporter.java b/teamengine-core/src/main/java/com/occamlab/te/CtlEarlReporter.java index d9127487a..4542baf3c 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/CtlEarlReporter.java +++ b/teamengine-core/src/main/java/com/occamlab/te/CtlEarlReporter.java @@ -12,6 +12,26 @@ package com.occamlab.te; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -665,4 +685,4 @@ public TestInfo(String assertion, String testName, int result, boolean isConform } -} \ No newline at end of file +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/CtlErrorHandler.java b/teamengine-core/src/main/java/com/occamlab/te/CtlErrorHandler.java index d03959095..7aad4deaf 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/CtlErrorHandler.java +++ b/teamengine-core/src/main/java/com/occamlab/te/CtlErrorHandler.java @@ -1,58 +1,78 @@ -/**************************************************************************** - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): No additional contributors to date - - ****************************************************************************/ -package com.occamlab.te; - -import org.xml.sax.ErrorHandler; -import org.xml.sax.SAXParseException; - -/** - * Validation error handler that accumulates the total number of error and warning - * notifications received. - * - */ -public class CtlErrorHandler implements ErrorHandler { - - int ErrorCount = 0; - - int WarningCount = 0; - - void error(String type, SAXParseException e) { - System.err.println(type + " at line " + e.getLineNumber() + ", column " + e.getColumnNumber() + " of " - + e.getSystemId() + ":"); - System.err.println(" " + e.getMessage()); - } - - public int getErrorCount() { - return ErrorCount; - } - - public int getWarningCount() { - return WarningCount; - } - - public void error(SAXParseException exception) { - error("Validation error", exception); - ErrorCount++; - } - - public void fatalError(SAXParseException exception) { - error("Fatal validation error", exception); - ErrorCount++; - } - - public void warning(SAXParseException exception) { - error("Validation warning", exception); - WarningCount++; - } - -} +/**************************************************************************** + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): No additional contributors to date + + ****************************************************************************/ +package com.occamlab.te; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXParseException; + +/** + * Validation error handler that accumulates the total number of error and warning + * notifications received. + * + */ +public class CtlErrorHandler implements ErrorHandler { + + int ErrorCount = 0; + + int WarningCount = 0; + + void error(String type, SAXParseException e) { + System.err.println(type + " at line " + e.getLineNumber() + ", column " + e.getColumnNumber() + " of " + + e.getSystemId() + ":"); + System.err.println(" " + e.getMessage()); + } + + public int getErrorCount() { + return ErrorCount; + } + + public int getWarningCount() { + return WarningCount; + } + + public void error(SAXParseException exception) { + error("Validation error", exception); + ErrorCount++; + } + + public void fatalError(SAXParseException exception) { + error("Fatal validation error", exception); + ErrorCount++; + } + + public void warning(SAXParseException exception) { + error("Validation warning", exception); + WarningCount++; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/Engine.java b/teamengine-core/src/main/java/com/occamlab/te/Engine.java index 8cd089451..1d270714d 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/Engine.java +++ b/teamengine-core/src/main/java/com/occamlab/te/Engine.java @@ -1,236 +1,256 @@ -/* - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): - C. Heazel (WiSC): Applied mods to address Fortify issues - - */ - -package com.occamlab.te; - -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - -import net.sf.saxon.Configuration; -import net.sf.saxon.functions.FunctionLibraryList; -import net.sf.saxon.s9api.DocumentBuilder; -import net.sf.saxon.s9api.Processor; -import net.sf.saxon.s9api.SaxonApiException; -import net.sf.saxon.s9api.XsltCompiler; -import net.sf.saxon.s9api.XsltExecutable; - -import com.occamlab.te.index.FunctionEntry; -import com.occamlab.te.index.Index; -import com.occamlab.te.index.TemplateEntry; -import com.occamlab.te.index.TestEntry; -import com.occamlab.te.saxon.TEFunctionLibrary; - -public class Engine { - - int cacheSize = 50; - - Processor processor = null; - - XsltCompiler compiler = null; - - DocumentBuilder builder = null; - - TeErrorListener errorListener = null; - - XsltExecutable formExecutable = null; - - // Map of loaded executables, ordered by access order - public Map loadedExecutables = Collections - .synchronizedMap(new LinkedHashMap<>(256, 0.75f, true)); - - public Map classLoaders; - - public Engine(Index index, String sourcesName, TEClassLoader cl) throws Exception { - this(); - ArrayList indexes = new ArrayList<>(); - indexes.add(index); - classLoaders = new HashMap<>(); - classLoaders.put(sourcesName, cl); - addFunctionLibrary(indexes); - } - - public Engine(Collection indexes, Map classLoaders, int cacheSize) throws Exception { - this(); - this.classLoaders = classLoaders; - if (cacheSize > 0) { - this.cacheSize = cacheSize; - } - addFunctionLibrary(indexes); - } - - public Engine() throws Exception { - String s = System.getProperty("te.cacheSize"); - if (s != null) { - cacheSize = Integer.parseInt(s); - } - - // Create processor - processor = new Processor(false); - - // Modify its configuration settings - Configuration config = processor.getUnderlyingConfiguration(); - config.setVersionWarning(false); - - // Use our custom error listener which reports line numbers in the CTL - // source file - errorListener = new TeErrorListener(); - config.setErrorListener(errorListener); - - // Create a compiler and document builder - compiler = processor.newXsltCompiler(); - builder = processor.newDocumentBuilder(); - - // Load an executable for the TECore.form method - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - InputStream is = cl.getResourceAsStream("com/occamlab/te/formfn.xsl"); - formExecutable = compiler.compile(new StreamSource(is)); - // Fortify Mod: We are done with the InputStream. Release the resource - is.close(); - } - - public void addFunctionLibrary(Collection indexes) { - // Change the function library to a new library list that includes - // our custom java function library - Configuration config = processor.getUnderlyingConfiguration(); - FunctionLibraryList liblist = new FunctionLibraryList(); - for (Index index : indexes) { - TEFunctionLibrary telib = new TEFunctionLibrary(config, index); - liblist.addFunctionLibrary(telib); - } - liblist.addFunctionLibrary(config.getExtensionBinder("java")); - config.setExtensionBinder("java", liblist); - - } - - /** - * Loads all of the XSL executables. This is a time consuming operation. - * @param index - * @param sourcesName A stylesheet reference. - * @throws Exception If the stylesheet fail to compile. - */ - public void preload(Index index, String sourcesName) throws Exception { - for (String key : index.getTestKeys()) { - TestEntry te = index.getTest(key); - loadExecutable(te, sourcesName); - } - for (String key : index.getFunctionKeys()) { - List functions = index.getFunctions(key); - for (FunctionEntry fe : functions) { - if (!fe.isJava()) { - loadExecutable(fe, sourcesName); - } - } - } - } - - boolean freeExecutable() { - Set keys = loadedExecutables.keySet(); - synchronized (loadedExecutables) { - Iterator it = keys.iterator(); - if (it.hasNext()) { - loadedExecutables.remove(it.next()); - return true; - } - } - return false; - } - - public XsltExecutable loadExecutable(TemplateEntry entry, String sourcesName) throws Exception { - String key = sourcesName + "," + entry.getId(); - if (entry instanceof FunctionEntry) { - key += "_" + ((FunctionEntry) entry).getMinArgs(); - } - XsltExecutable executable = loadedExecutables.get(key); - while (executable == null) { - // capture messages written to System.err by default message emitter - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream console = System.err; - try { - System.setErr(new PrintStream(baos)); - Source source = new StreamSource(entry.getTemplateFile()); - executable = compiler.compile(source); - loadedExecutables.put(key, executable); - } - catch (OutOfMemoryError e) { - boolean freed = freeExecutable(); - if (!freed) { - throw e; - } - } - catch (SaxonApiException e) { - throw new Exception(baos.toString() + e.getMessage(), e.getCause()); - } - finally { - System.setErr(console); - } - } - while (loadedExecutables.size() > cacheSize) { - boolean freed = freeExecutable(); - if (!freed) { - break; - } - } - - return executable; - } - - public Map getLoadedExecutables() { - return loadedExecutables; - } - - public TEClassLoader getClassLoader(String sourcesName) { - return classLoaders.get(sourcesName); - } - - public DocumentBuilder getBuilder() { - return builder; - } - - public XsltCompiler getCompiler() { - return compiler; - } - - public TeErrorListener getErrorListener() { - return errorListener; - } - - public XsltExecutable getFormExecutable() { - return formExecutable; - } - - public Processor getProcessor() { - return processor; - } - - public void setClassLoader(String sourcesName, TEClassLoader cl) { - if (null == this.classLoaders) { - this.classLoaders = new HashMap<>(); - } - this.classLoaders.put(sourcesName, cl); - } - -} +/* + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): + C. Heazel (WiSC): Applied mods to address Fortify issues + + */ + +package com.occamlab.te; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; + +import net.sf.saxon.Configuration; +import net.sf.saxon.functions.FunctionLibraryList; +import net.sf.saxon.s9api.DocumentBuilder; +import net.sf.saxon.s9api.Processor; +import net.sf.saxon.s9api.SaxonApiException; +import net.sf.saxon.s9api.XsltCompiler; +import net.sf.saxon.s9api.XsltExecutable; + +import com.occamlab.te.index.FunctionEntry; +import com.occamlab.te.index.Index; +import com.occamlab.te.index.TemplateEntry; +import com.occamlab.te.index.TestEntry; +import com.occamlab.te.saxon.TEFunctionLibrary; + +public class Engine { + + int cacheSize = 50; + + Processor processor = null; + + XsltCompiler compiler = null; + + DocumentBuilder builder = null; + + TeErrorListener errorListener = null; + + XsltExecutable formExecutable = null; + + // Map of loaded executables, ordered by access order + public Map loadedExecutables = Collections + .synchronizedMap(new LinkedHashMap<>(256, 0.75f, true)); + + public Map classLoaders; + + public Engine(Index index, String sourcesName, TEClassLoader cl) throws Exception { + this(); + ArrayList indexes = new ArrayList<>(); + indexes.add(index); + classLoaders = new HashMap<>(); + classLoaders.put(sourcesName, cl); + addFunctionLibrary(indexes); + } + + public Engine(Collection indexes, Map classLoaders, int cacheSize) throws Exception { + this(); + this.classLoaders = classLoaders; + if (cacheSize > 0) { + this.cacheSize = cacheSize; + } + addFunctionLibrary(indexes); + } + + public Engine() throws Exception { + String s = System.getProperty("te.cacheSize"); + if (s != null) { + cacheSize = Integer.parseInt(s); + } + + // Create processor + processor = new Processor(false); + + // Modify its configuration settings + Configuration config = processor.getUnderlyingConfiguration(); + config.setVersionWarning(false); + + // Use our custom error listener which reports line numbers in the CTL + // source file + errorListener = new TeErrorListener(); + config.setErrorListener(errorListener); + + // Create a compiler and document builder + compiler = processor.newXsltCompiler(); + builder = processor.newDocumentBuilder(); + + // Load an executable for the TECore.form method + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + InputStream is = cl.getResourceAsStream("com/occamlab/te/formfn.xsl"); + formExecutable = compiler.compile(new StreamSource(is)); + // Fortify Mod: We are done with the InputStream. Release the resource + is.close(); + } + + public void addFunctionLibrary(Collection indexes) { + // Change the function library to a new library list that includes + // our custom java function library + Configuration config = processor.getUnderlyingConfiguration(); + FunctionLibraryList liblist = new FunctionLibraryList(); + for (Index index : indexes) { + TEFunctionLibrary telib = new TEFunctionLibrary(config, index); + liblist.addFunctionLibrary(telib); + } + liblist.addFunctionLibrary(config.getExtensionBinder("java")); + config.setExtensionBinder("java", liblist); + + } + + /** + * Loads all of the XSL executables. This is a time consuming operation. + * @param index + * @param sourcesName A stylesheet reference. + * @throws Exception If the stylesheet fail to compile. + */ + public void preload(Index index, String sourcesName) throws Exception { + for (String key : index.getTestKeys()) { + TestEntry te = index.getTest(key); + loadExecutable(te, sourcesName); + } + for (String key : index.getFunctionKeys()) { + List functions = index.getFunctions(key); + for (FunctionEntry fe : functions) { + if (!fe.isJava()) { + loadExecutable(fe, sourcesName); + } + } + } + } + + boolean freeExecutable() { + Set keys = loadedExecutables.keySet(); + synchronized (loadedExecutables) { + Iterator it = keys.iterator(); + if (it.hasNext()) { + loadedExecutables.remove(it.next()); + return true; + } + } + return false; + } + + public XsltExecutable loadExecutable(TemplateEntry entry, String sourcesName) throws Exception { + String key = sourcesName + "," + entry.getId(); + if (entry instanceof FunctionEntry) { + key += "_" + ((FunctionEntry) entry).getMinArgs(); + } + XsltExecutable executable = loadedExecutables.get(key); + while (executable == null) { + // capture messages written to System.err by default message emitter + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream console = System.err; + try { + System.setErr(new PrintStream(baos)); + Source source = new StreamSource(entry.getTemplateFile()); + executable = compiler.compile(source); + loadedExecutables.put(key, executable); + } + catch (OutOfMemoryError e) { + boolean freed = freeExecutable(); + if (!freed) { + throw e; + } + } + catch (SaxonApiException e) { + throw new Exception(baos.toString() + e.getMessage(), e.getCause()); + } + finally { + System.setErr(console); + } + } + while (loadedExecutables.size() > cacheSize) { + boolean freed = freeExecutable(); + if (!freed) { + break; + } + } + + return executable; + } + + public Map getLoadedExecutables() { + return loadedExecutables; + } + + public TEClassLoader getClassLoader(String sourcesName) { + return classLoaders.get(sourcesName); + } + + public DocumentBuilder getBuilder() { + return builder; + } + + public XsltCompiler getCompiler() { + return compiler; + } + + public TeErrorListener getErrorListener() { + return errorListener; + } + + public XsltExecutable getFormExecutable() { + return formExecutable; + } + + public Processor getProcessor() { + return processor; + } + + public void setClassLoader(String sourcesName, TEClassLoader cl) { + if (null == this.classLoaders) { + this.classLoaders = new HashMap<>(); + } + this.classLoaders.put(sourcesName, cl); + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/ErrorHandlerImpl.java b/teamengine-core/src/main/java/com/occamlab/te/ErrorHandlerImpl.java index eeac8b0d3..de65fa962 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/ErrorHandlerImpl.java +++ b/teamengine-core/src/main/java/com/occamlab/te/ErrorHandlerImpl.java @@ -1,108 +1,128 @@ -package com.occamlab.te; - -import org.xml.sax.ErrorHandler; -import org.xml.sax.SAXParseException; - -import java.io.PrintWriter; - -/** - * Handles errors arising while processing XML resources and records the numbers of error - * and warning notifications received. - * - */ -public class ErrorHandlerImpl implements ErrorHandler { - - private int ErrorCount = 0; - - private int WarningCount = 0; - - private PrintWriter Logger; - - private String Prefix = ""; - - public ErrorHandlerImpl() { - this(null, new PrintWriter(System.out)); - } - - public ErrorHandlerImpl(String role, PrintWriter logger) { - setRole(role); - setLogger(logger); - } - - public void setRole(String role) { - if (role != null) { - Prefix = role + " "; - } - } - - public void setLogger(PrintWriter logger) { - Logger = logger; - } - - public String getErrorCounts() { - String msg = ""; - if (ErrorCount > 0 || WarningCount > 0) { - if (ErrorCount > 0) { - msg += ErrorCount + " error" + (ErrorCount == 1 ? "" : "s"); - if (WarningCount > 0) - msg += " and "; - } - if (WarningCount > 0) { - msg += WarningCount + " warning" + (WarningCount == 1 ? "" : "s"); - } - } - else { - msg = "No errors or warnings"; - } - msg += " detected."; - return msg; - } - - private void error(String type, SAXParseException e) { - Logger.print(type); - if (e.getLineNumber() >= 0) { - Logger.print(" at line " + e.getLineNumber()); - if (e.getColumnNumber() >= 0) { - Logger.print(", column " + e.getColumnNumber()); - } - if (e.getSystemId() != null) { - Logger.print(" of " + e.getSystemId()); - } - } - else { - if (e.getSystemId() != null) { - Logger.print(" in " + e.getSystemId()); - } - } - Logger.println(":"); - Logger.println(" " + e.getMessage()); - Logger.flush(); - // System.err.println(type + " at line " + + e.getLineNumber() + ", - // column " + e.getColumnNumber() + " of " + e.getSystemId() + ":"); - // System.err.println(" " + e.getMessage()); - } - - public int getErrorCount() { - return ErrorCount; - } - - public int getWarningCount() { - return WarningCount; - } - - public void error(SAXParseException exception) { - error(Prefix + "error", exception); - ErrorCount++; - } - - public void fatalError(SAXParseException exception) { - error("Fatal " + Prefix + "error", exception); - ErrorCount++; - } - - public void warning(SAXParseException exception) { - error(Prefix + "warning", exception); - WarningCount++; - } - -} +package com.occamlab.te; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXParseException; + +import java.io.PrintWriter; + +/** + * Handles errors arising while processing XML resources and records the numbers of error + * and warning notifications received. + * + */ +public class ErrorHandlerImpl implements ErrorHandler { + + private int ErrorCount = 0; + + private int WarningCount = 0; + + private PrintWriter Logger; + + private String Prefix = ""; + + public ErrorHandlerImpl() { + this(null, new PrintWriter(System.out)); + } + + public ErrorHandlerImpl(String role, PrintWriter logger) { + setRole(role); + setLogger(logger); + } + + public void setRole(String role) { + if (role != null) { + Prefix = role + " "; + } + } + + public void setLogger(PrintWriter logger) { + Logger = logger; + } + + public String getErrorCounts() { + String msg = ""; + if (ErrorCount > 0 || WarningCount > 0) { + if (ErrorCount > 0) { + msg += ErrorCount + " error" + (ErrorCount == 1 ? "" : "s"); + if (WarningCount > 0) + msg += " and "; + } + if (WarningCount > 0) { + msg += WarningCount + " warning" + (WarningCount == 1 ? "" : "s"); + } + } + else { + msg = "No errors or warnings"; + } + msg += " detected."; + return msg; + } + + private void error(String type, SAXParseException e) { + Logger.print(type); + if (e.getLineNumber() >= 0) { + Logger.print(" at line " + e.getLineNumber()); + if (e.getColumnNumber() >= 0) { + Logger.print(", column " + e.getColumnNumber()); + } + if (e.getSystemId() != null) { + Logger.print(" of " + e.getSystemId()); + } + } + else { + if (e.getSystemId() != null) { + Logger.print(" in " + e.getSystemId()); + } + } + Logger.println(":"); + Logger.println(" " + e.getMessage()); + Logger.flush(); + // System.err.println(type + " at line " + + e.getLineNumber() + ", + // column " + e.getColumnNumber() + " of " + e.getSystemId() + ":"); + // System.err.println(" " + e.getMessage()); + } + + public int getErrorCount() { + return ErrorCount; + } + + public int getWarningCount() { + return WarningCount; + } + + public void error(SAXParseException exception) { + error(Prefix + "error", exception); + ErrorCount++; + } + + public void fatalError(SAXParseException exception) { + error("Fatal " + Prefix + "error", exception); + ErrorCount++; + } + + public void warning(SAXParseException exception) { + error(Prefix + "warning", exception); + WarningCount++; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/Generator.java b/teamengine-core/src/main/java/com/occamlab/te/Generator.java index 7c5d1b9ac..942ca534f 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/Generator.java +++ b/teamengine-core/src/main/java/com/occamlab/te/Generator.java @@ -1,257 +1,277 @@ -/* - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): - C. Heazel (WiSC): Added Fortify adjudication changes - */ -package com.occamlab.te; - -import java.io.File; -import java.io.FileInputStream; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.xml.XMLConstants; -import javax.xml.parsers.SAXParser; -import javax.xml.transform.Source; -import javax.xml.transform.sax.SAXSource; -import javax.xml.transform.stream.StreamSource; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; -import javax.xml.validation.Validator; - -import net.sf.saxon.FeatureKeys; -import net.sf.saxon.s9api.Processor; -import net.sf.saxon.s9api.QName; -import net.sf.saxon.s9api.Serializer; -import net.sf.saxon.s9api.XdmAtomicValue; -import net.sf.saxon.s9api.XsltCompiler; -import net.sf.saxon.s9api.XsltExecutable; -import net.sf.saxon.s9api.XsltTransformer; - -import org.xml.sax.InputSource; -import org.xml.sax.XMLReader; // Fortify mod. - -import com.occamlab.te.index.Index; -import com.occamlab.te.util.Misc; -import com.occamlab.te.util.XMLParserUtils; - -/** - * Generates XSL template files from CTL sources and a master index of metadata about the - * CTL objects. The resulting files are stored in sub-directories of the main work - * directory (TE_BASE/work). - */ -public class Generator { - - private static final Logger LOGR = Logger.getLogger(Generator.class.getName()); - - private static String suiteDefaultResult = "Pass"; - - public static void setSuiteDefaultResult(String resultName) { - suiteDefaultResult = resultName.equals("BestPractice") ? "BestPractice" : "Pass"; - } - - public static String getSuiteDefaultResult() { - return suiteDefaultResult; - } - - /** - * Generates the XSLT stylesheets for running in doc mode. - * @param opts Static configuration settings. - * @return A master Index object that describes the resulting stylesheets. - * @throws Exception - */ - public static Index generateDocXsl(SetupOptions opts) throws Exception { - return generateXsl(opts, "com/occamlab/te/generate_dxsl.xsl", true); - } - - /** - * Generates the XSLT stylesheets that constitute an executable test suite (ETS). - * @param opts Static configuration settings. - * @return A master Index object that describes the resulting stylesheets. - * @throws Exception - */ - public static Index generateXsl(SetupOptions opts) throws Exception { - return generateXsl(opts, "com/occamlab/te/generate_xsl.xsl", false); - } - - private static Index generateXsl(SetupOptions opts, String generatorStylesheetResource, boolean docMode) - throws Exception { - Index masterIndex = new Index(); - - // Create CTL validator - SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - Schema ctl_schema = sf.newSchema(new StreamSource(Misc.getResourceURL("com/occamlab/te/schemas/ctl.xsd"))); - Validator ctl_validator = ctl_schema.newValidator(); - CtlErrorHandler validation_eh = new CtlErrorHandler(); - ctl_validator.setErrorHandler(validation_eh); - - // Create a transformer to generate executable scripts from CTL sources - Processor processor = new Processor(false); - processor.setConfigurationProperty(FeatureKeys.LINE_NUMBERING, Boolean.TRUE); - XsltCompiler generatorCompiler = processor.newXsltCompiler(); - XsltExecutable generatorXsltExecutable = generatorCompiler - .compile(new StreamSource(Misc.getResourceURL(generatorStylesheetResource))); - XsltTransformer generatorTransformer = generatorXsltExecutable.load(); - - // Create a list of CTL sources (may be files or dirs) - ArrayList sources = new ArrayList<>(); - File f = Misc.getResourceAsFile("com/occamlab/te/scripts/parsers.ctl"); - if (f.exists()) { - sources.add(f.getParentFile()); - } - sources.addAll(opts.getSources()); - - // Create a list of source CTL files only (no dirs), - // and a corresponding list containing a working dir for each file - ArrayList sourceFiles = new ArrayList<>(); - ArrayList workDirs = new ArrayList<>(); - Iterator it = sources.iterator(); - while (it.hasNext()) { - File source = it.next(); - LOGR.log(Level.FINE, "Processing CTL source files in {0}", source.getAbsolutePath()); - String encodedName = createEncodedName(source); - if (docMode) { - encodedName += "d"; - } - File workingDir = new File(opts.getWorkDir(), encodedName); - if (!workingDir.exists() && !workingDir.mkdir()) { - LOGR.log(Level.WARNING, "Unable to create working directory at {0}", workingDir.getAbsolutePath()); - } - if (source.isDirectory()) { - String[] children = source.list(); - for (int i = 0; i < children.length; i++) { - // Finds all .ctl and .xml files in the directory to use - String lowerName = children[i].toLowerCase(); - if (lowerName.endsWith(".ctl") || lowerName.endsWith(".xml")) { - File file = new File(source, children[i]); - if (file.isFile()) { - sourceFiles.add(file); - String basename = children[i].substring(0, children[i].length() - 4); - File subdir = new File(workingDir, basename); - subdir.mkdir(); - workDirs.add(subdir); - } - } - } - } - else { - sourceFiles.add(source); - workDirs.add(workingDir); - } - } - - // resolve xinclude elements but omit xml:base attributes - SAXParser parser = XMLParserUtils.createXIncludeAwareSAXParser(false); - - File generatorStylesheet = Misc.getResourceAsFile(generatorStylesheetResource); - - // Process each CTL source file - for (int i = 0; i < sourceFiles.size(); i++) { - File sourceFile = sourceFiles.get(i); - File workingDir = workDirs.get(i); - - // Read previous index for this file (if any), and determine whether - // the index and xsl need to be regenerated - File indexFile = new File(workingDir, "index.xml"); - Index index = null; - boolean regenerate = true; - - if (generatorStylesheet == null) { - // generatorStylesheet couldn't be found as a file (it was loaded from - // classpath jar) - regenerate = true; - } - else if (indexFile.isFile()) { - try { - if (indexFile.lastModified() > generatorStylesheet.lastModified()) { - index = new Index(indexFile); - regenerate = index.outOfDate(); - } - } - catch (Exception e) { - // If there was an exception reading the index file, it is - // likely corrupt. Regenerate it. - regenerate = true; - } - } - - if (regenerate) { - // Validate the source CTL file - boolean validationErrors = false; - if (opts.isValidate()) { - int old_count = validation_eh.getErrorCount(); - LOGR.log(Level.CONFIG, "Validating " + sourceFile); - ctl_validator.validate(new StreamSource(sourceFile)); - validationErrors = (validation_eh.getErrorCount() > old_count); - } - - if (!validationErrors) { - // Clean up the working directory - Misc.deleteDirContents(workingDir); - - InputSource input = new InputSource(new FileInputStream(sourceFile)); - input.setSystemId(sourceFile.toURI().toString()); - // Fortify Mods to prevent External Entity Injection - XMLReader reader = parser.getXMLReader(); - reader.setFeature("http://xml.org/sax/features/external-general-entities", false); - Source ctlSource = new SAXSource(reader, input); - // Source ctlSource = new SAXSource(parser.getXMLReader(),input); - // End Fortify Mods - // Run the generator transformation. Output is an index file - // and is saved to disk. The generator also creates XSL - // template files in the working dir. - generatorTransformer.setSource(ctlSource); - Serializer generatorSerializer = new Serializer(); - generatorSerializer.setOutputFile(indexFile); - generatorTransformer.setDestination(generatorSerializer); - XdmAtomicValue av = new XdmAtomicValue(workingDir.getAbsolutePath()); - generatorTransformer.setParameter(new QName("outdir"), av); - generatorTransformer.transform(); - - // Read the generated index - index = new Index(indexFile); - } - } - // Add new index entries to the master index - masterIndex.add(index); - } - - // If there were any validation errors, display them and throw an - // exception - int error_count = validation_eh.getErrorCount(); - if (error_count > 0) { - String msg = error_count + " validation error" + (error_count == 1 ? "" : "s"); - int warning_count = validation_eh.getWarningCount(); - if (warning_count > 0) { - msg += " and " + warning_count + " warning" + (warning_count == 1 ? "" : "s"); - } - msg += " detected."; - // appLogger.severe(msg); - throw new Exception(msg); - } - - return masterIndex; - } - - /** - * Creates a directory name from a file path. - * @param source A File reference. - * @return A String representing a legal directory name. - */ - public static String createEncodedName(File source) { - String fileURI = source.toURI().toString(); - String userDirURI = new File(System.getProperty("user.dir")).toURI().toString(); - fileURI = fileURI.replace(userDirURI, ""); - return fileURI.substring(fileURI.lastIndexOf(':') + 1).replace("%20", "-").replace('/', '_'); - } - -} +/* + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): + C. Heazel (WiSC): Added Fortify adjudication changes + */ +package com.occamlab.te; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.io.FileInputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.xml.XMLConstants; +import javax.xml.parsers.SAXParser; +import javax.xml.transform.Source; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; + +import net.sf.saxon.FeatureKeys; +import net.sf.saxon.s9api.Processor; +import net.sf.saxon.s9api.QName; +import net.sf.saxon.s9api.Serializer; +import net.sf.saxon.s9api.XdmAtomicValue; +import net.sf.saxon.s9api.XsltCompiler; +import net.sf.saxon.s9api.XsltExecutable; +import net.sf.saxon.s9api.XsltTransformer; + +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; // Fortify mod. + +import com.occamlab.te.index.Index; +import com.occamlab.te.util.Misc; +import com.occamlab.te.util.XMLParserUtils; + +/** + * Generates XSL template files from CTL sources and a master index of metadata about the + * CTL objects. The resulting files are stored in sub-directories of the main work + * directory (TE_BASE/work). + */ +public class Generator { + + private static final Logger LOGR = Logger.getLogger(Generator.class.getName()); + + private static String suiteDefaultResult = "Pass"; + + public static void setSuiteDefaultResult(String resultName) { + suiteDefaultResult = resultName.equals("BestPractice") ? "BestPractice" : "Pass"; + } + + public static String getSuiteDefaultResult() { + return suiteDefaultResult; + } + + /** + * Generates the XSLT stylesheets for running in doc mode. + * @param opts Static configuration settings. + * @return A master Index object that describes the resulting stylesheets. + * @throws Exception + */ + public static Index generateDocXsl(SetupOptions opts) throws Exception { + return generateXsl(opts, "com/occamlab/te/generate_dxsl.xsl", true); + } + + /** + * Generates the XSLT stylesheets that constitute an executable test suite (ETS). + * @param opts Static configuration settings. + * @return A master Index object that describes the resulting stylesheets. + * @throws Exception + */ + public static Index generateXsl(SetupOptions opts) throws Exception { + return generateXsl(opts, "com/occamlab/te/generate_xsl.xsl", false); + } + + private static Index generateXsl(SetupOptions opts, String generatorStylesheetResource, boolean docMode) + throws Exception { + Index masterIndex = new Index(); + + // Create CTL validator + SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + Schema ctl_schema = sf.newSchema(new StreamSource(Misc.getResourceURL("com/occamlab/te/schemas/ctl.xsd"))); + Validator ctl_validator = ctl_schema.newValidator(); + CtlErrorHandler validation_eh = new CtlErrorHandler(); + ctl_validator.setErrorHandler(validation_eh); + + // Create a transformer to generate executable scripts from CTL sources + Processor processor = new Processor(false); + processor.setConfigurationProperty(FeatureKeys.LINE_NUMBERING, Boolean.TRUE); + XsltCompiler generatorCompiler = processor.newXsltCompiler(); + XsltExecutable generatorXsltExecutable = generatorCompiler + .compile(new StreamSource(Misc.getResourceURL(generatorStylesheetResource))); + XsltTransformer generatorTransformer = generatorXsltExecutable.load(); + + // Create a list of CTL sources (may be files or dirs) + ArrayList sources = new ArrayList<>(); + File f = Misc.getResourceAsFile("com/occamlab/te/scripts/parsers.ctl"); + if (f.exists()) { + sources.add(f.getParentFile()); + } + sources.addAll(opts.getSources()); + + // Create a list of source CTL files only (no dirs), + // and a corresponding list containing a working dir for each file + ArrayList sourceFiles = new ArrayList<>(); + ArrayList workDirs = new ArrayList<>(); + Iterator it = sources.iterator(); + while (it.hasNext()) { + File source = it.next(); + LOGR.log(Level.FINE, "Processing CTL source files in {0}", source.getAbsolutePath()); + String encodedName = createEncodedName(source); + if (docMode) { + encodedName += "d"; + } + File workingDir = new File(opts.getWorkDir(), encodedName); + if (!workingDir.exists() && !workingDir.mkdir()) { + LOGR.log(Level.WARNING, "Unable to create working directory at {0}", workingDir.getAbsolutePath()); + } + if (source.isDirectory()) { + String[] children = source.list(); + for (int i = 0; i < children.length; i++) { + // Finds all .ctl and .xml files in the directory to use + String lowerName = children[i].toLowerCase(); + if (lowerName.endsWith(".ctl") || lowerName.endsWith(".xml")) { + File file = new File(source, children[i]); + if (file.isFile()) { + sourceFiles.add(file); + String basename = children[i].substring(0, children[i].length() - 4); + File subdir = new File(workingDir, basename); + subdir.mkdir(); + workDirs.add(subdir); + } + } + } + } + else { + sourceFiles.add(source); + workDirs.add(workingDir); + } + } + + // resolve xinclude elements but omit xml:base attributes + SAXParser parser = XMLParserUtils.createXIncludeAwareSAXParser(false); + + File generatorStylesheet = Misc.getResourceAsFile(generatorStylesheetResource); + + // Process each CTL source file + for (int i = 0; i < sourceFiles.size(); i++) { + File sourceFile = sourceFiles.get(i); + File workingDir = workDirs.get(i); + + // Read previous index for this file (if any), and determine whether + // the index and xsl need to be regenerated + File indexFile = new File(workingDir, "index.xml"); + Index index = null; + boolean regenerate = true; + + if (generatorStylesheet == null) { + // generatorStylesheet couldn't be found as a file (it was loaded from + // classpath jar) + regenerate = true; + } + else if (indexFile.isFile()) { + try { + if (indexFile.lastModified() > generatorStylesheet.lastModified()) { + index = new Index(indexFile); + regenerate = index.outOfDate(); + } + } + catch (Exception e) { + // If there was an exception reading the index file, it is + // likely corrupt. Regenerate it. + regenerate = true; + } + } + + if (regenerate) { + // Validate the source CTL file + boolean validationErrors = false; + if (opts.isValidate()) { + int old_count = validation_eh.getErrorCount(); + LOGR.log(Level.CONFIG, "Validating " + sourceFile); + ctl_validator.validate(new StreamSource(sourceFile)); + validationErrors = (validation_eh.getErrorCount() > old_count); + } + + if (!validationErrors) { + // Clean up the working directory + Misc.deleteDirContents(workingDir); + + InputSource input = new InputSource(new FileInputStream(sourceFile)); + input.setSystemId(sourceFile.toURI().toString()); + // Fortify Mods to prevent External Entity Injection + XMLReader reader = parser.getXMLReader(); + reader.setFeature("http://xml.org/sax/features/external-general-entities", false); + Source ctlSource = new SAXSource(reader, input); + // Source ctlSource = new SAXSource(parser.getXMLReader(),input); + // End Fortify Mods + // Run the generator transformation. Output is an index file + // and is saved to disk. The generator also creates XSL + // template files in the working dir. + generatorTransformer.setSource(ctlSource); + Serializer generatorSerializer = new Serializer(); + generatorSerializer.setOutputFile(indexFile); + generatorTransformer.setDestination(generatorSerializer); + XdmAtomicValue av = new XdmAtomicValue(workingDir.getAbsolutePath()); + generatorTransformer.setParameter(new QName("outdir"), av); + generatorTransformer.transform(); + + // Read the generated index + index = new Index(indexFile); + } + } + // Add new index entries to the master index + masterIndex.add(index); + } + + // If there were any validation errors, display them and throw an + // exception + int error_count = validation_eh.getErrorCount(); + if (error_count > 0) { + String msg = error_count + " validation error" + (error_count == 1 ? "" : "s"); + int warning_count = validation_eh.getWarningCount(); + if (warning_count > 0) { + msg += " and " + warning_count + " warning" + (warning_count == 1 ? "" : "s"); + } + msg += " detected."; + // appLogger.severe(msg); + throw new Exception(msg); + } + + return masterIndex; + } + + /** + * Creates a directory name from a file path. + * @param source A File reference. + * @return A String representing a legal directory name. + */ + public static String createEncodedName(File source) { + String fileURI = source.toURI().toString(); + String userDirURI = new File(System.getProperty("user.dir")).toURI().toString(); + fileURI = fileURI.replace(userDirURI, ""); + return fileURI.substring(fileURI.lastIndexOf(':') + 1).replace("%20", "-").replace('/', '_'); + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/ListSuites.java b/teamengine-core/src/main/java/com/occamlab/te/ListSuites.java index 52c45905e..4bff7ca1f 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/ListSuites.java +++ b/teamengine-core/src/main/java/com/occamlab/te/ListSuites.java @@ -1,114 +1,134 @@ -package com.occamlab.te; - -import java.io.File; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.occamlab.te.index.Index; -import com.occamlab.te.index.SuiteEntry; - -/** - * Command line utility for listing test suites in CTL sources. - * - * C. Heazel: modified to address Fortify issues 1/24/18 - * - */ -public class ListSuites { - - public static void main(String[] args) throws Exception { - SetupOptions setupOpts = new SetupOptions(); - File scriptsDir = new File(SetupOptions.getBaseConfigDirectory(), "scripts"); - String cmd = "java com.occamlab.te.ListSuites"; - - // Parse source command-line argument - for (int i = 0; i < args.length; i++) { - if (args[i].startsWith("-source=")) { - File f = new File(scriptsDir, args[i].substring(8)); - // Fortify Mod: make sure that the -source argument - // is not pointing to an illegal location - if (!f.exists() || !setupOpts.addSourceWithValidation(f)) { - System.out.println("Error: Can't find CTL script(s) at " + f.getAbsolutePath()); - return; - } - } - else if (args[i].startsWith("-cmd=")) { - cmd = args[i].substring(5); - } - else if (args[i].equals("-h") || args[i].equals("-help") || args[i].equals("-?")) { - syntax(cmd); - return; - } - } - - if (setupOpts.getSources().isEmpty()) { - String path = SetupOptions.getBaseConfigDirectory() + "/config.xml"; - if (new File(path).exists()) { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.parse(path); - NodeList nl = doc.getElementsByTagName("source"); - if (nl != null) { - for (int i = 0; i < nl.getLength(); i++) { - Element source = (Element) nl.item(i); - File f = new File(scriptsDir, source.getTextContent()); - if (!f.exists() || !setupOpts.addSourceWithValidation(f)) { - System.out.println("Error: Can't find CTL script(s) at " + f.getAbsolutePath()); - } - listSuites(setupOpts, true); - setupOpts.getSources().clear(); - } - } - } - else { - System.out.println("No config.xml file found in TE_BASE path " + SetupOptions.getBaseConfigDirectory()); - } - } - else { - listSuites(setupOpts, false); - } - } - - static void listSuites(SetupOptions setupOpts, boolean printSource) throws Exception { - Index index = Generator.generateXsl(setupOpts); - if (printSource) { - System.out.println("Source: " + setupOpts.getSources().get(0)); - } - for (String suiteId : index.getSuiteKeys()) { - SuiteEntry suite = index.getSuite(suiteId); - if (printSource) { - System.out.print(" "); - } - System.out.print("Suite " + suite.getPrefix() + ":" + suite.getLocalName()); - System.out.println(" (" + suiteId + ")"); - System.out.println(" Title: " + suite.getTitle()); - String desc = suite.getDescription(); - if (desc != null) { - System.out.println(" Description: " + desc); - } - String link = suite.getLink(); - if (link != null) { - System.out.println(" Link: " + link); - } - System.out.println(); - } - if (index.getSuiteKeys().isEmpty()) { - System.out.println("No suites found."); - System.out.println("Check the sources in config.xml or supply -source=path option(s)."); - } - System.out.println(); - } - - static void syntax(String cmd) { - System.out.println(); - System.out.println("Lists available test suites:"); - System.out.println(); - System.out.println(cmd + " [-source=ctlfile|dir]...\n"); - } - -} +package com.occamlab.te; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.occamlab.te.index.Index; +import com.occamlab.te.index.SuiteEntry; + +/** + * Command line utility for listing test suites in CTL sources. + * + * C. Heazel: modified to address Fortify issues 1/24/18 + * + */ +public class ListSuites { + + public static void main(String[] args) throws Exception { + SetupOptions setupOpts = new SetupOptions(); + File scriptsDir = new File(SetupOptions.getBaseConfigDirectory(), "scripts"); + String cmd = "java com.occamlab.te.ListSuites"; + + // Parse source command-line argument + for (int i = 0; i < args.length; i++) { + if (args[i].startsWith("-source=")) { + File f = new File(scriptsDir, args[i].substring(8)); + // Fortify Mod: make sure that the -source argument + // is not pointing to an illegal location + if (!f.exists() || !setupOpts.addSourceWithValidation(f)) { + System.out.println("Error: Can't find CTL script(s) at " + f.getAbsolutePath()); + return; + } + } + else if (args[i].startsWith("-cmd=")) { + cmd = args[i].substring(5); + } + else if (args[i].equals("-h") || args[i].equals("-help") || args[i].equals("-?")) { + syntax(cmd); + return; + } + } + + if (setupOpts.getSources().isEmpty()) { + String path = SetupOptions.getBaseConfigDirectory() + "/config.xml"; + if (new File(path).exists()) { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.parse(path); + NodeList nl = doc.getElementsByTagName("source"); + if (nl != null) { + for (int i = 0; i < nl.getLength(); i++) { + Element source = (Element) nl.item(i); + File f = new File(scriptsDir, source.getTextContent()); + if (!f.exists() || !setupOpts.addSourceWithValidation(f)) { + System.out.println("Error: Can't find CTL script(s) at " + f.getAbsolutePath()); + } + listSuites(setupOpts, true); + setupOpts.getSources().clear(); + } + } + } + else { + System.out.println("No config.xml file found in TE_BASE path " + SetupOptions.getBaseConfigDirectory()); + } + } + else { + listSuites(setupOpts, false); + } + } + + static void listSuites(SetupOptions setupOpts, boolean printSource) throws Exception { + Index index = Generator.generateXsl(setupOpts); + if (printSource) { + System.out.println("Source: " + setupOpts.getSources().get(0)); + } + for (String suiteId : index.getSuiteKeys()) { + SuiteEntry suite = index.getSuite(suiteId); + if (printSource) { + System.out.print(" "); + } + System.out.print("Suite " + suite.getPrefix() + ":" + suite.getLocalName()); + System.out.println(" (" + suiteId + ")"); + System.out.println(" Title: " + suite.getTitle()); + String desc = suite.getDescription(); + if (desc != null) { + System.out.println(" Description: " + desc); + } + String link = suite.getLink(); + if (link != null) { + System.out.println(" Link: " + link); + } + System.out.println(); + } + if (index.getSuiteKeys().isEmpty()) { + System.out.println("No suites found."); + System.out.println("Check the sources in config.xml or supply -source=path option(s)."); + } + System.out.println(); + } + + static void syntax(String cmd) { + System.out.println(); + System.out.println("Lists available test suites:"); + System.out.println(); + System.out.println(cmd + " [-source=ctlfile|dir]...\n"); + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/NullErrorListener.java b/teamengine-core/src/main/java/com/occamlab/te/NullErrorListener.java index a99e4693e..25c6742dc 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/NullErrorListener.java +++ b/teamengine-core/src/main/java/com/occamlab/te/NullErrorListener.java @@ -12,6 +12,26 @@ Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop ****************************************************************************/ package com.occamlab.te; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import javax.xml.transform.ErrorListener; import javax.xml.transform.TransformerException; diff --git a/teamengine-core/src/main/java/com/occamlab/te/RecordTestResult.java b/teamengine-core/src/main/java/com/occamlab/te/RecordTestResult.java index 1406ade53..62d54f1b9 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/RecordTestResult.java +++ b/teamengine-core/src/main/java/com/occamlab/te/RecordTestResult.java @@ -10,6 +10,26 @@ */ package com.occamlab.te; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import static com.occamlab.te.TECore.getResultDescription; import com.occamlab.te.index.SuiteEntry; import com.occamlab.te.index.TestEntry; diff --git a/teamengine-core/src/main/java/com/occamlab/te/RecordedForm.java b/teamengine-core/src/main/java/com/occamlab/te/RecordedForm.java index 1c787f711..d5d46c62e 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/RecordedForm.java +++ b/teamengine-core/src/main/java/com/occamlab/te/RecordedForm.java @@ -8,6 +8,26 @@ */ package com.occamlab.te; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.File; import javax.xml.parsers.DocumentBuilder; @@ -41,4 +61,4 @@ public static RecordedForm create(File formFile, TECore teCore) { return new RecordedForm(formFile, teCore); } -} \ No newline at end of file +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/RecordedForms.java b/teamengine-core/src/main/java/com/occamlab/te/RecordedForms.java index f1b4d4b32..353229247 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/RecordedForms.java +++ b/teamengine-core/src/main/java/com/occamlab/te/RecordedForms.java @@ -1,5 +1,25 @@ package com.occamlab.te; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.File; import java.util.ArrayList; import java.util.List; diff --git a/teamengine-core/src/main/java/com/occamlab/te/RuntimeOptions.java b/teamengine-core/src/main/java/com/occamlab/te/RuntimeOptions.java index 06b1e5682..4216411d7 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/RuntimeOptions.java +++ b/teamengine-core/src/main/java/com/occamlab/te/RuntimeOptions.java @@ -1,303 +1,323 @@ -/* - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - January 2018 - Modified all set operations to validate the input prior - to updating the runtime properties. This included converting these - operations to return a boolean vs. a void. - - Contributor(s): - C. Heazel (WiSC): - - Modifications to address Fortify issues - - Modifications to validate parameters on set operations - */ - -package com.occamlab.te; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.occamlab.te.util.TEPath; // Fortify addition - -import net.sf.saxon.s9api.XdmNode; - -/** - * The RuntimeOptions class provides runtime configuration settings for use by a test. It - * is not enough for this class to hold the settings. It also must assure that the - * settings are correct and valid. A bad configuration value will result in incorrect - * behavior for the test and may even crash the Engine. Therefor, this class implements - * the following requirements: 1) A RuntimeOptions object may be used without setting any - * of the settings. Therefore, the constructor shall initialize all settings to valid - * values. 2) Users may overwrite the RuntimeOption settings Therefore, each "set" - * operation shall validate its argument prior to modifying the setting. 3) The integrity - * of the settings must be protected. Therefore the settings can only be modified through - * the "set" operations. 4) Users must know the state of the runtime settings. Therefore, - * all operations shall return a value. - *

- * The Runtime settings are: - * - * testLogDir: This is the directory where the log file will be written. workDir: - * sessionId: suiteName: A suite is a set of tests. This is the name of the current suite - * testName: The name of the current test. sourcesName: baseURI: profiles: testPaths: - * params: recordedForms: - *

- * The configuration settings are: - * - * testLogDir: -- Constraint: Must be a valid TE directory path. -- Constraint: Null is - * not allowed. -- Comment: Initialized to the TE_BASE/users/ directory - * workDir: -- Constraint: Must be a valid TE directory path. -- Constraint: Null is not - * allowed. -- Comment: Initialized from setupOptions sessionId: -- Constraint: Required - * format is UUID although others are tolerated for now -- Constraint: Null is not - * allowed. suiteName: -- Constraint: Cannot be null -- Comment: initialized to an empty - * string testName: -- Constraint: Cannot be null -- Comment: initialized to an empty - * string sourcesName: -- Constraint: Cannot be null -- Comment: initialized to "default" - * -- TO-DO: determine why any other default breaks TE. baseURI: -- Constraint: Cannot be - * null -- Comment: initialized to an empty string profiles: -- Comment: initialized to an - * empty array list testPaths: -- Comment: initialized to an empty array list params: -- - * Comment: initialized to an empty array list recordedForms: -- Comment: initialized to - * an empty array list - */ - -public class RuntimeOptions { - - private int mode = Test.TEST_MODE; - - private File testLogDir = null; - - private File workDir = null; - - private String sessionId; - - private String testName = ""; - - private String suiteName = ""; - - private String sourcesName = "default"; - - private String baseURI = ""; - - private ArrayList profiles = new ArrayList<>(); - - private ArrayList testPaths = new ArrayList<>(); - - private ArrayList params = new ArrayList<>(); - - private List recordedForms = new ArrayList<>(); - - private static Logger jLogger = Logger.getLogger("com.occamlab.te.RuntimeOptions"); - - private static final String UUID_PATTERN = "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"; - - /** - * Default constructor sets the location of the test log directory to - * TE_BASE/users/{user.name}; it is created if it does not exist. - */ - public RuntimeOptions() { - File baseDir = SetupOptions.getBaseConfigDirectory(); - File usersDir = new File(baseDir, "users"); - File userDir = new File(usersDir, System.getProperty("user.name")); - if (!userDir.exists()) { - userDir.mkdirs(); - } - this.testLogDir = userDir; - SetupOptions sopts = new SetupOptions(); - this.workDir = sopts.getWorkDir(); - jLogger.setLevel(Level.INFO); - } - - public String getBaseURI() { - return baseURI; - } - - // Validate the baseURI argument then update the runtime parameter - public boolean setBaseURI(String baseURI) { - Logger.getLogger(RuntimeOptions.class.getName()).log(Level.CONFIG, "Setting baseURI = " + baseURI); - if (baseURI == null) - return false; - this.baseURI = baseURI; - return true; - } - - public String getSourcesName() { - return sourcesName; - } - - // Validate the sourcesName argument then update the runtime parameter - public boolean setSourcesName(String sourcesName) { - if (sourcesName == null) - return false; - this.sourcesName = sourcesName; - return true; - } - - /** - * Returns the location of the directory for writing test logs to. - * @return A File denoting a directory. - */ - public File getLogDir() { - return testLogDir; - } - - // Validate the logDir argument then update the runtime parameter - public boolean setLogDir(File logDir) { - // Fortify Mod: validate that this is a legal path - if (logDir == null) - return false; - TEPath tpath = new TEPath(logDir.getAbsolutePath()); - if (tpath.isValid()) { - this.testLogDir = logDir; - return true; - } - return false; - } - - public File getWorkDir() { - return workDir; - } - - // Validate the workDir argument then update the runtime parameter - public boolean setWorkDir(File workDir) { - // Fortify Mod: validate that this is a legal path - if (workDir == null) - return false; - TEPath tpath = new TEPath(workDir.getAbsolutePath()); - if (tpath.isValid()) { - this.workDir = workDir; - return true; - } - return false; - } - - public int getMode() { - return mode; - } - - // Validate the mode argument then update the runtime parameter - public boolean setMode(int mode) { - if (mode != Test.TEST_MODE && mode != Test.RETEST_MODE && mode != Test.RESUME_MODE - && mode != Test.REDO_FROM_CACHE_MODE && mode != Test.DOC_MODE && mode != Test.CHECK_MODE) - return false; - this.mode = mode; - return true; - } - - public String getSessionId() { - return sessionId; - } - - // Validate the sessionId argument then update the runtime parameter - public boolean setSessionId(String sessionId) { - jLogger.log(Level.INFO, "RuntimeOptions: Setting session to " + sessionId); - if (sessionId == null) { - return false; - } - this.sessionId = sessionId; - return true; - } - - public String getSuiteName() { - return suiteName; - } - - // Validate the suiteName argument then update the runtime parameter - public boolean setSuiteName(String suiteName) { - if (suiteName == null) - return false; - this.suiteName = suiteName; - return true; - } - - public ArrayList getProfiles() { - return profiles; - } - - // Validate the profile argument then update the runtime parameter - public boolean addProfile(String profile) { - if (profile == null) - return false; - this.profiles.add(profile); - return true; - } - - public ArrayList getTestPaths() { - return testPaths; - } - - // Validate the testPath argument then update the runtime parameter - public boolean addTestPath(String testPath) { - if (testPath == null) - return false; - this.testPaths.add(testPath); - return true; - } - - public ArrayList getParams() { - return params; - } - - // Validate the param argument then update the runtime parameter - public boolean addParam(String param) { - if (param == null) - return false; - this.params.add(param); - return true; - } - - public XdmNode getContextNode() { - return null; - } - - public String getTestName() { - return testName; - } - - // Validate the testName argument then update the runtime parameter - public boolean setTestName(String testName) { - if (testName == null) - return false; - this.testName = testName; - return true; - } - - // Validate the recordedForm argument then update the runtime parameter - public boolean addRecordedForm(String recordedForm) { - if (recordedForm == null) - return false; - recordedForms.add(new File(recordedForm)); - return true; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("RuntimeOptions {\n"); - sb.append("mode=").append(mode).append(",\n"); - sb.append("testLogDir=").append(testLogDir).append(",\n"); - sb.append("workDir=").append(workDir).append(",\n"); - sb.append("sessionId=").append(sessionId).append(",\n"); - sb.append("testName=").append(testName).append(",\n"); - sb.append("suiteName=").append(suiteName).append(",\n"); - sb.append("sourcesName=").append(sourcesName).append(",\n"); - sb.append("baseURI=").append(baseURI).append(",\n"); - sb.append("profiles=").append(profiles).append(",\n"); - sb.append("testPaths=").append(testPaths).append(",\n"); - sb.append("recordedFroms=").append(recordedForms).append(",\n"); - sb.append("params=").append(params).append("\n}"); - return sb.toString(); - } - - /** - * @return the recordedForms - */ - public List getRecordedForms() { - return recordedForms; - } - -} +/* + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + January 2018 - Modified all set operations to validate the input prior + to updating the runtime properties. This included converting these + operations to return a boolean vs. a void. + + Contributor(s): + C. Heazel (WiSC): + - Modifications to address Fortify issues + - Modifications to validate parameters on set operations + */ + +package com.occamlab.te; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.occamlab.te.util.TEPath; // Fortify addition + +import net.sf.saxon.s9api.XdmNode; + +/** + * The RuntimeOptions class provides runtime configuration settings for use by a test. It + * is not enough for this class to hold the settings. It also must assure that the + * settings are correct and valid. A bad configuration value will result in incorrect + * behavior for the test and may even crash the Engine. Therefor, this class implements + * the following requirements: 1) A RuntimeOptions object may be used without setting any + * of the settings. Therefore, the constructor shall initialize all settings to valid + * values. 2) Users may overwrite the RuntimeOption settings Therefore, each "set" + * operation shall validate its argument prior to modifying the setting. 3) The integrity + * of the settings must be protected. Therefore the settings can only be modified through + * the "set" operations. 4) Users must know the state of the runtime settings. Therefore, + * all operations shall return a value. + *

+ * The Runtime settings are: + * + * testLogDir: This is the directory where the log file will be written. workDir: + * sessionId: suiteName: A suite is a set of tests. This is the name of the current suite + * testName: The name of the current test. sourcesName: baseURI: profiles: testPaths: + * params: recordedForms: + *

+ * The configuration settings are: + * + * testLogDir: -- Constraint: Must be a valid TE directory path. -- Constraint: Null is + * not allowed. -- Comment: Initialized to the TE_BASE/users/ directory + * workDir: -- Constraint: Must be a valid TE directory path. -- Constraint: Null is not + * allowed. -- Comment: Initialized from setupOptions sessionId: -- Constraint: Required + * format is UUID although others are tolerated for now -- Constraint: Null is not + * allowed. suiteName: -- Constraint: Cannot be null -- Comment: initialized to an empty + * string testName: -- Constraint: Cannot be null -- Comment: initialized to an empty + * string sourcesName: -- Constraint: Cannot be null -- Comment: initialized to "default" + * -- TO-DO: determine why any other default breaks TE. baseURI: -- Constraint: Cannot be + * null -- Comment: initialized to an empty string profiles: -- Comment: initialized to an + * empty array list testPaths: -- Comment: initialized to an empty array list params: -- + * Comment: initialized to an empty array list recordedForms: -- Comment: initialized to + * an empty array list + */ + +public class RuntimeOptions { + + private int mode = Test.TEST_MODE; + + private File testLogDir = null; + + private File workDir = null; + + private String sessionId; + + private String testName = ""; + + private String suiteName = ""; + + private String sourcesName = "default"; + + private String baseURI = ""; + + private ArrayList profiles = new ArrayList<>(); + + private ArrayList testPaths = new ArrayList<>(); + + private ArrayList params = new ArrayList<>(); + + private List recordedForms = new ArrayList<>(); + + private static Logger jLogger = Logger.getLogger("com.occamlab.te.RuntimeOptions"); + + private static final String UUID_PATTERN = "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"; + + /** + * Default constructor sets the location of the test log directory to + * TE_BASE/users/{user.name}; it is created if it does not exist. + */ + public RuntimeOptions() { + File baseDir = SetupOptions.getBaseConfigDirectory(); + File usersDir = new File(baseDir, "users"); + File userDir = new File(usersDir, System.getProperty("user.name")); + if (!userDir.exists()) { + userDir.mkdirs(); + } + this.testLogDir = userDir; + SetupOptions sopts = new SetupOptions(); + this.workDir = sopts.getWorkDir(); + jLogger.setLevel(Level.INFO); + } + + public String getBaseURI() { + return baseURI; + } + + // Validate the baseURI argument then update the runtime parameter + public boolean setBaseURI(String baseURI) { + Logger.getLogger(RuntimeOptions.class.getName()).log(Level.CONFIG, "Setting baseURI = " + baseURI); + if (baseURI == null) + return false; + this.baseURI = baseURI; + return true; + } + + public String getSourcesName() { + return sourcesName; + } + + // Validate the sourcesName argument then update the runtime parameter + public boolean setSourcesName(String sourcesName) { + if (sourcesName == null) + return false; + this.sourcesName = sourcesName; + return true; + } + + /** + * Returns the location of the directory for writing test logs to. + * @return A File denoting a directory. + */ + public File getLogDir() { + return testLogDir; + } + + // Validate the logDir argument then update the runtime parameter + public boolean setLogDir(File logDir) { + // Fortify Mod: validate that this is a legal path + if (logDir == null) + return false; + TEPath tpath = new TEPath(logDir.getAbsolutePath()); + if (tpath.isValid()) { + this.testLogDir = logDir; + return true; + } + return false; + } + + public File getWorkDir() { + return workDir; + } + + // Validate the workDir argument then update the runtime parameter + public boolean setWorkDir(File workDir) { + // Fortify Mod: validate that this is a legal path + if (workDir == null) + return false; + TEPath tpath = new TEPath(workDir.getAbsolutePath()); + if (tpath.isValid()) { + this.workDir = workDir; + return true; + } + return false; + } + + public int getMode() { + return mode; + } + + // Validate the mode argument then update the runtime parameter + public boolean setMode(int mode) { + if (mode != Test.TEST_MODE && mode != Test.RETEST_MODE && mode != Test.RESUME_MODE + && mode != Test.REDO_FROM_CACHE_MODE && mode != Test.DOC_MODE && mode != Test.CHECK_MODE) + return false; + this.mode = mode; + return true; + } + + public String getSessionId() { + return sessionId; + } + + // Validate the sessionId argument then update the runtime parameter + public boolean setSessionId(String sessionId) { + jLogger.log(Level.INFO, "RuntimeOptions: Setting session to " + sessionId); + if (sessionId == null) { + return false; + } + this.sessionId = sessionId; + return true; + } + + public String getSuiteName() { + return suiteName; + } + + // Validate the suiteName argument then update the runtime parameter + public boolean setSuiteName(String suiteName) { + if (suiteName == null) + return false; + this.suiteName = suiteName; + return true; + } + + public ArrayList getProfiles() { + return profiles; + } + + // Validate the profile argument then update the runtime parameter + public boolean addProfile(String profile) { + if (profile == null) + return false; + this.profiles.add(profile); + return true; + } + + public ArrayList getTestPaths() { + return testPaths; + } + + // Validate the testPath argument then update the runtime parameter + public boolean addTestPath(String testPath) { + if (testPath == null) + return false; + this.testPaths.add(testPath); + return true; + } + + public ArrayList getParams() { + return params; + } + + // Validate the param argument then update the runtime parameter + public boolean addParam(String param) { + if (param == null) + return false; + this.params.add(param); + return true; + } + + public XdmNode getContextNode() { + return null; + } + + public String getTestName() { + return testName; + } + + // Validate the testName argument then update the runtime parameter + public boolean setTestName(String testName) { + if (testName == null) + return false; + this.testName = testName; + return true; + } + + // Validate the recordedForm argument then update the runtime parameter + public boolean addRecordedForm(String recordedForm) { + if (recordedForm == null) + return false; + recordedForms.add(new File(recordedForm)); + return true; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("RuntimeOptions {\n"); + sb.append("mode=").append(mode).append(",\n"); + sb.append("testLogDir=").append(testLogDir).append(",\n"); + sb.append("workDir=").append(workDir).append(",\n"); + sb.append("sessionId=").append(sessionId).append(",\n"); + sb.append("testName=").append(testName).append(",\n"); + sb.append("suiteName=").append(suiteName).append(",\n"); + sb.append("sourcesName=").append(sourcesName).append(",\n"); + sb.append("baseURI=").append(baseURI).append(",\n"); + sb.append("profiles=").append(profiles).append(",\n"); + sb.append("testPaths=").append(testPaths).append(",\n"); + sb.append("recordedFroms=").append(recordedForms).append(",\n"); + sb.append("params=").append(params).append("\n}"); + return sb.toString(); + } + + /** + * @return the recordedForms + */ + public List getRecordedForms() { + return recordedForms; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/SetupOptions.java b/teamengine-core/src/main/java/com/occamlab/te/SetupOptions.java index 3fe5ba801..12d333fd8 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/SetupOptions.java +++ b/teamengine-core/src/main/java/com/occamlab/te/SetupOptions.java @@ -1,232 +1,252 @@ -/** - * ************************************************************************** - * - * Contributor(s): - * C. Heazel (WiSC): Added Fortify adjudication changes - * - *************************************************************************** - */ -package com.occamlab.te; - -import java.io.File; -import java.io.IOException; -import java.nio.file.FileSystems; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import org.w3c.dom.Document; - -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -import com.occamlab.te.util.TEPath; // Fortify addition - -/** - * Provides static configuration settings. The {@code TE_BASE} system property or - * environment variable specifies the location of the main configuration directory that - * contains several essential sub-directories. - * - *

- * - *

- * TE_BASE
- *  |-- config.xml
- *  |-- resources/
- *  |-- scripts/
- *  |-- work/
- *  +-- users/
- *      |-- {username1}/
- *      +-- {usernameN}/
- * 
- * - *

- * - */ -public class SetupOptions { - - public static final String TE_BASE = "TE_BASE"; - - private static File teBaseDir = getBaseConfigDirectory(); - - boolean validate = true; - - boolean preload = false; - - File workDir = null; - - String sourcesName = "default"; - - ArrayList sources = new ArrayList<>(); - - private static Logger jLogger = Logger.getLogger("com.occamlab.te.SetupOptions"); - - /** - * Default constructor. Creates the TE_BASE/scripts directory if it does not exist. - */ - public SetupOptions() { - File scriptsDir = new File(teBaseDir, "scripts"); - if (!scriptsDir.exists() && !scriptsDir.mkdirs()) { - throw new RuntimeException("Failed to create directory at " + scriptsDir.getAbsolutePath()); - } - } - - /** - * Determines the location of the TE_BASE directory by looking for either 1) a system - * property or 2) an environment variable named {@value #TE_BASE}. Finally, if neither - * is set then the "teamengine" subdirectory is created in the user home directory - * (${user.home}/teamengine). - * @return A File denoting the location of the base configuration directory. - */ - public static File getBaseConfigDirectory() { - if (null != teBaseDir) { - return teBaseDir; - } - String basePath = System.getProperty(TE_BASE); - if (null == basePath) { - basePath = System.getenv(TE_BASE); - } - if (null == basePath) { - basePath = System.getProperty("user.home") + FileSystems.getDefault().getSeparator() + "teamengine"; - } - File baseDir = new File(basePath); - if (!baseDir.isDirectory()) { - baseDir.mkdirs(); - } - Logger.getLogger(SetupOptions.class.getName()).log(Level.CONFIG, "Using TE_BASE at " + baseDir); - return baseDir; - } - - /** - * Determine the test recording is on or off. - * @param testName - * @return boolean - * @throws javax.xml.parsers.ParserConfigurationException - * @throws org.xml.sax.SAXException - * @throws java.io.IOException - */ - public static boolean recordingInfo(String testName) - throws ParserConfigurationException, SAXException, IOException { - TECore.rootTestName.clear(); - String path = getBaseConfigDirectory() + "/config.xml"; - if (new File(path).exists()) { - // Fortify Mod: prevent external entity injection - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - // DocumentBuilder db = - // DocumentBuilderFactory.newInstance().newDocumentBuilder(); - Document doc = db.parse(path); - NodeList nodeListForStandardTag = doc.getElementsByTagName("standard"); - if (null != nodeListForStandardTag && nodeListForStandardTag.getLength() > 0) { - for (int i = 0; i < nodeListForStandardTag.getLength(); i++) { - Element elementStandard = (Element) nodeListForStandardTag.item(i); - if (testName.equals(elementStandard.getElementsByTagName("local-name").item(0).getTextContent())) { - if (null != elementStandard.getElementsByTagName("record").item(0)) { - System.setProperty("Record", "True"); - NodeList rootTestNameArray = elementStandard.getElementsByTagName("test-name"); - if (null != rootTestNameArray && rootTestNameArray.getLength() > 0) { - for (int counter = 0; counter < rootTestNameArray.getLength(); counter++) { - Element rootTestName = (Element) rootTestNameArray.item(counter); - TECore.rootTestName.add(rootTestName.getTextContent()); - } - } - return true; - } - } - - } - } - } - System.setProperty("Record", "False"); - return false; - } - - public String getSourcesName() { - return sourcesName; - } - - public void setSourcesName(String sourcesName) { - this.sourcesName = sourcesName; - } - - /** - * Returns the location of the work directory (TE_BASE/work). - * @return A File denoting a directory location; it is created if it does not exist. - */ - public File getWorkDir() { - if (null == this.workDir) { - File dir = new File(teBaseDir, "work"); - if (!dir.exists() && !dir.mkdir()) { - throw new RuntimeException("Failed to create directory at " + dir.getAbsolutePath()); - } - this.workDir = dir; - } - return workDir; - } - - /** - * Returns a list of file system resources (directories and files) containing CTL test - * scripts. - * @return A List containing one or more File references (TE_BASE/scripts is the - * default location). - */ - public List getSources() { - return sources; - } - - /** - * Adds a file system resource to the collection of known scripts. - * @param source A File object representing a file or directory. - * @deprecated Use {@link SetupOptions#addSourceWithValidation(File source)} instead - */ - @Deprecated - public void addSource(File source) { - this.sources.add(source); - } - - /** - * Adds a file system resource to the collection of known scripts. Fortify Mod: - * validate the argument and return success or failure - * @param source A File object representing a file or directory. - */ - public boolean addSourceWithValidation(File source) { - // Fortify Mod: validate that source is on a valid path - if (source != null) { - TEPath tpath = new TEPath(source.getAbsolutePath()); - if (tpath.isValid()) { - this.sources.add(source); - return true; - } - else { - jLogger.log(Level.INFO, "SetupOptions: Attempt to set invalid source " + source); - } - } - return false; - } - - public Element getParamsElement() { - return null; - } - - public boolean isValidate() { - return validate; - } - - public void setValidate(boolean validate) { - this.validate = validate; - } - - public boolean isPreload() { - return preload; - } - - public void setPreload(boolean preload) { - this.preload = preload; - } - -} +/** + * ************************************************************************** + * + * Contributor(s): + * C. Heazel (WiSC): Added Fortify adjudication changes + * + *************************************************************************** + */ +package com.occamlab.te; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileSystems; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import org.w3c.dom.Document; + +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import com.occamlab.te.util.TEPath; // Fortify addition + +/** + * Provides static configuration settings. The {@code TE_BASE} system property or + * environment variable specifies the location of the main configuration directory that + * contains several essential sub-directories. + * + *

+ * + *

+ * TE_BASE
+ *  |-- config.xml
+ *  |-- resources/
+ *  |-- scripts/
+ *  |-- work/
+ *  +-- users/
+ *      |-- {username1}/
+ *      +-- {usernameN}/
+ * 
+ * + *

+ * + */ +public class SetupOptions { + + public static final String TE_BASE = "TE_BASE"; + + private static File teBaseDir = getBaseConfigDirectory(); + + boolean validate = true; + + boolean preload = false; + + File workDir = null; + + String sourcesName = "default"; + + ArrayList sources = new ArrayList<>(); + + private static Logger jLogger = Logger.getLogger("com.occamlab.te.SetupOptions"); + + /** + * Default constructor. Creates the TE_BASE/scripts directory if it does not exist. + */ + public SetupOptions() { + File scriptsDir = new File(teBaseDir, "scripts"); + if (!scriptsDir.exists() && !scriptsDir.mkdirs()) { + throw new RuntimeException("Failed to create directory at " + scriptsDir.getAbsolutePath()); + } + } + + /** + * Determines the location of the TE_BASE directory by looking for either 1) a system + * property or 2) an environment variable named {@value #TE_BASE}. Finally, if neither + * is set then the "teamengine" subdirectory is created in the user home directory + * (${user.home}/teamengine). + * @return A File denoting the location of the base configuration directory. + */ + public static File getBaseConfigDirectory() { + if (null != teBaseDir) { + return teBaseDir; + } + String basePath = System.getProperty(TE_BASE); + if (null == basePath) { + basePath = System.getenv(TE_BASE); + } + if (null == basePath) { + basePath = System.getProperty("user.home") + FileSystems.getDefault().getSeparator() + "teamengine"; + } + File baseDir = new File(basePath); + if (!baseDir.isDirectory()) { + baseDir.mkdirs(); + } + Logger.getLogger(SetupOptions.class.getName()).log(Level.CONFIG, "Using TE_BASE at " + baseDir); + return baseDir; + } + + /** + * Determine the test recording is on or off. + * @param testName + * @return boolean + * @throws javax.xml.parsers.ParserConfigurationException + * @throws org.xml.sax.SAXException + * @throws java.io.IOException + */ + public static boolean recordingInfo(String testName) + throws ParserConfigurationException, SAXException, IOException { + TECore.rootTestName.clear(); + String path = getBaseConfigDirectory() + "/config.xml"; + if (new File(path).exists()) { + // Fortify Mod: prevent external entity injection + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + // DocumentBuilder db = + // DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document doc = db.parse(path); + NodeList nodeListForStandardTag = doc.getElementsByTagName("standard"); + if (null != nodeListForStandardTag && nodeListForStandardTag.getLength() > 0) { + for (int i = 0; i < nodeListForStandardTag.getLength(); i++) { + Element elementStandard = (Element) nodeListForStandardTag.item(i); + if (testName.equals(elementStandard.getElementsByTagName("local-name").item(0).getTextContent())) { + if (null != elementStandard.getElementsByTagName("record").item(0)) { + System.setProperty("Record", "True"); + NodeList rootTestNameArray = elementStandard.getElementsByTagName("test-name"); + if (null != rootTestNameArray && rootTestNameArray.getLength() > 0) { + for (int counter = 0; counter < rootTestNameArray.getLength(); counter++) { + Element rootTestName = (Element) rootTestNameArray.item(counter); + TECore.rootTestName.add(rootTestName.getTextContent()); + } + } + return true; + } + } + + } + } + } + System.setProperty("Record", "False"); + return false; + } + + public String getSourcesName() { + return sourcesName; + } + + public void setSourcesName(String sourcesName) { + this.sourcesName = sourcesName; + } + + /** + * Returns the location of the work directory (TE_BASE/work). + * @return A File denoting a directory location; it is created if it does not exist. + */ + public File getWorkDir() { + if (null == this.workDir) { + File dir = new File(teBaseDir, "work"); + if (!dir.exists() && !dir.mkdir()) { + throw new RuntimeException("Failed to create directory at " + dir.getAbsolutePath()); + } + this.workDir = dir; + } + return workDir; + } + + /** + * Returns a list of file system resources (directories and files) containing CTL test + * scripts. + * @return A List containing one or more File references (TE_BASE/scripts is the + * default location). + */ + public List getSources() { + return sources; + } + + /** + * Adds a file system resource to the collection of known scripts. + * @param source A File object representing a file or directory. + * @deprecated Use {@link SetupOptions#addSourceWithValidation(File source)} instead + */ + @Deprecated + public void addSource(File source) { + this.sources.add(source); + } + + /** + * Adds a file system resource to the collection of known scripts. Fortify Mod: + * validate the argument and return success or failure + * @param source A File object representing a file or directory. + */ + public boolean addSourceWithValidation(File source) { + // Fortify Mod: validate that source is on a valid path + if (source != null) { + TEPath tpath = new TEPath(source.getAbsolutePath()); + if (tpath.isValid()) { + this.sources.add(source); + return true; + } + else { + jLogger.log(Level.INFO, "SetupOptions: Attempt to set invalid source " + source); + } + } + return false; + } + + public Element getParamsElement() { + return null; + } + + public boolean isValidate() { + return validate; + } + + public void setValidate(boolean validate) { + this.validate = validate; + } + + public boolean isPreload() { + return preload; + } + + public void setPreload(boolean preload) { + this.preload = preload; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/Suite.java b/teamengine-core/src/main/java/com/occamlab/te/Suite.java index 62c6a838b..61d7013f2 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/Suite.java +++ b/teamengine-core/src/main/java/com/occamlab/te/Suite.java @@ -1,122 +1,142 @@ -package com.occamlab.te; - -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -/** - * Provides metadata about a test suite. - * - */ -public class Suite { - - private String prefix; - - private String namespaceUri; - - private String localName; - - private String title; - - private String description; - - private String startingTestPrefix; - - private String startingTestNamespaceUri; - - private String startingTestLocalName; - - private String link; - - private String dataLink; - - private String version; - - public Suite(Element suiteElement) { - String name = suiteElement.getAttribute("name"); - this.version = suiteElement.getAttribute("version"); - - int colon = name.indexOf(":"); - prefix = name.substring(0, colon); - localName = name.substring(colon + 1); - namespaceUri = suiteElement.lookupNamespaceURI(prefix); - - NodeList titleElements = suiteElement.getElementsByTagNameNS(Test.CTL_NS, "title"); - title = ((Element) titleElements.item(0)).getTextContent(); - - NodeList descElements = suiteElement.getElementsByTagNameNS(Test.CTL_NS, "description"); - if (descElements.getLength() > 0) { - description = ((Element) descElements.item(0)).getTextContent(); - } - else { - description = null; - } - - NodeList linkElements = suiteElement.getElementsByTagNameNS(Test.CTL_NS, "link"); - for (int i = 0; i < linkElements.getLength(); i++) { - Element linkElem = (Element) linkElements.item(i); - String linkText = linkElem.getTextContent(); - if (linkText.startsWith("data")) { - this.dataLink = linkText; - } - else { - this.link = linkText; - } - } - - NodeList startingTestElements = suiteElement.getElementsByTagNameNS(Test.CTL_NS, "starting-test"); - name = ((Element) startingTestElements.item(0)).getTextContent(); - colon = name.indexOf(":"); - startingTestPrefix = name.substring(0, colon); - startingTestLocalName = name.substring(colon + 1); - startingTestNamespaceUri = suiteElement.lookupNamespaceURI(startingTestPrefix); - } - - public String getKey() { - return namespaceUri + "," + localName; - } - - public String getPrefix() { - return prefix; - } - - public String getNamespaceUri() { - return namespaceUri; - } - - public String getLocalName() { - return localName; - } - - public String getTitle() { - return title; - } - - public String getDescription() { - return description; - } - - public String getLink() { - return this.link; - } - - public String getDataLink() { - return this.dataLink; - } - - public String getStartingTestPrefix() { - return startingTestPrefix; - } - - public String getStartingTestNamespaceUri() { - return startingTestNamespaceUri; - } - - public String getStartingTestLocalName() { - return startingTestLocalName; - } - - public String getVersion() { - return this.version; - } - -} +package com.occamlab.te; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +/** + * Provides metadata about a test suite. + * + */ +public class Suite { + + private String prefix; + + private String namespaceUri; + + private String localName; + + private String title; + + private String description; + + private String startingTestPrefix; + + private String startingTestNamespaceUri; + + private String startingTestLocalName; + + private String link; + + private String dataLink; + + private String version; + + public Suite(Element suiteElement) { + String name = suiteElement.getAttribute("name"); + this.version = suiteElement.getAttribute("version"); + + int colon = name.indexOf(":"); + prefix = name.substring(0, colon); + localName = name.substring(colon + 1); + namespaceUri = suiteElement.lookupNamespaceURI(prefix); + + NodeList titleElements = suiteElement.getElementsByTagNameNS(Test.CTL_NS, "title"); + title = ((Element) titleElements.item(0)).getTextContent(); + + NodeList descElements = suiteElement.getElementsByTagNameNS(Test.CTL_NS, "description"); + if (descElements.getLength() > 0) { + description = ((Element) descElements.item(0)).getTextContent(); + } + else { + description = null; + } + + NodeList linkElements = suiteElement.getElementsByTagNameNS(Test.CTL_NS, "link"); + for (int i = 0; i < linkElements.getLength(); i++) { + Element linkElem = (Element) linkElements.item(i); + String linkText = linkElem.getTextContent(); + if (linkText.startsWith("data")) { + this.dataLink = linkText; + } + else { + this.link = linkText; + } + } + + NodeList startingTestElements = suiteElement.getElementsByTagNameNS(Test.CTL_NS, "starting-test"); + name = ((Element) startingTestElements.item(0)).getTextContent(); + colon = name.indexOf(":"); + startingTestPrefix = name.substring(0, colon); + startingTestLocalName = name.substring(colon + 1); + startingTestNamespaceUri = suiteElement.lookupNamespaceURI(startingTestPrefix); + } + + public String getKey() { + return namespaceUri + "," + localName; + } + + public String getPrefix() { + return prefix; + } + + public String getNamespaceUri() { + return namespaceUri; + } + + public String getLocalName() { + return localName; + } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public String getLink() { + return this.link; + } + + public String getDataLink() { + return this.dataLink; + } + + public String getStartingTestPrefix() { + return startingTestPrefix; + } + + public String getStartingTestNamespaceUri() { + return startingTestNamespaceUri; + } + + public String getStartingTestLocalName() { + return startingTestLocalName; + } + + public String getVersion() { + return this.version; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/SwingForm.java b/teamengine-core/src/main/java/com/occamlab/te/SwingForm.java index ee2b27751..991c96947 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/SwingForm.java +++ b/teamengine-core/src/main/java/com/occamlab/te/SwingForm.java @@ -1,290 +1,310 @@ -package com.occamlab.te; - -import java.awt.BorderLayout; -import java.net.URL; -import java.net.URLDecoder; -import java.io.File; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Enumeration; - -import javax.swing.JEditorPane; -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.SwingUtilities; -import javax.swing.event.HyperlinkEvent; -import javax.swing.event.HyperlinkListener; -import javax.swing.text.AttributeSet; -import javax.swing.text.StyleConstants; -import javax.swing.text.html.FormView; -import javax.swing.text.html.HTML; -import javax.swing.text.html.HTMLDocument; -import javax.swing.text.html.HTMLEditorKit; -import javax.swing.text.html.HTMLFrameHyperlinkEvent; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import com.occamlab.te.util.DomUtils; - -/** - * Swing-based form created from the content of a <ctl:form> element. This is - * produced when not running the test harness in a web application context. - */ -public class SwingForm extends JFrame implements HyperlinkListener { - - static final long serialVersionUID = 7907599307261079944L; - - public static final String CTL_NS = "http://www.occamlab.com/ctl"; - - private static SwingForm mainForm = null; - - private static SwingForm popupForm = null; - - private static TECore core; - - private static String popupName = Thread.currentThread().getName(); - - private JEditorPane jedit; - - private ArrayList fileFields = new ArrayList<>(); - - private static class Invoker implements Runnable { - - String name; - - int width; - - int height; - - public void run() { - if (mainForm == null) { - mainForm = new SwingForm(name); - } - - String html = core.getFormHtml(); - core.setFormHtml(null); - // For some reason, the tag generated by SAXON screws up the - // JEditorPane, so replace it with a dummy tag. - int i = html.indexOf(" 0) { - html = html.substring(0, i + 1) + "blah" + html.substring(i + 5); - } - - mainForm.jedit.setText(html); - mainForm.setSize(width, height); - mainForm.validate(); - mainForm.setVisible(true); - } - - } - - private class CustomFormView extends FormView { - - public CustomFormView(javax.swing.text.Element elem) { - super(elem); - } - - protected void submitData(String data) { - if (SwingForm.this == popupForm) { - return; - } - - // System.out.println("data: "+data); - try { - String kvps = data + "&="; - int start = 0; - int end = data.length(); - - DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - Document doc = db.newDocument(); - Element root = doc.createElement("values"); - doc.appendChild(root); - do { - String key; - String value; - - int eq = kvps.indexOf("=", start); - int amp = kvps.indexOf("&", start); - if (amp > eq) { - key = kvps.substring(start, eq); - value = kvps.substring(eq + 1, amp); - } - else { - key = kvps.substring(start, amp); - value = ""; - } - - Element valueElement = doc.createElement("value"); - valueElement.setAttribute("key", key); - // Special case for file inputs - if (fileFields.contains(key)) { - File f = new File(URLDecoder.decode(value, StandardCharsets.UTF_8)); - if (f != null) { - if (core.formParsers.containsKey(key)) { - Element parser = core.formParsers.get(key); - URL url = f.toURI().toURL(); - Element response = core.parse(url.openConnection(), parser, doc); - Element content = DomUtils.getElementByTagName(response, "content"); - if (content != null) { - Element child = DomUtils.getChildElement(content); - if (child != null) { - valueElement.appendChild(child); - } - } - } - else { - // value = Core.saveFileToWorkingDir(value); // - // What does copying the file to a new dir - // accomplish? - Element fileEntry = doc.createElementNS(CTL_NS, "file-entry"); - fileEntry.setAttribute("full-path", - URLDecoder.decode(value, StandardCharsets.UTF_8).replace('\\', '/')); - valueElement.appendChild(fileEntry); - } - } - } - else { - valueElement.appendChild(doc.createTextNode(URLDecoder.decode(value, StandardCharsets.UTF_8))); - } - root.appendChild(valueElement); - start = amp + 1; - // System.out.println("key|value: "+key+"|"+value); - } - while (start < end); - - core.setFormResults(doc); - if (popupForm != null) { - popupForm.setVisible(false); - } - } - catch (Throwable t) { - t.printStackTrace(System.out); - } - mainForm.setVisible(false); - } - - } - - private class CustomViewFactory extends HTMLEditorKit.HTMLFactory { - - public javax.swing.text.View create(javax.swing.text.Element elem) { - AttributeSet as = elem.getAttributes(); - HTML.Tag tag = (HTML.Tag) (as.getAttribute(StyleConstants.NameAttribute)); - - if (tag == HTML.Tag.INPUT) { - String type = ""; - String name = ""; - Enumeration e = as.getAttributeNames(); - while (e.hasMoreElements()) { - Object key = e.nextElement(); - if (key == HTML.Attribute.TYPE) { - type = as.getAttribute(key).toString(); - } - if (key == HTML.Attribute.NAME) { - name = as.getAttribute(key).toString(); - } - } - - if (type.equalsIgnoreCase("submit")) { - return new CustomFormView(elem); - } - - if (type.equalsIgnoreCase("file")) { - fileFields.add(name); - } - } - - return super.create(elem); - } - - } - - private class CustomHTMLEditorKit extends HTMLEditorKit { - - static final long serialVersionUID = 5742710765916499050L; - - public javax.swing.text.ViewFactory getViewFactory() { - return new CustomViewFactory(); - } - - } - - private SwingForm(String name) { - setTitle(name); - // setBackground(Color.gray); - getContentPane().setLayout(new BorderLayout()); - - JPanel topPanel = new JPanel(); - topPanel.setLayout(new BorderLayout()); - getContentPane().add(topPanel, BorderLayout.CENTER); - - jedit = new JEditorPane(); - jedit.setEditorKit(new CustomHTMLEditorKit()); - jedit.setEditable(false); - jedit.addHyperlinkListener(this); - - JScrollPane scrollPane = new JScrollPane(); - scrollPane.getViewport().add(jedit, BorderLayout.CENTER); - topPanel.add(scrollPane, BorderLayout.CENTER); - } - - public void hyperlinkUpdate(HyperlinkEvent e) { - if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { - JEditorPane pane = (JEditorPane) e.getSource(); - if (e instanceof HTMLFrameHyperlinkEvent) { - HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e; - HTMLDocument doc = (HTMLDocument) pane.getDocument(); - doc.processHTMLFrameHyperlinkEvent(evt); - } - else { - try { - URL target = e.getURL(); - if (target == null) { - target = new URL(new URL(core.opts.getBaseURI()), e.getDescription()); - } - if (this == popupForm) { - pane.setPage(target); - } - else { - if (popupForm == null) { - popupForm = new SwingForm(popupName); - popupForm.setSize(700, 500); - popupForm.setLocation(this.getX() + 30, this.getY() + 30); - } - popupForm.jedit.setPage(target); - popupForm.setVisible(true); - } - } - catch (Throwable t) { - t.printStackTrace(); - } - } - } - } - - public static void create(String name, int width, int height, TECore core) { - Invoker invoker = new Invoker(); - invoker.name = name; - invoker.width = width; - invoker.height = height; - SwingForm.core = core; - SwingUtilities.invokeLater(invoker); - } - - public static void destroy() { - if (popupForm != null) { - popupForm.dispose(); - popupForm = null; - } - if (mainForm != null) { - mainForm.dispose(); - mainForm = null; - } - } - -} +package com.occamlab.te; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.awt.BorderLayout; +import java.net.URL; +import java.net.URLDecoder; +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Enumeration; + +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; +import javax.swing.text.AttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.text.html.FormView; +import javax.swing.text.html.HTML; +import javax.swing.text.html.HTMLDocument; +import javax.swing.text.html.HTMLEditorKit; +import javax.swing.text.html.HTMLFrameHyperlinkEvent; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import com.occamlab.te.util.DomUtils; + +/** + * Swing-based form created from the content of a <ctl:form> element. This is + * produced when not running the test harness in a web application context. + */ +public class SwingForm extends JFrame implements HyperlinkListener { + + static final long serialVersionUID = 7907599307261079944L; + + public static final String CTL_NS = "http://www.occamlab.com/ctl"; + + private static SwingForm mainForm = null; + + private static SwingForm popupForm = null; + + private static TECore core; + + private static String popupName = Thread.currentThread().getName(); + + private JEditorPane jedit; + + private ArrayList fileFields = new ArrayList<>(); + + private static class Invoker implements Runnable { + + String name; + + int width; + + int height; + + public void run() { + if (mainForm == null) { + mainForm = new SwingForm(name); + } + + String html = core.getFormHtml(); + core.setFormHtml(null); + // For some reason, the tag generated by SAXON screws up the + // JEditorPane, so replace it with a dummy tag. + int i = html.indexOf(" 0) { + html = html.substring(0, i + 1) + "blah" + html.substring(i + 5); + } + + mainForm.jedit.setText(html); + mainForm.setSize(width, height); + mainForm.validate(); + mainForm.setVisible(true); + } + + } + + private class CustomFormView extends FormView { + + public CustomFormView(javax.swing.text.Element elem) { + super(elem); + } + + protected void submitData(String data) { + if (SwingForm.this == popupForm) { + return; + } + + // System.out.println("data: "+data); + try { + String kvps = data + "&="; + int start = 0; + int end = data.length(); + + DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document doc = db.newDocument(); + Element root = doc.createElement("values"); + doc.appendChild(root); + do { + String key; + String value; + + int eq = kvps.indexOf("=", start); + int amp = kvps.indexOf("&", start); + if (amp > eq) { + key = kvps.substring(start, eq); + value = kvps.substring(eq + 1, amp); + } + else { + key = kvps.substring(start, amp); + value = ""; + } + + Element valueElement = doc.createElement("value"); + valueElement.setAttribute("key", key); + // Special case for file inputs + if (fileFields.contains(key)) { + File f = new File(URLDecoder.decode(value, StandardCharsets.UTF_8)); + if (f != null) { + if (core.formParsers.containsKey(key)) { + Element parser = core.formParsers.get(key); + URL url = f.toURI().toURL(); + Element response = core.parse(url.openConnection(), parser, doc); + Element content = DomUtils.getElementByTagName(response, "content"); + if (content != null) { + Element child = DomUtils.getChildElement(content); + if (child != null) { + valueElement.appendChild(child); + } + } + } + else { + // value = Core.saveFileToWorkingDir(value); // + // What does copying the file to a new dir + // accomplish? + Element fileEntry = doc.createElementNS(CTL_NS, "file-entry"); + fileEntry.setAttribute("full-path", + URLDecoder.decode(value, StandardCharsets.UTF_8).replace('\\', '/')); + valueElement.appendChild(fileEntry); + } + } + } + else { + valueElement.appendChild(doc.createTextNode(URLDecoder.decode(value, StandardCharsets.UTF_8))); + } + root.appendChild(valueElement); + start = amp + 1; + // System.out.println("key|value: "+key+"|"+value); + } + while (start < end); + + core.setFormResults(doc); + if (popupForm != null) { + popupForm.setVisible(false); + } + } + catch (Throwable t) { + t.printStackTrace(System.out); + } + mainForm.setVisible(false); + } + + } + + private class CustomViewFactory extends HTMLEditorKit.HTMLFactory { + + public javax.swing.text.View create(javax.swing.text.Element elem) { + AttributeSet as = elem.getAttributes(); + HTML.Tag tag = (HTML.Tag) (as.getAttribute(StyleConstants.NameAttribute)); + + if (tag == HTML.Tag.INPUT) { + String type = ""; + String name = ""; + Enumeration e = as.getAttributeNames(); + while (e.hasMoreElements()) { + Object key = e.nextElement(); + if (key == HTML.Attribute.TYPE) { + type = as.getAttribute(key).toString(); + } + if (key == HTML.Attribute.NAME) { + name = as.getAttribute(key).toString(); + } + } + + if (type.equalsIgnoreCase("submit")) { + return new CustomFormView(elem); + } + + if (type.equalsIgnoreCase("file")) { + fileFields.add(name); + } + } + + return super.create(elem); + } + + } + + private class CustomHTMLEditorKit extends HTMLEditorKit { + + static final long serialVersionUID = 5742710765916499050L; + + public javax.swing.text.ViewFactory getViewFactory() { + return new CustomViewFactory(); + } + + } + + private SwingForm(String name) { + setTitle(name); + // setBackground(Color.gray); + getContentPane().setLayout(new BorderLayout()); + + JPanel topPanel = new JPanel(); + topPanel.setLayout(new BorderLayout()); + getContentPane().add(topPanel, BorderLayout.CENTER); + + jedit = new JEditorPane(); + jedit.setEditorKit(new CustomHTMLEditorKit()); + jedit.setEditable(false); + jedit.addHyperlinkListener(this); + + JScrollPane scrollPane = new JScrollPane(); + scrollPane.getViewport().add(jedit, BorderLayout.CENTER); + topPanel.add(scrollPane, BorderLayout.CENTER); + } + + public void hyperlinkUpdate(HyperlinkEvent e) { + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + JEditorPane pane = (JEditorPane) e.getSource(); + if (e instanceof HTMLFrameHyperlinkEvent) { + HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e; + HTMLDocument doc = (HTMLDocument) pane.getDocument(); + doc.processHTMLFrameHyperlinkEvent(evt); + } + else { + try { + URL target = e.getURL(); + if (target == null) { + target = new URL(new URL(core.opts.getBaseURI()), e.getDescription()); + } + if (this == popupForm) { + pane.setPage(target); + } + else { + if (popupForm == null) { + popupForm = new SwingForm(popupName); + popupForm.setSize(700, 500); + popupForm.setLocation(this.getX() + 30, this.getY() + 30); + } + popupForm.jedit.setPage(target); + popupForm.setVisible(true); + } + } + catch (Throwable t) { + t.printStackTrace(); + } + } + } + } + + public static void create(String name, int width, int height, TECore core) { + Invoker invoker = new Invoker(); + invoker.name = name; + invoker.width = width; + invoker.height = height; + SwingForm.core = core; + SwingUtilities.invokeLater(invoker); + } + + public static void destroy() { + if (popupForm != null) { + popupForm.dispose(); + popupForm = null; + } + if (mainForm != null) { + mainForm.dispose(); + mainForm = null; + } + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/TEClassLoader.java b/teamengine-core/src/main/java/com/occamlab/te/TEClassLoader.java index abde13e39..69b4bdc28 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/TEClassLoader.java +++ b/teamengine-core/src/main/java/com/occamlab/te/TEClassLoader.java @@ -1,162 +1,182 @@ -/**************************************************************************** - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): No additional contributors to date - - ****************************************************************************/ -package com.occamlab.te; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.Vector; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class TEClassLoader extends ClassLoader { - - List resourcesDirs; - - ClassLoader cl; - - HashSet registeredClasses; - - private static Logger logger = Logger.getLogger("com.occamlab.te.TEClassLoader"); - - private static List resourcesDirsList(File resourcesDir) { - List resourcesDirs = new ArrayList<>(); - if (resourcesDir != null) { - resourcesDirs.add(resourcesDir); - } - return resourcesDirs; - } - - public TEClassLoader() { - this(resourcesDirsList(null)); - } - - public TEClassLoader(File resourcesDir) { - this(resourcesDirsList(resourcesDir)); - } - - public TEClassLoader(List resourcesDirs) { - this.resourcesDirs = resourcesDirs; - cl = Thread.currentThread().getContextClassLoader(); - registeredClasses = new HashSet<>(); - registeredClasses.add("com.occamlab.te.parsers.HTTPParser"); - registeredClasses.add("com.occamlab.te.parsers.SchematronValidatingParser"); - registeredClasses.add("com.occamlab.te.parsers.XMLValidatingParser"); - registeredClasses.add("com.occamlab.te.parsers.XSLTransformationParser"); - } - - public URL getResource(String name) { - for (File resourcesDir : resourcesDirs) { - File f = new File(resourcesDir, name); - try { - return f.toURI().toURL(); - } - catch (MalformedURLException e) { - logger.log(Level.SEVERE, "getResource", e); - } - } - return cl.getResource(name); - } - - public InputStream getResourceAsStream(String name) { - if (resourcesDirs.size() > 0) { - URL u = getResource(name); - if (u != null) { - try { - return u.openStream(); - } - catch (IOException e) { - } - } - } - return cl.getResourceAsStream(name); - } - - public Enumeration getResources(String name) throws IOException { - Enumeration resources = cl.getResources(name); - URL u = getResource(name); - if (resourcesDirs.size() > 0 && u != null) { - Vector v = new Vector<>(); - v.add(u); - while (resources.hasMoreElements()) { - v.add(resources.nextElement()); - } - return v.elements(); - } - return resources; - } - - // public void registerClass(String name) { - // if (!registeredClasses.contains(name)) { - // registeredClasses.add(name); - // } - // } - - private Class readClass(String name) { - String filename = name.replace('.', '/') + ".class"; - try { - InputStream in = getResourceAsStream(filename); - ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); - int i = in.read(); - while (i >= 0) { - baos.write(i); - i = in.read(); - } - in.close(); - return defineClass(name, baos.toByteArray(), 0, baos.size()); - } - catch (Exception e) { - logger.log(Level.SEVERE, "readClass", e); - return null; - } - } - - public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - Class c = findLoadedClass(name); - if (c == null) { - for (String registeredClass : registeredClasses) { - if (name.startsWith(registeredClass)) { - c = readClass(name); - break; - } - } - } - if (c == null) { - try { - c = cl.loadClass(name); - } - catch (ClassNotFoundException e) { - } - } - if (c == null) { - c = readClass(name); - } - if (c == null) { - throw new ClassNotFoundException(name); - } - else { - if (resolve) { - resolveClass(c); - } - return c; - } - } - -} +/**************************************************************************** + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): No additional contributors to date + + ****************************************************************************/ +package com.occamlab.te; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class TEClassLoader extends ClassLoader { + + List resourcesDirs; + + ClassLoader cl; + + HashSet registeredClasses; + + private static Logger logger = Logger.getLogger("com.occamlab.te.TEClassLoader"); + + private static List resourcesDirsList(File resourcesDir) { + List resourcesDirs = new ArrayList<>(); + if (resourcesDir != null) { + resourcesDirs.add(resourcesDir); + } + return resourcesDirs; + } + + public TEClassLoader() { + this(resourcesDirsList(null)); + } + + public TEClassLoader(File resourcesDir) { + this(resourcesDirsList(resourcesDir)); + } + + public TEClassLoader(List resourcesDirs) { + this.resourcesDirs = resourcesDirs; + cl = Thread.currentThread().getContextClassLoader(); + registeredClasses = new HashSet<>(); + registeredClasses.add("com.occamlab.te.parsers.HTTPParser"); + registeredClasses.add("com.occamlab.te.parsers.SchematronValidatingParser"); + registeredClasses.add("com.occamlab.te.parsers.XMLValidatingParser"); + registeredClasses.add("com.occamlab.te.parsers.XSLTransformationParser"); + } + + public URL getResource(String name) { + for (File resourcesDir : resourcesDirs) { + File f = new File(resourcesDir, name); + try { + return f.toURI().toURL(); + } + catch (MalformedURLException e) { + logger.log(Level.SEVERE, "getResource", e); + } + } + return cl.getResource(name); + } + + public InputStream getResourceAsStream(String name) { + if (resourcesDirs.size() > 0) { + URL u = getResource(name); + if (u != null) { + try { + return u.openStream(); + } + catch (IOException e) { + } + } + } + return cl.getResourceAsStream(name); + } + + public Enumeration getResources(String name) throws IOException { + Enumeration resources = cl.getResources(name); + URL u = getResource(name); + if (resourcesDirs.size() > 0 && u != null) { + Vector v = new Vector<>(); + v.add(u); + while (resources.hasMoreElements()) { + v.add(resources.nextElement()); + } + return v.elements(); + } + return resources; + } + + // public void registerClass(String name) { + // if (!registeredClasses.contains(name)) { + // registeredClasses.add(name); + // } + // } + + private Class readClass(String name) { + String filename = name.replace('.', '/') + ".class"; + try { + InputStream in = getResourceAsStream(filename); + ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); + int i = in.read(); + while (i >= 0) { + baos.write(i); + i = in.read(); + } + in.close(); + return defineClass(name, baos.toByteArray(), 0, baos.size()); + } + catch (Exception e) { + logger.log(Level.SEVERE, "readClass", e); + return null; + } + } + + public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + Class c = findLoadedClass(name); + if (c == null) { + for (String registeredClass : registeredClasses) { + if (name.startsWith(registeredClass)) { + c = readClass(name); + break; + } + } + } + if (c == null) { + try { + c = cl.loadClass(name); + } + catch (ClassNotFoundException e) { + } + } + if (c == null) { + c = readClass(name); + } + if (c == null) { + throw new ClassNotFoundException(name); + } + else { + if (resolve) { + resolveClass(c); + } + return c; + } + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/TECore.java b/teamengine-core/src/main/java/com/occamlab/te/TECore.java index 42af6c1be..607919f0c 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/TECore.java +++ b/teamengine-core/src/main/java/com/occamlab/te/TECore.java @@ -1,2592 +1,2612 @@ -/** - * ************************************************************************** - * - * The Original Code is TEAM Engine. - * - * The Initial Developer of the Original Code is Northrop Grumman Corporation - * jointly with The National Technology Alliance. Portions created by Northrop - * Grumman Corporation are Copyright (C) 2005-2006, Northrop Grumman - * Corporation. All Rights Reserved. - * - * Contributor(s): - * S. Gianfranceschi (Intecs): Added the SOAP suport - * C. Heazel (WiSC): Added Fortify adjudication changes - * - *************************************************************************** - */ -package com.occamlab.te; - -import java.io.BufferedWriter; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintStream; -import java.io.PrintWriter; -import java.io.RandomAccessFile; -import java.io.StringReader; -import java.io.StringWriter; -import java.lang.reflect.Method; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLConnection; -import java.nio.charset.StandardCharsets; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Stack; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.zip.CRC32; - -import javax.xml.XMLConstants; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMResult; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; - -import com.occamlab.te.form.ImageHandler; -import com.occamlab.te.html.EarlToHtmlTransformation; - -import net.sf.saxon.dom.NodeOverNodeInfo; -import net.sf.saxon.expr.XPathContext; -import net.sf.saxon.expr.XPathContextMajor; -import net.sf.saxon.instruct.Executable; -import net.sf.saxon.om.NodeInfo; -import net.sf.saxon.s9api.Axis; -import net.sf.saxon.s9api.QName; -import net.sf.saxon.s9api.S9APIUtils; -import net.sf.saxon.s9api.SaxonApiException; -import net.sf.saxon.s9api.Serializer; -import net.sf.saxon.s9api.XdmAtomicValue; -import net.sf.saxon.s9api.XdmDestination; -import net.sf.saxon.s9api.XdmItem; -import net.sf.saxon.s9api.XdmNode; -import net.sf.saxon.s9api.XdmNodeKind; -import net.sf.saxon.s9api.XdmSequenceIterator; -import net.sf.saxon.s9api.XsltExecutable; -import net.sf.saxon.s9api.XsltTransformer; -import net.sf.saxon.trans.XPathException; - -import org.w3c.dom.Attr; -import org.w3c.dom.Comment; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.w3c.dom.Text; - -import com.occamlab.te.index.FunctionEntry; -import com.occamlab.te.index.Index; -import com.occamlab.te.index.ParserEntry; -import com.occamlab.te.index.ProfileEntry; -import com.occamlab.te.index.SuiteEntry; -import com.occamlab.te.index.TemplateEntry; -import com.occamlab.te.index.TestEntry; -import com.occamlab.te.saxon.ObjValue; -import com.occamlab.te.util.Constants; -import com.occamlab.te.util.DomUtils; -import com.occamlab.te.util.IOUtils; -import com.occamlab.te.util.LogUtils; -import com.occamlab.te.util.Misc; -import com.occamlab.te.util.SoapUtils; -import com.occamlab.te.util.StringUtils; -import com.occamlab.te.util.URLConnectionUtils; -import com.occamlab.te.util.TEPath; - -import static java.util.logging.Level.FINE; -import static java.util.logging.Level.SEVERE; - -/** - * Provides various utility methods to support test execution and logging. Primary ones - * include implementation and execution of ctl:suite, ctl:profile, ctl:test, ctl:function, - * ctl:request and ctl:soap-request instructions, and invocation of any parsers specified - * therein. - * - */ -public class TECore implements Runnable { - - private static final Logger LOGR = Logger.getLogger(TECore.class.getName()); - - public static final String SOAP_V_1_1 = "1.1"; - - public static final String SOAP_V_1_2 = "1.2"; - - Engine engine; // Engine object - - Index index; - - public static int testCount = 0; - - int reTestCount = 0; - - public static int methodCount = 0; - - String testName = ""; - - public static String nameOfTest = ""; - - final RuntimeOptions opts; - - String testServletURL = null; - - volatile PrintStream out; // Console destination - - boolean web = false; // True when running as a servlet - - RecordedForms recordedForms; - - private String testPath; // Uniquely identifies a test instance - - String fnPath = ""; // Uniquely identifies an XSL function instance within a - - // test instance - String indent = ""; // Contains the appropriate number of spaces for the - - // current indent level - String contextLabel = ""; // Current context label set by ctl:for-each - - String testType = "Mandatory"; // Type of current test - - String defaultResultName = "Pass"; // Default result name for current test - - int defaultResult = PASS; // Default result for current test - - ArrayList media = new ArrayList<>(); - - public File dirPath; - - Document prevLog = null; // Log document for current test from previous test - - // execution (resume and retest modes only) - // Log document for suite to enable use of getLogCache by profile test - Document suiteLog = null; - - public static String pathURL = ""; - - public static String assertionMsz = ""; - - public static String messageTest = ""; - - PrintWriter logger = null; // Logger for current test - - volatile String formHtml; // HTML representation for an active form - - volatile Document formResults; // Holds form results until they are - - // retrieved - Map formParsers = new HashMap<>(); - - Map functionInstances = new HashMap<>(); - - Map parserInstances = new HashMap<>(); - - Map parserMethods = new HashMap<>(); - - LinkedList testStack = new LinkedList<>(); - - volatile boolean threadComplete = false; - - volatile boolean stop = false; - - volatile ByteArrayOutputStream threadOutput; - - private Stack fnCallStack; - - public static final int CONTINUE = -1; - - public static final int BEST_PRACTICE = 0; - - public static final int PASS = 1; - - public static final int NOT_TESTED = 2; - - public static final int SKIPPED = 3; - - public static final int WARNING = 4; - - public static final int INHERITED_FAILURE = 5; - - public static final int FAIL = 6; - - public static final String MSG_CONTINUE = "Inconclusive! Continue Test"; - - public static final String MSG_BEST_PRACTICE = "Passed as Best Practice"; - - public static final String MSG_PASS = "Passed"; - - public static final String MSG_NOT_TESTED = "Not Tested"; - - public static final String MSG_SKIPPED = "Skipped - Prerequisites not satisfied"; - - public static final String MSG_WARNING = "Warning"; - - public static final String MSG_INHERITED_FAILURE = "Failed - Inherited"; - - public static final String MSG_FAIL = "Failed"; - - public static final int MANDATORY = 0; - - public static final int MANDATORY_IF_IMPLEMENTED = 1; - - public static final int OPTIONAL = 2; - - static final String XSL_NS = Test.XSL_NS; - static final String CTL_NS = Test.CTL_NS; - static final String TE_NS = Test.TE_NS; - static final String INDENT = " "; - static final QName TECORE_QNAME = new QName("te", TE_NS, "core"); - static final QName TEPARAMS_QNAME = new QName("te", TE_NS, "params"); - static final QName LOCALNAME_QNAME = new QName("local-name"); - static final QName LABEL_QNAME = new QName("label"); - static final String HEADER_BLOCKS = "header-blocks"; - - private static Logger jlogger = Logger.getLogger("com.occamlab.te.TECore"); - - public static DocumentBuilderFactory icFactory; - - public static DocumentBuilder icBuilder; - - public static Document doc; - - public static Element mainRootElement; - - public static DocumentBuilderFactory icFactoryClause; - - public static DocumentBuilder icBuilderClause; - - public static Document docClause; - - public static Element mainRootElementClause; - - public static String TESTNAME = ""; - - public static int rootNo = 0; - - public static String Clause = ""; - - public static String Purpose = ""; - - public static ArrayList rootTestName = new ArrayList<>(); - - public Document userInputs = null; - - public Boolean supportHtmlReport = false; - - public final ImageHandler imageHandler; - - public TECore() { - this.opts = null; - this.imageHandler = null; - } - - public TECore(Engine engine, Index index, RuntimeOptions opts) { - this.engine = engine; - this.index = index; - this.opts = opts; - this.recordedForms = new RecordedForms(opts.getRecordedForms()); - this.testPath = opts.getSessionId(); - this.out = System.out; - this.imageHandler = new ImageHandler(opts.getLogDir(), opts.getSessionId()); - this.fnCallStack = new Stack<>(); - } - - public TestEntry getParentTest() { - if (testStack.size() < 2) { - return testStack.peek(); - } - else { - return testStack.get(1); - } - } - - public String getParamsXML(List params) throws Exception { - String paramsXML = ""; - for (int i = 0; i < params.size(); i++) { - String param = params.get(i); - String name = param.substring(0, param.indexOf('=')); - String value = param.substring(param.indexOf('=') + 1); - if (params.get(i).indexOf('=') != 0) { - paramsXML += ""; - paramsXML += ""; - paramsXML += ""; - } - } - paramsXML += ""; - // System.out.println("paramsXML: "+paramsXML); - return paramsXML; - } - - XPathContext getXPathContext(TestEntry test, String sourcesName, XdmNode contextNode) throws Exception { - XPathContext context = null; - if (test.usesContext() && contextNode != null) { - XsltExecutable xe = engine.loadExecutable(test, sourcesName); - Executable ex = xe.getUnderlyingCompiledStylesheet().getExecutable(); - context = new XPathContextMajor(contextNode.getUnderlyingNode(), ex); - } - return context; - } - - // Execute tests - public void execute() throws Exception { - try { - TestEntry grandParent = new TestEntry(); - grandParent.setType("Mandatory"); - grandParent.setResult(CONTINUE); - testStack.push(grandParent); - String sessionId = opts.getSessionId(); - int mode = opts.getMode(); - ArrayList params = opts.getParams(); - - if (mode == Test.RESUME_MODE) { - reexecute_test(sessionId); - } - else if (mode == Test.REDO_FROM_CACHE_MODE) { - reexecute_test(sessionId); - } - else if (mode == Test.RETEST_MODE) { - for (String testPath : opts.getTestPaths()) { - reexecute_test(testPath); - } - } - else if (mode == Test.TEST_MODE || mode == Test.DOC_MODE) { - String testName = opts.getTestName(); - if (!testName.isEmpty()) { - // NOTE: getContextNode() always returns null - XdmNode contextNode = opts.getContextNode(); - execute_test(testName, params, contextNode); - } - else { - String suiteName = opts.getSuiteName(); - List profiles = opts.getProfiles(); - if (!suiteName.isEmpty() || profiles.size() == 0) { - execute_suite(suiteName, params); - } - if (profiles.contains("*")) { - for (String profile : index.getProfileKeys()) { - try { - execute_profile(profile, params, false); - } - catch (Exception e) { - jlogger.log(Level.WARNING, e.getMessage(), e.getCause()); - } - } - } - else { - for (String profile : profiles) { - try { - execute_profile(profile, params, true); - } - catch (Exception e) { - jlogger.log(Level.WARNING, e.getMessage(), e.getCause()); - } - } - } - } - } - else { - throw new Exception("Unsupported mode"); - } - } - finally { - if (!web) { - SwingForm.destroy(); - } - if (opts.getLogDir() != null) { - // Create xml execution report file - LogUtils.createFullReportLog(opts.getLogDir().getAbsolutePath() + File.separator + opts.getSessionId()); - File resultsDir = new File(opts.getLogDir(), opts.getSessionId()); - if (supportHtmlReport) { - Map testInputMap = new HashMap<>(); - testInputMap = extractTestInputs(userInputs, opts); - - if (!new File(resultsDir, "testng").exists() && null != testInputMap) { - /* - * Transform CTL result into EARL result, when the CTL test is - * executed through the webapp. - */ - try { - - File testLog = new File(resultsDir, "report_logs.xml"); - CtlEarlReporter report = new CtlEarlReporter(); - - if (null != opts.getSourcesName()) { - report.generateEarlReport(resultsDir, testLog, opts.getSourcesName(), testInputMap); - } - } - catch (IOException iox) { - throw new RuntimeException("Failed to serialize EARL results to " + iox); - } - } - } - } - } - } - - public void reexecute_test(String testPath) throws Exception { - File deleteExistingResultDir = new File( - opts.getLogDir() + File.separator + testPath + File.separator + "result"); - if (deleteExistingResultDir.exists()) { - Misc.deleteDir(deleteExistingResultDir); - } - File deleteExistingTestngDir = new File( - opts.getLogDir() + File.separator + testPath + File.separator + "testng"); - if (deleteExistingTestngDir.exists()) { - Misc.deleteDir(deleteExistingTestngDir); - } - Document log = LogUtils.readLog(opts.getLogDir(), testPath); - String testId = LogUtils.getTestIdFromLog(log); - TestEntry test = index.getTest(testId); - net.sf.saxon.s9api.DocumentBuilder builder = engine.getBuilder(); - XdmNode paramsNode = LogUtils.getParamsFromLog(builder, log); - XdmNode contextNode = LogUtils.getContextFromLog(builder, log); - XPathContext context = getXPathContext(test, opts.getSourcesName(), contextNode); - setTestPath(testPath); - executeTest(test, paramsNode, context); - if (testPath.equals(opts.getSessionId())) { - // Profile not executed in retest mode - suiteLog = LogUtils.readLog(opts.getLogDir(), testPath); - ArrayList params = opts.getParams(); - List profiles = opts.getProfiles(); - if (profiles.contains("*")) { - for (String profile : index.getProfileKeys()) { - try { - execute_profile(profile, params, false); - } - catch (Exception e) { - jlogger.log(Level.WARNING, e.getMessage(), e.getCause()); - } - } - } - else { - for (String profile : profiles) { - try { // 2011-12-21 PwD - execute_profile(profile, params, true); - } - catch (Exception e) { - jlogger.log(Level.WARNING, e.getMessage(), e.getCause()); - } - } - } - } - } - - public int execute_test(String testName, List params, XdmNode contextNode) throws Exception { - if (LOGR.isLoggable(FINE)) { - String logMsg = String.format("Preparing test %s for execution, using params:%n %s", testName, params); - LOGR.fine(logMsg); - } - TestEntry test = index.getTest(testName); - if (test == null) { - throw new Exception("Error: Test " + testName + " not found."); - } - XdmNode paramsNode = engine.getBuilder().build(new StreamSource(new StringReader(getParamsXML(params)))); - if (contextNode == null && test.usesContext()) { - String contextNodeXML = "" + test.getContext() + ""; - contextNode = engine.getBuilder().build(new StreamSource(new StringReader(contextNodeXML))); - } - XPathContext context = getXPathContext(test, opts.getSourcesName(), contextNode); - return executeTest(test, paramsNode, context); - } - - public void execute_suite(String suiteName, List params) throws Exception { - SuiteEntry suite = null; - if (suiteName == null || suiteName.isEmpty()) { - Iterator it = index.getSuiteKeys().iterator(); - if (!it.hasNext()) { - throw new Exception("Error: No suites in sources."); - } - suite = index.getSuite(it.next()); - if (it.hasNext()) { - throw new Exception( - "Error: Suite name must be specified since there is more than one suite in sources."); - } - } - else { - suite = index.getSuite(suiteName); - if (suite == null) { - throw new Exception("Error: Suite " + suiteName + " not found."); - } - } - defaultResultName = suite.getDefaultResult(); - defaultResult = defaultResultName.equals("BestPractice") ? BEST_PRACTICE : PASS; - testStack.peek().setDefaultResult(defaultResult); - testStack.peek().setResult(defaultResult); - - ArrayList kvps = new ArrayList<>(params); - Document form = suite.getForm(); - if (form != null) { - Document results = (Document) form(form, suite.getId()); - for (Element value : DomUtils.getElementsByTagName(results, "value")) { - kvps.add(value.getAttribute("key") + "=" + value.getTextContent()); - } - } - String name = suite.getPrefix() + ":" + suite.getLocalName(); - out.println( - "Testing suite " + name + " in " + getMode() + " with defaultResult of " + defaultResultName + " ..."); - RecordTestResult recordTestResult = new RecordTestResult(); - if (opts.getLogDir() != null) { - recordTestResult.recordingStartCheck(suite); - recordTestResult.recordingStartClause(suite); - } - setIndentLevel(1); - int result = execute_test(suite.getStartingTest().toString(), kvps, null); - recordTestResult.detailTestPath(); - reTestCount = 0; - out.print("Suite " + suite.getPrefix() + ":" + suite.getLocalName() + " "); - if (result == TECore.FAIL || result == TECore.INHERITED_FAILURE) { - out.println(MSG_FAIL); - } - else if (result == TECore.WARNING) { - out.println(MSG_WARNING); - } - else if (result == TECore.BEST_PRACTICE) { - out.println(MSG_BEST_PRACTICE); - } - else { - out.println(MSG_PASS); - } - if (opts.getLogDir() != null) { - recordTestResult.saveRecordingClause(suite, dirPath); - recordTestResult.saveRecordingData(suite, dirPath); - } - } - - public void execute_profile(String profileName, List params, boolean required) throws Exception { - ProfileEntry profile = index.getProfile(profileName); - if (profile == null) { - throw new Exception("Error: Profile " + profileName + " not found."); - } - SuiteEntry suite = index.getSuite(profile.getBaseSuite()); - if (suite == null) { - throw new Exception("Error: The base suite (" + profile.getBaseSuite().toString() + ") for the profile (" - + profileName + ") not found."); - } - String sessionId = opts.getSessionId(); - Document log = LogUtils.readLog(opts.getLogDir(), sessionId); - if (log == null) { - execute_suite(suite.getId(), params); - log = LogUtils.readLog(opts.getLogDir(), sessionId); - } - suiteLog = log; - String testId = LogUtils.getTestIdFromLog(log); - List baseParams = LogUtils.getParamListFromLog(engine.getBuilder(), log); - TestEntry test = index.getTest(testId); - if (suite.getStartingTest().equals(test.getQName())) { - ArrayList kvps = new ArrayList<>(); - kvps.addAll(baseParams); - kvps.addAll(params); - Document form = profile.getForm(); - if (form != null) { - Document results = (Document) form(form, profile.getId()); - for (Element value : DomUtils.getElementsByTagName(results, "value")) { - kvps.add(value.getAttribute("key") + "=" + value.getTextContent()); - } - } - setTestPath(sessionId + "/" + profile.getLocalName()); - String name = profile.getPrefix() + ":" + profile.getLocalName(); - out.println("\nTesting profile " + name + "..."); - Document baseLog = LogUtils.makeTestList(opts.getLogDir(), sessionId, profile.getExcludes()); - Element baseTest = DomUtils.getElement(baseLog); - // out.println(DomUtils.serializeNode(baseLog)); - out.print(TECore.INDENT + "Base tests from suite " + suite.getPrefix() + ":" + suite.getLocalName() + " "); - String summary = "Not complete"; - if ("yes".equals(baseTest.getAttribute("complete"))) { - int baseResult = Integer.parseInt(baseTest.getAttribute("result")); - summary = getResultDescription(baseResult); - } - out.println(summary); - setIndentLevel(1); - String defaultResultName = profile.getDefaultResult(); - defaultResult = defaultResultName.equals("BestPractice") ? BEST_PRACTICE : PASS; - out.println("\nExecuting profile " + name + " with defaultResult of " + defaultResultName + "..."); - int result = execute_test(profile.getStartingTest().toString(), kvps, null); - out.print("Profile " + profile.getPrefix() + ":" + profile.getLocalName() + " "); - summary = getResultDescription(result); - out.println(summary); - } - else { - if (required) { - throw new Exception( - "Error: Profile " + profileName + " is not a valid profile for session " + sessionId + "."); - } - } - } - - public XdmNode executeTemplate(TemplateEntry template, XdmNode params, XPathContext context) throws Exception { - if (stop) { - throw new Exception("Execution was stopped by the user."); - } - XsltExecutable executable = engine.loadExecutable(template, opts.getSourcesName()); - XsltTransformer xt = executable.load(); - XdmDestination dest = new XdmDestination(); - xt.setDestination(dest); - if (template.usesContext() && context != null) { - xt.setSource((NodeInfo) context.getContextItem()); - } - else { - xt.setSource(new StreamSource(new StringReader(""))); - } - xt.setParameter(TECORE_QNAME, new ObjValue(this)); - if (params != null) { - xt.setParameter(TEPARAMS_QNAME, params); - } - // test may set global verdict, e.g. by calling ctl:fail - if (LOGR.isLoggable(FINE)) { - LOGR.log(FINE, "Executing TemplateEntry {0}" + template.getQName()); - } - xt.transform(); - XdmNode ret = dest.getXdmNode(); - if (ret != null && LOGR.isLoggable(FINE)) { - LOGR.log(FINE, "Output:\n" + ret.toString()); - } - return ret; - } - - static String getLabel(XdmNode n) { - String label = n.getAttributeValue(LABEL_QNAME); - if (label == null) { - XdmNode value = (XdmNode) n.axisIterator(Axis.CHILD).next(); - XdmItem childItem = null; - try { - childItem = value.axisIterator(Axis.CHILD).next(); - } - catch (Exception e) { - // Not an error - } - if (childItem == null) { - XdmSequenceIterator it = value.axisIterator(Axis.ATTRIBUTE); - if (it.hasNext()) { - label = it.next().getStringValue(); - } - else { - label = ""; - } - } - else if (childItem.isAtomicValue()) { - label = childItem.getStringValue(); - } - else if (childItem instanceof XdmNode) { - XdmNode n2 = (XdmNode) childItem; - if (n2.getNodeKind() == XdmNodeKind.ELEMENT) { - label = "<" + n2.getNodeName().toString() + ">"; - } - else { - label = n2.toString(); - } - } - } - return label; - } - - String getAssertionValue(String text, XdmNode paramsVar) { - if (text.indexOf("$") < 0) { - return text; - } - String newText = text; - XdmNode params = (XdmNode) paramsVar.axisIterator(Axis.CHILD).next(); - XdmSequenceIterator it = params.axisIterator(Axis.CHILD); - while (it.hasNext()) { - XdmNode n = (XdmNode) it.next(); - QName qname = n.getNodeName(); - if (qname != null) { - String tagname = qname.getLocalName(); - if (tagname.equals("param")) { - String name = n.getAttributeValue(LOCALNAME_QNAME); - String label = getLabel(n); - newText = StringUtils.replaceAll(newText, "{$" + name + "}", label); - } - } - } - newText = StringUtils.replaceAll(newText, "{$context}", contextLabel); - return newText; - } - - static String getResultDescription(int result) { - if (result == CONTINUE) { - return MSG_CONTINUE; - } - else if (result == BEST_PRACTICE) { - return MSG_BEST_PRACTICE; - } - else if (result == PASS) { - return MSG_PASS; - } - else if (result == NOT_TESTED) { - return MSG_NOT_TESTED; - } - else if (result == SKIPPED) { - return MSG_SKIPPED; - } - else if (result == WARNING) { - return MSG_WARNING; - } - else if (result == INHERITED_FAILURE) { - return MSG_INHERITED_FAILURE; - } - else { - return MSG_FAIL; - } - } - - /** - * Executes a test implemented as an XSLT template. - * @param test Provides information about the test (gleaned from an entry in the test - * suite index). - * @param params A node representing test run arguments. - * @param context A context in which the template is evaluated. - * @return An integer value indicating the test result. - * @throws Exception If any error arises while executing the test. - */ - public int executeTest(TestEntry test, XdmNode params, XPathContext context) throws Exception { - testType = test.getType(); - // It is possible to get here without setting testPath. Make sure it is set. - if (testPath == null) - testPath = opts.getSessionId(); - defaultResult = test.getDefaultResult(); - defaultResultName = (defaultResult == BEST_PRACTICE) ? "BestPractice" : "Pass"; - Document oldPrevLog = prevLog; - if (opts.getMode() == Test.RESUME_MODE) { - prevLog = readLog(); - } - else if (opts.getMode() == Test.REDO_FROM_CACHE_MODE) { - prevLog = readLog(); - } - else { - prevLog = null; - } - String assertion = getAssertionValue(test.getAssertion(), params); - // seperate two sub test. - out.println( - "******************************************************************************************************************************"); - out.print(indent + "Testing "); - out.print(test.getName() + " type " + test.getType()); - - // Check test is contain client test main layer or not - - if (rootTestName != null && rootTestName.size() > 0) { - for (int i = 0; i < rootTestName.size(); i++) { - if ((test.getName()).contains(rootTestName.get(i))) { - methodCount = methodCount + 1; - } - } - } - - out.print(" in " + getMode() + " with defaultResult " + defaultResultName + " "); - String testName = test.getName() + " type " + test.getType(); - System.setProperty("TestName", testName); - out.println("(" + testPath + ")..."); - if (opts.getLogDir() != null) { - String logDir = opts.getLogDir() + "/" + testPath.split("/")[0]; - // Fortify Mod: Add TEPath validation of the log directory path - TEPath tpath = new TEPath(logDir); - // create log directory - if (tpath.isValid() && "True".equals(System.getProperty("Record"))) { - dirPath = new File(logDir + "/test_data"); - if (!dirPath.exists()) { - if (!dirPath.mkdir()) { - System.out.println("Failed to create Error Log!"); - } - } - } - } - - // Delete files for coverage report. - if (reTestCount == 0) { - if (getMode().contains("Retest")) { - if (null != dirPath) { - if (dirPath.isDirectory()) { - File[] files = dirPath.listFiles(); - if (files != null && files.length > 0) { - for (File aFile : files) { - aFile.delete(); - } - } - dirPath.delete(); - } - else { - dirPath.delete(); - } - } - reTestCount = 1; - } - } - String oldIndent = indent; - indent += INDENT; - if (test.usesContext()) { - out.println(indent + "Context: " + test.getContext()); - } - out.println(indent + "Assertion: " + assertion); - assertionMsz = assertion; - PrintWriter oldLogger = logger; - if (opts.getLogDir() != null) { - logger = createLog(); - logger.println(""); - logger.print(""); - logger.println("" + StringUtils.escapeXML(assertion) + ""); - if (params != null) { - logger.println(params.toString()); - pathURL = params.toString(); - } - if (test.usesContext()) { - logger.print(""); - logger.print(""); - logger.print(test.getContext()); - logger.print(""); - logger.println(""); - } - logger.println(""); - logger.flush(); - } - - test.setResult(CONTINUE); - RecordTestResult recordTestResult = new RecordTestResult(); - recordTestResult.storeStartTestDetail(test, dirPath); - try { - testStack.push(test); - executeTemplate(test, params, context); - if (test.getResult() == CONTINUE) { - test.setResult(defaultResult); - } - } - catch (SaxonApiException e) { - jlogger.log(SEVERE, e.getMessage()); - DateFormat dateFormat = new SimpleDateFormat(Constants.YYYY_M_MDD_H_HMMSS); - Date date = new Date(); - try { - String path = System.getProperty("PATH") + "/error_log"; - File file = new File(path); - if (!file.exists()) { - if (!file.mkdir()) { - System.out.println("Failed to create Error Log!"); - } - } - file = new File(path, "log.txt"); - if (!file.exists()) { - try { - boolean fileCreated = file.createNewFile(); - } - catch (IOException ioe) { - System.out.println("Error while creating empty file: " + ioe); - } - } - OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file, true), - StandardCharsets.UTF_8); - BufferedWriter fbw = new BufferedWriter(writer); - fbw.write(dateFormat.format(date) + " ERROR"); - fbw.newLine(); - fbw.write("Test Name : " + System.getProperty("TestName")); - fbw.newLine(); - fbw.write("Failed to execute the extension function: "); - e.printStackTrace(new PrintWriter(fbw)); - fbw.newLine(); - fbw.close(); - } - catch (IOException exep) { - System.out.println("Error: " + e.getMessage()); - } - if (logger != null) { - logger.println(""); - } - test.setResult(FAIL); - } - finally { - updateParentTestResult(test); - testStack.pop(); - if (logger != null) { - logger.println(""); - - if (test.isConformanceClass()) { - logger.println(""); - supportHtmlReport = true; - } - logger.println(""); - logger.flush(); - logger.close(); - } - // Add missing info in the log.xml E.g. endtag ' or' endtest ''. - if (opts.getLogDir() != null && testPath != null) { - String logDir = opts.getLogDir() + "/" + testPath; - addMissingInfo(logDir, test); - } - } - // Create node which contain all test detail. - if ("True".equals(System.getProperty("Record"))) { - mainRootElement.appendChild(RecordTestResult.getMethod()); - } - assertionMsz = ""; - pathURL = ""; - messageTest = ""; - logger = oldLogger; - prevLog = oldPrevLog; - indent = oldIndent; - DateFormat dateFormat = new SimpleDateFormat(Constants.YYYY_M_MDD_H_HMMSS); - Calendar cal = Calendar.getInstance(); - out.println(indent + "Test " + test.getName() + " " + getResultDescription(test.getResult())); - recordTestResult.storeFinalTestDetail(test, dateFormat, cal, dirPath); - if (LOGR.isLoggable(FINE)) { - String msg = String.format("Executed test %s - Verdict: %s", test.getLocalName(), - getResultDescription(test.getResult())); - LOGR.log(FINE, msg); - } - - return test.getResult(); - } - - public void addMissingInfo(String dir, TestEntry test) { - - String logdir = dir + File.separator + "log.xml"; - DocumentBuilderFactory dbf = null; - DocumentBuilder docBuilder = null; - Document doc = null; - File logfile = new File(logdir); - try { - dbf = DocumentBuilderFactory.newInstance(); - docBuilder = dbf.newDocumentBuilder(); - docBuilder.setErrorHandler(null); - doc = docBuilder.parse(logfile); - - } - catch (Exception e) { - - try { - FileWriter fw = new FileWriter(logdir, true); - BufferedWriter bw = new BufferedWriter(fw); - PrintWriter out = new PrintWriter(bw); - out.println(""); - out.close(); - bw.close(); - doc = docBuilder.parse(logfile); - } - catch (Exception ex) { - throw new RuntimeException("Unable to update missing information in " + logdir); - } - - } - - NodeList nl = doc.getElementsByTagName("endtest"); - if (nl.getLength() == 0) { - - Element root = doc.getDocumentElement(); - appendEndTestElement(test, doc, root); - appendConformanceClassElement(test, doc, root); - } - - try { - DOMSource source = new DOMSource(doc); - - TransformerFactory transformerFactory = TransformerFactory.newInstance(); - Transformer transformer = transformerFactory.newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - StreamResult result = new StreamResult(logfile); - transformer.transform(source, result); - } - catch (Exception ex) { - throw new RuntimeException("Unable to update missing information in " + logdir); - } - - } - - private void appendEndTestElement(TestEntry test, Document doc, Element root) { - Element endtest = doc.createElement("endtest"); - - Attr resultAttribute = doc.createAttribute("result"); - resultAttribute.setValue(Integer.toString(test.getResult())); - - endtest.setAttributeNode(resultAttribute); - root.appendChild(endtest); - } - - private void appendConformanceClassElement(TestEntry test, Document doc, Element root) { - if (test.isConformanceClass()) { - Element conformanceClass = doc.createElement("conformanceClass"); - - Attr nameAttribute = doc.createAttribute("name"); - nameAttribute.setValue(test.getLocalName()); - - Attr isBasicAttribute = doc.createAttribute("isBasic"); - isBasicAttribute.setValue(Boolean.toString(test.isBasic())); - - Attr resultAttribute = doc.createAttribute("result"); - resultAttribute.setValue(Integer.toString(test.getResult())); - - conformanceClass.setAttributeNode(nameAttribute); - conformanceClass.setAttributeNode(isBasicAttribute); - conformanceClass.setAttributeNode(resultAttribute); - root.appendChild(conformanceClass); - } - - } - - /** - * Runs a subtest as directed by a <ctl:call-test> instruction. - * @param context The context in which the subtest is executed. - * @param localName The [local name] of the subtest. - * @param namespaceURI The [namespace name] of the subtest. - * @param params A NodeInfo object containing test parameters. - * @param callId A node identifier used to build a file path reference for the test - * results. - * @throws Exception If an error occcurs while executing the test. - */ - public synchronized void callTest(XPathContext context, String localName, String namespaceURI, NodeInfo params, - String callId) throws Exception { - String key = "{" + namespaceURI + "}" + localName; - TestEntry test = index.getTest(key); - if (logger != null) { - logger.println(""); - logger.flush(); - } - if (opts.getMode() == Test.RESUME_MODE) { - Document doc = LogUtils.readLog(opts.getLogDir(), testPath + "/" + callId); - int result = LogUtils.getResultFromLog(doc); - if (result == CONTINUE) { - throw new IllegalStateException( - "Error: 'continue' is not allowed when a test is called using 'call-test' instruction"); - } - else { - out.println(indent + "Test " + test.getName() + " " + getResultDescription(result)); - test.setResult(result); - updateParentTestResult(test); - return; - } - } - - String oldTestPath = testPath; - testPath += "/" + callId; - int result = CONTINUE; - try { - result = executeTest(test, S9APIUtils.makeNode(params), context); - } - catch (Exception e) { - - } - finally { - testPath = oldTestPath; - } - if (result == CONTINUE) { - throw new IllegalStateException( - "Error: 'continue' is not allowed when a test is called using 'call-test' instruction"); - } - } - - /** - * Modifies the result of the parent test according to the result of the current test. - * The parent test will be 'tainted' with an inherited failure if (a) a subtest - * failed, or (b) a required subtest was skipped. - * @param currTest The TestEntry for the current test. - */ - private void updateParentTestResult(TestEntry currTest) { - TestEntry parentTest = getParentTest(); - if (null == parentTest) - return; - if (LOGR.isLoggable(FINE)) { - LOGR.log(FINE, "Entered setParentTestResult with TestEntry {0} (result={1})", - new Object[] { currTest.getQName(), currTest.getResult() }); - LOGR.log(FINE, "Parent TestEntry is {0} (result={1})", - new Object[] { parentTest.getQName(), parentTest.getResult() }); - } - switch (currTest.getResult()) { - case FAIL: - // fall through - case INHERITED_FAILURE: - parentTest.setResult(INHERITED_FAILURE); - break; - case SKIPPED: - if (currTest.getType().equalsIgnoreCase("Mandatory")) { - parentTest.setResult(INHERITED_FAILURE); - } - break; - default: - parentTest.setResult(Integer.max(currTest.getResult(), parentTest.getResult())); - break; - } - } - - /* - * ctl:repeat-test is not documented and is not used in any - * https://github.com/opengeospatial ETS - */ - /* - * public void repeatTest(XPathContext context, String localName, String NamespaceURI, - * NodeInfo params, String callId, int count, int pause) throws Exception { String key - * = "{" + NamespaceURI + "}" + localName; TestEntry test = index.getTest(key); - * - * if (logger != null) { logger.println(""); logger.flush(); } if (opts.getMode() == Test.RESUME_MODE) { Document doc - * = LogUtils.readLog(opts.getLogDir(), testPath + "/" + callId); int result = - * LogUtils.getResultFromLog(doc); if (result >= 0) { out.println(indent + "Test " + - * test.getName() + " " + getResultDescription(result)); if (result == WARNING) { - * warning(); } else if (result != PASS) { inheritedFailure(); } return; } } int - * oldResult = verdict; String oldTestPath = testPath; testPath += "/" + callId; - * - * for (int i = 0; i < count; i++) { executeTest(test, S9APIUtils.makeNode(params), - * context); testPath = oldTestPath; if (verdict == FAIL && oldResult != FAIL) { // If - * the child result was FAIL and parent hasn't directly // failed, // set parent - * result to INHERITED_FAILURE verdict = INHERITED_FAILURE; - * - * return; } else if (verdict == CONTINUE) { // - * System.out.println("Pausing for..."+pause); if (pause > 0 && i < count - 1) { - * - * try { - * - * Thread.sleep(pause); } catch (Exception e) { e.printStackTrace(); } } - * - * } else if (verdict <= oldResult) { // Restore parent result if the child results - * aren't worse verdict = oldResult; return; - * - * } } verdict = FAIL; if (oldResult != FAIL) { // If the child result was FAIL and - * parent hasn't directly failed, // set parent result to INHERITED_FAILURE verdict = - * INHERITED_FAILURE; } - * - * } - */ - - public NodeInfo executeXSLFunction(XPathContext context, FunctionEntry fe, NodeInfo params) throws Exception { - String oldFnPath = fnPath; - CRC32 crc = new CRC32(); - crc.update((fe.getPrefix() + fe.getId()).getBytes()); - fnPath += Long.toHexString(crc.getValue()) + "/"; - XdmNode n = executeTemplate(fe, S9APIUtils.makeNode(params), context); - fnPath = oldFnPath; - if (n == null) { - return null; - } - return n.getUnderlyingNode(); - } - - public Object callFunction(XPathContext context, String localName, String namespaceURI, NodeInfo params) - throws Exception { - // System.out.println("callFunction {" + NamespaceURI + "}" + - // localName); - String key = "{" + namespaceURI + "}" + localName; - List functions = index.getFunctions(key); - Node paramsNode = NodeOverNodeInfo.wrap(params); - List paramElements = DomUtils.getElementsByTagName(paramsNode, "param"); - for (FunctionEntry fe : functions) { - if (!fe.isJava()) { - boolean valid = true; - for (Element el : paramElements) { - String uri = el.getAttribute("namespace-uri"); - String name = el.getAttribute("local-name"); - String prefix = el.getAttribute("prefix"); - javax.xml.namespace.QName qname = new javax.xml.namespace.QName(uri, name, prefix); - if (!fe.getParams().contains(qname)) { - valid = false; - break; - } - } - if (valid) { - if (opts.getMode() == Test.DOC_MODE) { - if (fnCallStack.contains(key)) { - return null; - } - else { - fnCallStack.add(key); - Object result = executeXSLFunction(context, fe, params); - fnCallStack.pop(); - return result; - } - } - else { - return executeXSLFunction(context, fe, params); - } - } - } - } - - if (opts.getMode() == Test.DOC_MODE) { - return null; - } - - for (FunctionEntry fe : functions) { - if (fe.isJava()) { - int argCount = paramElements.size(); - if (fe.getMinArgs() >= argCount && fe.getMaxArgs() <= argCount) { - TEClassLoader cl = engine.getClassLoader(opts.getSourcesName()); - Method method = Misc.getMethod(fe.getClassName(), fe.getMethod(), cl, argCount); - Class[] types = method.getParameterTypes(); - Object[] args = new Object[argCount]; - for (int i = 0; i < argCount; i++) { - Element el = DomUtils.getElementByTagName(paramElements.get(i), "value"); - if (types[i].equals(String.class)) { - Map attrs = DomUtils.getAttributes(el); - if (attrs.size() > 0) { - args[i] = attrs.values().iterator().next(); - } - else { - args[i] = el.getTextContent(); - } - } - else if (types[i].toString().equals("char")) { - args[i] = el.getTextContent().charAt(0); - } - else if (types[i].toString().equals("boolean")) { - args[i] = Boolean.parseBoolean(el.getTextContent()); - } - else if (types[i].toString().equals("byte")) { - args[i] = Byte.parseByte(el.getTextContent()); - } - else if (types[i].toString().equals("short")) { - args[i] = Short.parseShort(el.getTextContent()); - } - else if (types[i].toString().equals("int")) { - args[i] = Integer.parseInt(el.getTextContent()); - } - else if (types[i].toString().equals("long")) { - args[i] = Long.parseLong(el.getTextContent()); - } - else if (types[i].toString().equals("float")) { - args[i] = Float.parseFloat(el.getTextContent()); - } - else if (types[i].toString().equals("double")) { - args[i] = Double.parseDouble(el.getTextContent()); - } - else if (Document.class.isAssignableFrom(types[i])) { - args[i] = DomUtils.createDocument(DomUtils.getChildElement(el)); - } - else if (NodeList.class.isAssignableFrom(types[i])) { - args[i] = el.getChildNodes(); - } - else if (Node.class.isAssignableFrom(types[i])) { - args[i] = el.getFirstChild(); - } - else { - throw new Exception( - "Error: Function " + key + " uses unsupported Java type " + types[i].toString()); - } - } - try { - Object instance = null; - if (fe.isInitialized()) { - // String instkey = fe.getId() + "," + - // Integer.toString(fe.getMinArgs()) + "," + - // Integer.toString(fe.getMaxArgs()); - instance = getFunctionInstance(fe.hashCode()); - if (instance == null) { - try { - instance = Misc.makeInstance(fe.getClassName(), fe.getClassParams(), cl); - putFunctionInstance(fe.hashCode(), instance); - } - catch (Exception e) { - throw new XPathException(e); - } - } - } - return method.invoke(instance, args); - } - catch (java.lang.reflect.InvocationTargetException e) { - Throwable cause = e.getCause(); - String msg = "Error invoking function " + fe.getId() + "\n" + cause.getClass().getName(); - if (cause.getMessage() != null) { - msg += ": " + cause.getMessage(); - } - jlogger.log(SEVERE, "InvocationTargetException", e); - - throw new Exception(msg, cause); - } - } - } - } - throw new Exception("No function {" + namespaceURI + "}" + localName + " with a compatible signature."); - } - - public void _continue() { - testStack.peek().setResult(CONTINUE); - } - - public void bestPractice() { - if (testStack.peek().getResult() < BEST_PRACTICE) { - testStack.peek().setResult(BEST_PRACTICE); - } - } - - public void notTested() { - if (testStack.peek().getResult() < NOT_TESTED) { - testStack.peek().setResult(NOT_TESTED); - } - } - - public void skipped() { - if (testStack.peek().getResult() < SKIPPED) { - testStack.peek().setResult(SKIPPED); - } - } - - public void pass() { - if (testStack.peek().getResult() < PASS) { - testStack.peek().setResult(PASS); - } - } - - public void warning() { - if (testStack.peek().getResult() < WARNING) { - testStack.peek().setResult(WARNING); - } - } - - public void inheritedFailure() { - if (testStack.peek().getResult() < INHERITED_FAILURE) { - testStack.peek().setResult(INHERITED_FAILURE); - } - } - - public void fail() { - testStack.peek().setResult(FAIL); - } - - public String getResult() { - return getResultDescription(testStack.getLast().getResult()); - } - - public String getMode() { - return Test.getModeName(opts.getMode()); - } - - public void setContextLabel(String label) { - contextLabel = label; - } - - public String getFormHtml() { - return formHtml; - } - - public void setFormHtml(String html) { - this.formHtml = html; - } - - public Document getFormResults() { - return formResults; - } - - public void setFormResults(Document doc) { - try { - StringWriter sw = new StringWriter(); - // Fortify Mod: prevent external entity injection - TransformerFactory tf = TransformerFactory.newInstance(); - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer transformer = tf.newTransformer(); - // End Fortify Mod - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); - transformer.transform(new DOMSource(doc), new StreamResult(sw)); - if (userInputs == null) { - userInputs = doc; - } - LOGR.info("Setting form results:\n " + sw.toString()); - } - catch (Exception e) { - LOGR.log(SEVERE, "Failed to log the form results", e); - } - this.formResults = doc; - } - - public Map getFormParsers() { - return formParsers; - } - - public Document readLog() throws Exception { - return LogUtils.readLog(opts.getLogDir(), testPath); - } - - public PrintWriter createLog() throws Exception { - return LogUtils.createLog(opts.getLogDir(), testPath); - } - - // Get a File pointer to a file reference (in XML) - public static File getFile(NodeList fileNodes) { - File file = null; - for (int i = 0; i < fileNodes.getLength(); i++) { - Element e = (Element) fileNodes.item(i); - String type = e.getAttribute("type"); - - try { - // URL, File, or Resource - if (type.equals("url")) { - URL url = new URL(e.getTextContent()); - file = new File(url.toURI()); - } - else if (type.equals("file")) { - file = new File(e.getTextContent()); - } - else if (type.equals("resource")) { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - file = new File(cl.getResource(e.getTextContent()).getFile()); - } - else { - System.out.println("Incorrect file reference: Unknown type!"); - } - } - catch (Exception exception) { - System.err.println("Error getting file. " + exception.getMessage()); - jlogger.log(SEVERE, "Error getting file. " + exception.getMessage(), e); - - return null; - } - } - return file; - } - - // BEGIN SOAP SUPPORT - public NodeList soap_request(Document ctlRequest, String id) throws Throwable { - Element request = (Element) ctlRequest.getElementsByTagNameNS(Test.CTL_NS, "soap-request").item(0); - if (opts.getMode() == Test.RESUME_MODE && prevLog != null) { - for (Element request_e : DomUtils.getElementsByTagName(prevLog, "soap-request")) { - if (request_e.getAttribute("id").equals(fnPath + id)) { - logger.println(DomUtils.serializeNode(request_e)); - logger.flush(); - Element response_e = DomUtils.getElementByTagName(request_e, "response"); - Element content_e = DomUtils.getElementByTagName(response_e, "content"); - return content_e.getChildNodes(); - // return DomUtils.getChildElement(content_e); - } - } - } - - String logTag = "\n"; - logTag += DomUtils.serializeNode(request) + "\n"; - // if (logger != null) { - // logger.println(""); - // logger.println(DomUtils.serializeNode(request)); - // } - Exception ex = null; - Element response = null; - Element parserInstruction = null; - NodeList nl = request.getChildNodes(); - long elapsedTime = 0; - for (int i = 0; i < nl.getLength(); i++) { - Node n = nl.item(i); - if (n.getNodeType() == Node.ELEMENT_NODE && !n.getNamespaceURI().equals(CTL_NS)) { - parserInstruction = (Element) n; - } - } - try { - Date before = new Date(); - URLConnection uc = build_soap_request(request); - response = parse(uc, parserInstruction); - Date after = new Date(); - elapsedTime = after.getTime() - before.getTime(); - - // Adding the exchange time in the response as comment the format is - // the following - // - // the comment is included in the first tag of the response - // SOAP:Envelope in case a SOAP message is returned the specific - // interface tag if a SOAP parser is applied - Element content = DomUtils.getElementByTagName(response, "content"); - if (content != null) { - nl = content.getChildNodes(); - for (int i = 0; i < nl.getLength(); i++) { - Node n = nl.item(i); - if (n.getNodeType() == Node.ELEMENT_NODE) { - Document doc; - doc = response.getOwnerDocument(); - Comment comm = doc.createComment("Response received in [" + elapsedTime + "] milliseconds"); - n.appendChild(comm); - } - } - } - - logTag += DomUtils.serializeNode(response) + "\n"; - jlogger.log(FINE, DomUtils.serializeNode(response)); - } - catch (Exception e) { - ex = e; - } - logTag += ""; - logTag += ""; - if (logger != null) { - logger.println(logTag); - logger.flush(); - } - if (ex == null) { - Element parser = DomUtils.getElementByTagName(response, "parser"); - if (parser != null) { - String text = parser.getTextContent(); - if (text.length() > 0) { - out.println(parser.getTextContent()); - } - } - Element content = DomUtils.getElementByTagName(response, "content"); - return content.getChildNodes(); - } - else { - throw ex; - } - } - - /** - * Create SOAP request, sends it and return an URL Connection ready to be parsed. - * @param xml the soap-request node (from CTL) - * @return The URL Connection - * @throws Exception the exception - * - * <soap-request version="1.1|1.2" charset="UTF-8"> - * <url>http://blah</url> <action>Some-URI</action> - * <headers> <header MutUnderstand="true" rely="true" role="http://etc"> - * <t:Transaction xmlns:t="some-URI" >5</t:Transaction> </header> - * </headers> <body> <m:GetLastTradePrice xmlns:m="Some-URI"> - * <symbol>DEF</symbol> </m:GetLastTradePrice> </body> - * <parsers:SOAPParser return="content"> <parsers:XMLValidatingParser> - * <parsers:schemas> <parsers:schema - * type="url">http://blah/schema.xsd</parsers:schema> - * </parsers:schemas> </parsers:XMLValidatingParser> - * </parsers:SOAPParser> </soap-request> - */ - static public URLConnection build_soap_request(Node xml) throws Exception { - String sUrl = null; - String method = "POST"; - String charset = ((Element) xml).getAttribute("charset").isEmpty() ? ((Element) xml).getAttribute("charset") - : "UTF-8"; - String version = ((Element) xml).getAttribute("version"); - String action = ""; - String contentType = ""; - Element body = null; - - // Read in the test information (from CTL) - NodeList nl = xml.getChildNodes(); - for (int i = 0; i < nl.getLength(); i++) { - Node n = nl.item(i); - if (n.getNodeType() == Node.ELEMENT_NODE) { - if (n.getLocalName().equals("url")) { - sUrl = n.getTextContent(); - } - else if (n.getLocalName().equals("action")) { - action = n.getTextContent(); - } - // else if (n.getLocalName().equals("header")) { - // header = (org.w3c.dom.Element) n; - /* - * } - */else if (n.getLocalName().equals("body")) { - body = (org.w3c.dom.Element) n; - } - } - } - - // Get the list of the header blocks needed to build the SOAP Header - // section - List headerBloks = DomUtils.getElementsByTagNameNS(xml, CTL_NS, HEADER_BLOCKS); - // Open the URLConnection - URLConnection uc = new URL(sUrl).openConnection(); - if (uc instanceof HttpURLConnection) { - ((HttpURLConnection) uc).setRequestMethod(method); - } - - uc.setDoOutput(true); - byte[] bytes = null; - - // SOAP POST - bytes = SoapUtils.getSoapMessageAsByte(version, headerBloks, body, charset); - // System.out.println("SOAP MESSAGE " + new String(bytes)); - - uc.setRequestProperty("User-Agent", "Team Engine 1.2"); - uc.setRequestProperty("Cache-Control", "no-cache"); - uc.setRequestProperty("Pragma", "no-cache"); - uc.setRequestProperty("charset", charset); - uc.setRequestProperty("Content-Length", Integer.toString(bytes.length)); - - if (version.equals(SOAP_V_1_1)) { - // Handle HTTP binding for SOAP 1.1 - // uc.setRequestProperty("Accept", "application/soap+xml"); - uc.setRequestProperty("Accept", "text/xml"); - uc.setRequestProperty("SOAPAction", action); - contentType = "text/xml"; - if (!charset.isEmpty()) { - contentType = contentType + "; charset=" + charset; - } - uc.setRequestProperty("Content-Type", contentType); - } - else { - // Handle HTTP binding for SOAP 1.2 - uc.setRequestProperty("Accept", "application/soap+xml"); - contentType = "application/soap+xml"; - if (!charset.isEmpty()) { - contentType = contentType + "; charset=" + charset; - } - if (!action.isEmpty()) { - contentType = contentType + "; action=" + action; - } - uc.setRequestProperty("Content-Type", contentType); - } - OutputStream os = uc.getOutputStream(); - os.write(bytes); - return uc; - - } - - /** - * Implements ctl:request. Create and send an HTTP request then return an - * HttpResponse. Invoke any specified parsers on the response to validate it, change - * its format or derive specific information from it. - */ - public NodeList request(Document ctlRequest, String id) throws Throwable { - Element request = (Element) ctlRequest.getElementsByTagNameNS(Test.CTL_NS, "request").item(0); - if (opts.getMode() == Test.RESUME_MODE && prevLog != null) { - for (Element request_e : DomUtils.getElementsByTagName(prevLog, "request")) { - if (request_e.getAttribute("id").equals(fnPath + id)) { - logger.println(DomUtils.serializeNode(request_e)); - logger.flush(); - Element response_e = DomUtils.getElementByTagName(request_e, "response"); - Element content_e = DomUtils.getElementByTagName(response_e, "content"); - return content_e.getChildNodes(); - // return DomUtils.getChildElement(content_e); - } - } - } - - String logTag = "\n"; - logTag += DomUtils.serializeNode(request) + "\n"; - // if (logger != null) { - // logger.println(""); - // logger.println(DomUtils.serializeNode(request)); - // } - long elapsedTime = 0; - Exception ex = null; - Element response = null; - Element parserInstruction = null; - NodeList nl = request.getChildNodes(); - for (int i = 0; i < nl.getLength(); i++) { - Node n = nl.item(i); - if (n.getNodeType() == Node.ELEMENT_NODE && !n.getNamespaceURI().equals(CTL_NS)) { - parserInstruction = (Element) n; - } - } - - try { - Date before = new Date(); - URLConnection uc = build_request(request); - response = parse(uc, parserInstruction); - Date after = new Date(); - elapsedTime = after.getTime() - before.getTime(); - - // Adding the exchange time in the response as comment the format is - // the following - // - // the comment is included in the first tag of the response - Element content = DomUtils.getElementByTagName(response, "content"); - if (content != null) { - nl = content.getChildNodes(); - for (int i = 0; i < nl.getLength(); i++) { - Node n = nl.item(i); - if (n.getNodeType() == Node.ELEMENT_NODE) { - Document doc; - doc = response.getOwnerDocument(); - Comment comm = doc.createComment("Response received in [" + elapsedTime + "] milliseconds"); - n.appendChild(comm); - } - } - } - - logTag += DomUtils.serializeNode(response) + "\n"; - // if (logger != null) { - // logger.println(DomUtils.serializeNode(response)); - // } - } - catch (Exception e) { - ex = e; - } - // logTag += ""; - logTag += ""; - if (logger != null) { - // logger.println(""); - logger.println(logTag); - logger.flush(); - } - if (ex == null) { - Element parser = DomUtils.getElementByTagName(response, "parser"); - if (parser != null) { - String text = parser.getTextContent(); - if (text.length() > 0) { - out.println(parser.getTextContent()); - } - } - Element content = DomUtils.getElementByTagName(response, "content"); - return content.getChildNodes(); - } - else { - throw ex; - } - } - - /** - * Submits a request to some HTTP endpoint using the given request details. - * @param xml An ctl:request element. - * @return A URLConnection object representing an open communications link. - * @throws Exception If any error occurs while submitting the request or establishing - * a conection. - */ - public URLConnection build_request(Node xml) throws Exception { - Node body = null; - ArrayList headers = new ArrayList<>(); - ArrayList parts = new ArrayList<>(); - String sUrl = null; - String sParams = ""; - String method = "GET"; - String charset = "UTF-8"; - boolean multipart = false; - - // Read in the test information (from CTL) - NodeList nl = xml.getChildNodes(); - for (int i = 0; i < nl.getLength(); i++) { - Node n = nl.item(i); - if (n.getNodeType() == Node.ELEMENT_NODE) { - if (n.getLocalName().equals("url")) { - sUrl = n.getTextContent(); - } - else if (n.getLocalName().equals("method")) { - method = n.getTextContent().toUpperCase(); - } - else if (n.getLocalName().equals("header")) { - headers.add(new String[] { ((Element) n).getAttribute("name"), n.getTextContent() }); - } - else if (n.getLocalName().equals("param")) { - if (sParams.length() > 0) { - sParams += "&"; - } - sParams += ((Element) n).getAttribute("name") + "=" + n.getTextContent(); - // WARNING! May break some existing test suites - // + URLEncoder.encode(n.getTextContent(), "UTF-8"); - } - else if (n.getLocalName().equals("dynamicParam")) { - String name = null; - String val = null; - NodeList dpnl = n.getChildNodes(); - for (int j = 0; j < dpnl.getLength(); j++) { - Node dpn = dpnl.item(j); - if (dpn.getNodeType() == Node.ELEMENT_NODE) { - if (dpn.getLocalName().equals("name")) { - name = dpn.getTextContent(); - } - else if (dpn.getLocalName().equals("value")) { - val = dpn.getTextContent(); - // val = - // URLEncoder.encode(dpn.getTextContent(),"UTF-8"); - } - } - } - if (name != null && val != null) { - if (sParams.length() > 0) - sParams += "&"; - sParams += name + "=" + val; - } - } - else if (n.getLocalName().equals("body")) { - body = n; - } - else if (n.getLocalName().equals("part")) { - parts.add(n); - } - } - } - - // Complete GET KVP syntax - // Fortify Mod: Added check for null sUrl. Shouldn't happen but ---- - // if (method.equals("GET") && sParams.length() > 0) { - if (method.equals("GET") && sParams.length() > 0 && sUrl != null) { - if (sUrl.indexOf("?") == -1) { - sUrl += "?"; - } - else if (!sUrl.endsWith("?") && !sUrl.endsWith("&")) { - sUrl += "&"; - } - sUrl += sParams; - } - - // System.out.println(sUrl); - TransformerFactory tf = TransformerFactory.newInstance(); - // Fortify Mod: prevent external entity injection - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer t = tf.newTransformer(); - - // Open the URLConnection - URLConnection uc = new URL(sUrl).openConnection(); - if (uc instanceof HttpURLConnection) { - HttpURLConnection httpUc = (HttpURLConnection) uc; - httpUc.setRequestMethod(method); - boolean redirect = checkForRedirect(httpUc); - if (redirect) { - String redirectURL = httpUc.getHeaderField("Location"); - uc = new URL(redirectURL).openConnection(); - if (uc instanceof HttpURLConnection) { - ((HttpURLConnection) uc).setRequestMethod(method); - } - } - else { - // https://github.com/opengeospatial/teamengine/issues/553 - // need to re-connect, as the check for redirects already opened the - // connection - uc = new URL(sUrl).openConnection(); - } - } - - // POST setup (XML payload and header information) - if (method.equals("POST") || method.equals("PUT")) { - uc.setDoOutput(true); - byte[] bytes = null; - String mime = null; - - // KVP over POST - if (body == null) { - bytes = sParams.getBytes(); - mime = "application/x-www-form-urlencoded"; - } // XML POST - else { - String bodyContent = ""; - - NodeList children = body.getChildNodes(); - for (int i = 0; i < children.getLength(); i++) { - if (children.item(i).getNodeType() == Node.ELEMENT_NODE) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - t.transform(new DOMSource(children.item(i)), new StreamResult(baos)); - bodyContent = baos.toString(); - bytes = baos.toByteArray(); - - if (mime == null) { - mime = "application/xml; charset=" + charset; - } - break; - } - } - if (bytes == null) { - bytes = body.getTextContent().getBytes(); - mime = "text/plain"; - } - - // Add parts if present - if (parts.size() > 0) { - String prefix = "--"; - String boundary = "7bdc3bba-e2c9-11db-8314-0800200c9a66"; - String newline = "\r\n"; - multipart = true; - - // Set main body and related headers - ByteArrayOutputStream contentBytes = new ByteArrayOutputStream(); - String bodyPart = prefix + boundary + newline; - bodyPart += "Content-Type: " + mime + newline + newline; - bodyPart += bodyContent; - writeBytes(contentBytes, bodyPart.getBytes(charset)); - - // Append all parts to the original body, seperated by the - // boundary sequence - for (int i = 0; i < parts.size(); i++) { - Element currentPart = (Element) parts.get(i); - String cid = currentPart.getAttribute("cid"); - if (cid.indexOf("cid:") != -1) { - cid = cid.substring(cid.indexOf("cid:") + "cid:".length()); - } - String contentType = currentPart.getAttribute("content-type"); - - // Default encodings and content-type - if (contentType.equals("application/xml")) { - contentType = "application/xml; charset=" + charset; - } - if (contentType == null || contentType.isEmpty()) { - contentType = "application/octet-stream"; - } - - // Set headers for each part - String partHeaders = newline + prefix + boundary + newline; - partHeaders += "Content-Type: " + contentType + newline; - partHeaders += "Content-ID: <" + cid + ">" + newline + newline; - writeBytes(contentBytes, partHeaders.getBytes(charset)); - - // Get the fileName, if it exists - NodeList files = currentPart.getElementsByTagNameNS(CTL_NS, "file"); - - // Get part for a specified file - if (files.getLength() > 0) { - File contentFile = getFile(files); - - InputStream is = new FileInputStream(contentFile); - long length = contentFile.length(); - byte[] fileBytes = new byte[(int) length]; - int offset = 0; - int numRead = 0; - while (offset < fileBytes.length - && (numRead = is.read(fileBytes, offset, fileBytes.length - offset)) >= 0) { - offset += numRead; - } - is.close(); - - writeBytes(contentBytes, fileBytes); - } // Get part from inline data (or xi:include) - else { - // Text - if (currentPart.getFirstChild() instanceof Text) { - writeBytes(contentBytes, currentPart.getTextContent().getBytes(charset)); - } // XML - else { - writeBytes(contentBytes, - DomUtils.serializeNode(currentPart.getFirstChild()).getBytes(charset)); - } - } - } - - String endingBoundary = newline + prefix + boundary + prefix + newline; - writeBytes(contentBytes, endingBoundary.getBytes(charset)); - - bytes = contentBytes.toByteArray(); - - // Global Content-Type and Length to be added after the - // parts have been parsed - mime = "multipart/related; type=\"" + mime + "\"; boundary=\"" + boundary + "\""; - - // String contentsString = new String(bytes, charset); - // System.out.println("Content-Type: "+mime+"\n"+contentsString); - } - } - - // Set headers - if (body != null) { - String mid = ((Element) body).getAttribute("mid"); - if (mid != null && !mid.isEmpty()) { - if (mid.indexOf("mid:") != -1) { - mid = mid.substring(mid.indexOf("mid:") + "mid:".length()); - } - uc.setRequestProperty("Message-ID", "<" + mid + ">"); - } - } - uc.setRequestProperty("Content-Type", mime); - uc.setRequestProperty("Content-Length", Integer.toString(bytes.length)); - - // Enter the custom headers (overwrites the defaults if present) - for (int i = 0; i < headers.size(); i++) { - String[] header = headers.get(i); - if (multipart && header[0].toLowerCase().equals("content-type")) { - } - else { - uc.setRequestProperty(header[0], header[1]); - } - } - - OutputStream os = uc.getOutputStream(); - os.write(bytes); - } - else { - for (int i = 0; i < headers.size(); ++i) { - String[] header = headers.get(i); - uc.setRequestProperty(header[0], header[1]); - } - } - - return uc; - } - - public static void writeBytes(ByteArrayOutputStream baos, byte[] bytes) { - baos.write(bytes, 0, bytes.length); - } - - public Element parse(Document parse_instruction, String xsl_version) throws Throwable { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - // Fortify Mod: prevent external entity injection - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - - TransformerFactory tf = TransformerFactory.newInstance(); - // Fortify Mod: prevent external entity injection - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer t = null; - Node content = null; - Document parser_instruction = null; - - Element parse_element = (Element) parse_instruction.getElementsByTagNameNS(CTL_NS, "parse").item(0); - - NodeList children = parse_element.getChildNodes(); - for (int i = 0; i < children.getLength(); i++) { - if (children.item(i).getNodeType() == Node.ELEMENT_NODE) { - Element e = (Element) children.item(i); - if (e.getNamespaceURI().equals(XSL_NS) && e.getLocalName().equals("output")) { - Document doc = db.newDocument(); - Element transform = doc.createElementNS(XSL_NS, "transform"); - transform.setAttribute("version", xsl_version); - doc.appendChild(transform); - Element output = doc.createElementNS(XSL_NS, "output"); - NamedNodeMap atts = e.getAttributes(); - for (int j = 0; j < atts.getLength(); j++) { - Attr a = (Attr) atts.item(i); - output.setAttribute(a.getName(), a.getValue()); - } - transform.appendChild(output); - Element template = doc.createElementNS(XSL_NS, "template"); - template.setAttribute("match", "node()|@*"); - transform.appendChild(template); - Element copy = doc.createElementNS(XSL_NS, "copy"); - template.appendChild(copy); - Element apply = doc.createElementNS(XSL_NS, "apply-templates"); - apply.setAttribute("select", "node()|@*"); - copy.appendChild(apply); - t = tf.newTransformer(new DOMSource(doc)); - } - else if (e.getLocalName().equals("content")) { - NodeList children2 = e.getChildNodes(); - for (int j = 0; j < children2.getLength(); j++) { - if (children2.item(j).getNodeType() == Node.ELEMENT_NODE) { - content = children2.item(j); - } - } - if (content == null) { - content = children2.item(0); - } - } - else { - parser_instruction = db.newDocument(); - tf.newTransformer().transform(new DOMSource(e), new DOMResult(parser_instruction)); - } - } - } - if (t == null) { - t = tf.newTransformer(); - } - File temp = File.createTempFile("$te_", ".xml"); - // Fortify Mod: It is possible to get here without assigning a value to content. - // if (content.getNodeType() == Node.TEXT_NODE) { - if (content != null && content.getNodeType() == Node.TEXT_NODE) { - RandomAccessFile raf = new RandomAccessFile(temp, "rw"); - raf.writeBytes(((Text) content).getTextContent()); - raf.close(); - } - else { - t.transform(new DOMSource(content), new StreamResult(temp)); - } - URLConnection uc = temp.toURI().toURL().openConnection(); - Element result = parse(uc, parser_instruction); - temp.delete(); - return result; - } - - /** - * Parses the content retrieved from some URI and builds a DOM Document containing - * information extracted from the response message. Subsidiary parsers are invoked in - * accord with the supplied parser instructions. - * @param uc A URLConnection object. - * @param instruction A Document or Element node containing parser instructions. - * @return An Element containing selected info from a URLConnection as specified by - * instruction Element and children. - */ - public Element parse(URLConnection uc, Node instruction) throws Throwable { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - // Fortify Mod: Disable entity expansion to foil External Entity Injections - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document response_doc = db.newDocument(); - return parse(uc, instruction, response_doc); - } - - /** - * Invoke a parser or chain of parsers as specified by instruction element and - * children. Parsers in chain share uc, strip off their own instructions, and pass - * child instructions to next parser in chain. Final parser in chain modifies content. - * All parsers in chain can return info in attributes and child elements of - * instructions. If parser specified in instruction, call it to return specified info - * from uc. - */ - public Element parse(URLConnection uc, Node instruction, Document response_doc) throws Exception { - // Fortify Mod: To prevent external entity injections - TransformerFactory tf = TransformerFactory.newInstance(); - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer idt = tf.newTransformer(); - // End Fortify Mod - Element parser_e = response_doc.createElement("parser"); - Element response_e = response_doc.createElement("response"); - Element content_e = response_doc.createElement("content"); - if (instruction == null) { - InputStream is = null; - uc.connect(); - String contentType = uc.getContentType(); - try { - is = URLConnectionUtils.getInputStream(uc); - if (contentType != null && contentType.contains("xml")) { // a crude check - idt.transform(new StreamSource(is), new DOMResult(content_e)); - } - else { - content_e.setTextContent(IOUtils.inputStreamToString(is)); - } - } - finally { - if (null != is) - is.close(); - } - } - else { - Element instruction_e; - if (instruction instanceof Element) { - instruction_e = (Element) instruction; - } - else { - instruction_e = ((Document) instruction).getDocumentElement(); - } - String key = "{" + instruction_e.getNamespaceURI() + "}" + instruction_e.getLocalName(); - ParserEntry pe = index.getParser(key); - Object instance = null; - - // Instantiate the parser object if requested. - if (pe.isInitialized()) { - instance = parserInstances.get(key); - if (instance == null) { - try { - TEClassLoader cl = engine.getClassLoader(opts.getSourcesName()); - instance = Misc.makeInstance(pe.getClassName(), pe.getClassParams(), cl); - } - catch (Exception e) { - throw new Exception("Can't instantiate parser " + pe.getName(), e); - } - parserInstances.put(key, instance); - } - } - - Method method = parserMethods.get(key); - if (method == null) { - TEClassLoader cl = engine.getClassLoader(opts.getSourcesName()); - method = Misc.getMethod(pe.getClassName(), pe.getMethod(), cl, 3, 4); - parserMethods.put(key, method); - } - StringWriter swLogger = new StringWriter(); - PrintWriter pwLogger = new PrintWriter(swLogger); - int arg_count = method.getParameterTypes().length; - Object[] args = new Object[arg_count]; - args[0] = uc; - args[1] = instruction_e; - args[2] = pwLogger; - if (arg_count > 3) { - args[3] = this; - } - Object return_object; - try { - if (LOGR.isLoggable(Level.FINER)) { - LOGR.finer("Invoking method " + method.toGenericString() + "size args[] = " + args.length - + "\n args[0]: " + args[0].toString() + "\n args[1]:\n" - + DomUtils.serializeNode((Node) args[1])); - } - return_object = method.invoke(instance, args); - } - catch (java.lang.reflect.InvocationTargetException e) { - Throwable cause = e.getCause(); - String msg = "Error invoking parser " + pe.getId() + "\n" + cause.getClass().getName(); - if (cause.getMessage() != null) { - msg += ": " + cause.getMessage(); - } - jlogger.log(SEVERE, msg, e); - // CTL says parsers should return null if they encounter an error. - // Apparently this parser is broken. Wrap the thrown exception in a - // RuntimeException since we really know nothing about what went wrong. - throw new RuntimeException("Parser " + pe.getId() + " threw an exception.", cause); - } - pwLogger.close(); - if (return_object instanceof Node) { - idt.transform(new DOMSource((Node) return_object), new DOMResult(content_e)); - } - else if (return_object != null) { - content_e.appendChild(response_doc.createTextNode(return_object.toString())); - } - parser_e.setAttribute("prefix", instruction_e.getPrefix()); - parser_e.setAttribute("local-name", instruction_e.getLocalName()); - parser_e.setAttribute("namespace-uri", instruction_e.getNamespaceURI()); - parser_e.setTextContent(swLogger.toString()); - } - response_e.appendChild(parser_e); - response_e.appendChild(content_e); - return response_e; - } - - public Node message(String message, String id) { - String formatted_message = indent + message.trim().replaceAll("\n", "\n" + indent); - String messageTrim = message.trim().replaceAll("\n", "\n" + indent); - if (!(messageTrim.contains("Clause") || messageTrim.contains("Purpose") || messageTrim.contains("TestName"))) { - out.println(formatted_message); - messageTest = message; - } - else { - if (messageTrim.contains("TestName")) { - TESTNAME = messageTrim.replace("TestName : ", ""); - if (rootTestName != null && rootTestName.size() > 0) { - for (int i = 0; i < rootTestName.size(); i++) { - if (messageTrim.contains(rootTestName.get(i))) { - rootNo = i + 1; - } - } - } - } - else if (messageTrim.contains("Clause")) { - Clause = messageTrim.replace("Clause : ", ""); - } - else { - Purpose = messageTrim.replace("Purpose : ", ""); - } - if ((rootNo != 0) && (!"".equals(Clause)) && (!"".equals(Purpose))) { - mainRootElementClause.appendChild(RecordTestResult.getClause()); - Clause = ""; - Purpose = ""; - rootNo = 0; - } - } - if (logger != null) { - logger.println(""); - } - return null; - } - - public void putLogCache(String id, Document xmlToCache) { - if (logger != null) { - String xmlString = DomUtils.serializeNode(xmlToCache); - logger.println("" + xmlString + ""); - } - } - - public Element getLogCache(String id) { - Element child_e = null; - if (prevLog != null) { - for (Element cache_e : DomUtils.getElementsByTagName(prevLog, "cache")) { - if (cache_e.getAttribute("id").equals(id)) { - child_e = DomUtils.getChildElement(cache_e); - } - } - } - if (suiteLog != null && child_e == null) { - for (Element cache_e : DomUtils.getElementsByTagName(suiteLog, "cache")) { - if (cache_e.getAttribute("id").equals(id)) { - child_e = DomUtils.getChildElement(cache_e); - } - } - } - return child_e; - } - - /** - * Converts CTL input form elements to generate a Swing-based or XHTML form and - * reports the results of processing the submitted form. The results document is - * produced in (web context) or - * {@link com.occamlab.te.SwingForm.CustomFormView#submitData(String)}. - * @param ctlForm a DOM Document representing a <ctl:form> element. - * @throws java.lang.Exception - * @return a DOM Document containing the resulting <values> element as the - * document element. - */ - public Node form(Document ctlForm, String id) throws Exception { - if (opts.getMode() == Test.RESUME_MODE && prevLog != null) { - for (Element e : DomUtils.getElementsByTagName(prevLog, "formresults")) { - if (e.getAttribute("id").equals(fnPath + id)) { - logger.println(DomUtils.serializeNode(e)); - logger.flush(); - return DomUtils.getChildElement(e); - } - } - } - - String name = Thread.currentThread().getName(); - Element form = (Element) ctlForm.getElementsByTagNameNS(CTL_NS, "form").item(0); - - NamedNodeMap attrs = form.getAttributes(); - Attr attr = (Attr) attrs.getNamedItem("name"); - if (attr != null) { - name = attr.getValue(); - } - - for (Element parseInstruction : DomUtils.getElementsByTagNameNS(form, CTL_NS, "parse")) { - String key = parseInstruction.getAttribute("file"); - formParsers.put(key, DomUtils.getChildElement(parseInstruction)); - } - - // Determine if there are file widgets or not - boolean hasFiles = false; - List inputs = DomUtils.getElementsByTagName(form, "input"); - inputs.addAll(DomUtils.getElementsByTagNameNS(form, "http://www.w3.org/1999/xhtml", "input")); - for (Element input : inputs) { - if (input.getAttribute("type").toLowerCase().equals("file")) { - hasFiles = true; - break; - } - } - - // Get "method" attribute - "post" or "get" - attr = (Attr) attrs.getNamedItem("method"); - String method = "get"; - if (attr != null) { - method = attr.getValue().toLowerCase(); - } - else if (hasFiles) { - method = "post"; - } - imageHandler.saveImages(form); - - XsltTransformer formTransformer = engine.getFormExecutable().load(); - formTransformer.setSource(new DOMSource(ctlForm)); - formTransformer.setParameter(new QName("title"), new XdmAtomicValue(name)); - formTransformer.setParameter(new QName("web"), new XdmAtomicValue(web ? "yes" : "no")); - formTransformer.setParameter(new QName("files"), new XdmAtomicValue(hasFiles ? "yes" : "no")); - formTransformer.setParameter(new QName("thread"), - new XdmAtomicValue(Long.toString(Thread.currentThread().getId()))); - formTransformer.setParameter(new QName("method"), new XdmAtomicValue(method)); - formTransformer.setParameter(new QName("base"), new XdmAtomicValue(opts.getBaseURI())); - formTransformer.setParameter(new QName("action"), new XdmAtomicValue(getTestServletURL())); - StringWriter sw = new StringWriter(); - Serializer serializer = new Serializer(); - serializer.setOutputWriter(sw); - serializer.setOutputProperty(Serializer.Property.OMIT_XML_DECLARATION, "yes"); - formTransformer.setDestination(serializer); - formTransformer.transform(); - this.formHtml = sw.toString(); - if (LOGR.isLoggable(FINE)) - LOGR.fine(this.formHtml); - - if (!recordedForms.isEmpty()) { - RecordedForm.create(recordedForms.next(), this); - } - else if (!web) { - int width = 700; - int height = 500; - attr = (Attr) attrs.getNamedItem("width"); - if (attr != null) { - width = Integer.parseInt(attr.getValue()); - } - attr = (Attr) attrs.getNamedItem("height"); - if (attr != null) { - height = Integer.parseInt(attr.getValue()); - } - SwingForm.create(name, width, height, this); - } - - while (formResults == null) { - if (stop) { - formParsers.clear(); - throw new Exception("Execution was stopped by the user."); - } - Thread.sleep(250); - } - - Document doc = formResults; - if (LOGR.isLoggable(FINE)) - LOGR.fine(DomUtils.serializeNode(doc)); - formResults = null; - formParsers.clear(); - - if (logger != null) { - logger.println(""); - logger.println(DomUtils.serializeNode(doc)); - logger.println(""); - } - return doc; - } - - public void setIndentLevel(int level) { - indent = ""; - for (int i = 0; i < level; i++) { - indent += INDENT; - } - } - - public String getOutput() { - String output = threadOutput.toString(); - threadOutput.reset(); - return output; - } - - public void stopThread() throws Exception { - stop = true; - while (!threadComplete) { - Thread.sleep(100); - } - } - - public boolean isThreadComplete() { - return threadComplete; - } - - public void run() { - threadComplete = false; - // activeThread = Thread.currentThread(); - try { - opts.getLogDir().mkdir(); - threadOutput = new ByteArrayOutputStream(); - out = new PrintStream(threadOutput); - execute(); - out.close(); - } - catch (Exception e) { - jlogger.log(SEVERE, "", e); - } - // activeThread = null; - threadComplete = true; - } - - public File getLogDir() { - return opts.getLogDir(); - } - - public PrintStream getOut() { - return out; - } - - public void setOut(PrintStream out) { - this.out = out; - } - - public String getTestPath() { - return testPath; - } - - /** - * Returns the location of the directory containing the test run output. - * @return A String representing a file URI denoting the path name of a directory. - */ - public String getTestRunDirectory() { - String logDirURI = opts.getLogDir().toURI().toString(); - return logDirURI + opts.getSessionId(); - } - - /** - * Updates the local testPath value. C. Heazel made private since it is never called - * by an external object Could be removed since local classes can set it directly. Or - * augmented by value validation. - */ - private void setTestPath(String testPath) { - this.testPath = testPath; - } - - public boolean isWeb() { - return web; - } - - public void setWeb(boolean web) { - this.web = web; - } - - public Object getFunctionInstance(Integer key) { - return functionInstances.get(key); - } - - public Object putFunctionInstance(Integer key, Object instance) { - return functionInstances.put(key, instance); - } - - public Engine getEngine() { - return engine; - } - - public Index getIndex() { - return index; - } - - public RuntimeOptions getOpts() { - return opts; - } - - public String getTestServletURL() { - return testServletURL; - } - - public void setTestServletURL(String testServletURL) { - this.testServletURL = testServletURL; - } - - /** - * Transform EARL result into HTML report using XSLT. - * @param outputDir - */ - // Fortify Mod: Changed to a private method so that the value of the - // outputDir parameter can be managed. - // Note: that there is no indication that this method is ever called. - public boolean earlHtmlReport(String outputDir) { - TEPath tpath = new TEPath(outputDir); - if (!tpath.isValid()) { - System.out.println("ViewLog Error: Invalid log file name " + outputDir); - return false; - } - EarlToHtmlTransformation earlToHtml = new EarlToHtmlTransformation(); - earlToHtml.earlHtmlReport(outputDir); - return true; - } - - /** - * This method is used to extract the test input into Map from the document element. - * @param userInput Document node - * @param runOpts - * @return User Input Map - */ - private Map extractTestInputs(Document userInput, RuntimeOptions runOpts) { - Map inputMap = new HashMap<>(); - if (null != userInputs) { - NodeList values = userInputs.getDocumentElement().getElementsByTagName("value"); - if (values.getLength() == 0) { - inputMap = Collections.emptyMap(); - } - else { - for (int i = 0; i < values.getLength(); i++) { - Element value = (Element) values.item(i); - inputMap.put(value.getAttribute("key"), value.getTextContent()); - } - } - } - else if (null != opts.getParams()) { - List runParams = opts.getParams(); - for (String param : runParams) { - String[] kvp = param.split("="); - inputMap.put(kvp[0], kvp[1]); - } - } - return inputMap; - } - - private boolean checkForRedirect(HttpURLConnection conn) throws IOException { - int status = conn.getResponseCode(); - if (status != HttpURLConnection.HTTP_OK) { - if (status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_MOVED_PERM - || status == HttpURLConnection.HTTP_SEE_OTHER) - return true; - } - return false; - } - - /** - * Builds a DOM Document representing a classpath resource. - * @param name The name of an XML resource. - * @return A Document node, or {@code null} if the resource cannot be parsed for any - * reason. - */ - public Document findXMLResource(String name) { - URL url = this.getClass().getResource(name); - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); - docFactory.setNamespaceAware(true); - // Fortify Mod: Disable entity expansion to foil External Entity Injections - docFactory.setExpandEntityReferences(false); - Document doc = null; - try { - DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); - doc = docBuilder.parse(url.toURI().toString()); - } - catch (Exception e) { - LOGR.log(Level.WARNING, "Failed to parse classpath resource " + name, e); - } - return doc; - } - -} +/** + * ************************************************************************** + * + * The Original Code is TEAM Engine. + * + * The Initial Developer of the Original Code is Northrop Grumman Corporation + * jointly with The National Technology Alliance. Portions created by Northrop + * Grumman Corporation are Copyright (C) 2005-2006, Northrop Grumman + * Corporation. All Rights Reserved. + * + * Contributor(s): + * S. Gianfranceschi (Intecs): Added the SOAP suport + * C. Heazel (WiSC): Added Fortify adjudication changes + * + *************************************************************************** + */ +package com.occamlab.te; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.BufferedWriter; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.RandomAccessFile; +import java.io.StringReader; +import java.io.StringWriter; +import java.lang.reflect.Method; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Stack; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.CRC32; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import com.occamlab.te.form.ImageHandler; +import com.occamlab.te.html.EarlToHtmlTransformation; + +import net.sf.saxon.dom.NodeOverNodeInfo; +import net.sf.saxon.expr.XPathContext; +import net.sf.saxon.expr.XPathContextMajor; +import net.sf.saxon.instruct.Executable; +import net.sf.saxon.om.NodeInfo; +import net.sf.saxon.s9api.Axis; +import net.sf.saxon.s9api.QName; +import net.sf.saxon.s9api.S9APIUtils; +import net.sf.saxon.s9api.SaxonApiException; +import net.sf.saxon.s9api.Serializer; +import net.sf.saxon.s9api.XdmAtomicValue; +import net.sf.saxon.s9api.XdmDestination; +import net.sf.saxon.s9api.XdmItem; +import net.sf.saxon.s9api.XdmNode; +import net.sf.saxon.s9api.XdmNodeKind; +import net.sf.saxon.s9api.XdmSequenceIterator; +import net.sf.saxon.s9api.XsltExecutable; +import net.sf.saxon.s9api.XsltTransformer; +import net.sf.saxon.trans.XPathException; + +import org.w3c.dom.Attr; +import org.w3c.dom.Comment; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +import com.occamlab.te.index.FunctionEntry; +import com.occamlab.te.index.Index; +import com.occamlab.te.index.ParserEntry; +import com.occamlab.te.index.ProfileEntry; +import com.occamlab.te.index.SuiteEntry; +import com.occamlab.te.index.TemplateEntry; +import com.occamlab.te.index.TestEntry; +import com.occamlab.te.saxon.ObjValue; +import com.occamlab.te.util.Constants; +import com.occamlab.te.util.DomUtils; +import com.occamlab.te.util.IOUtils; +import com.occamlab.te.util.LogUtils; +import com.occamlab.te.util.Misc; +import com.occamlab.te.util.SoapUtils; +import com.occamlab.te.util.StringUtils; +import com.occamlab.te.util.URLConnectionUtils; +import com.occamlab.te.util.TEPath; + +import static java.util.logging.Level.FINE; +import static java.util.logging.Level.SEVERE; + +/** + * Provides various utility methods to support test execution and logging. Primary ones + * include implementation and execution of ctl:suite, ctl:profile, ctl:test, ctl:function, + * ctl:request and ctl:soap-request instructions, and invocation of any parsers specified + * therein. + * + */ +public class TECore implements Runnable { + + private static final Logger LOGR = Logger.getLogger(TECore.class.getName()); + + public static final String SOAP_V_1_1 = "1.1"; + + public static final String SOAP_V_1_2 = "1.2"; + + Engine engine; // Engine object + + Index index; + + public static int testCount = 0; + + int reTestCount = 0; + + public static int methodCount = 0; + + String testName = ""; + + public static String nameOfTest = ""; + + final RuntimeOptions opts; + + String testServletURL = null; + + volatile PrintStream out; // Console destination + + boolean web = false; // True when running as a servlet + + RecordedForms recordedForms; + + private String testPath; // Uniquely identifies a test instance + + String fnPath = ""; // Uniquely identifies an XSL function instance within a + + // test instance + String indent = ""; // Contains the appropriate number of spaces for the + + // current indent level + String contextLabel = ""; // Current context label set by ctl:for-each + + String testType = "Mandatory"; // Type of current test + + String defaultResultName = "Pass"; // Default result name for current test + + int defaultResult = PASS; // Default result for current test + + ArrayList media = new ArrayList<>(); + + public File dirPath; + + Document prevLog = null; // Log document for current test from previous test + + // execution (resume and retest modes only) + // Log document for suite to enable use of getLogCache by profile test + Document suiteLog = null; + + public static String pathURL = ""; + + public static String assertionMsz = ""; + + public static String messageTest = ""; + + PrintWriter logger = null; // Logger for current test + + volatile String formHtml; // HTML representation for an active form + + volatile Document formResults; // Holds form results until they are + + // retrieved + Map formParsers = new HashMap<>(); + + Map functionInstances = new HashMap<>(); + + Map parserInstances = new HashMap<>(); + + Map parserMethods = new HashMap<>(); + + LinkedList testStack = new LinkedList<>(); + + volatile boolean threadComplete = false; + + volatile boolean stop = false; + + volatile ByteArrayOutputStream threadOutput; + + private Stack fnCallStack; + + public static final int CONTINUE = -1; + + public static final int BEST_PRACTICE = 0; + + public static final int PASS = 1; + + public static final int NOT_TESTED = 2; + + public static final int SKIPPED = 3; + + public static final int WARNING = 4; + + public static final int INHERITED_FAILURE = 5; + + public static final int FAIL = 6; + + public static final String MSG_CONTINUE = "Inconclusive! Continue Test"; + + public static final String MSG_BEST_PRACTICE = "Passed as Best Practice"; + + public static final String MSG_PASS = "Passed"; + + public static final String MSG_NOT_TESTED = "Not Tested"; + + public static final String MSG_SKIPPED = "Skipped - Prerequisites not satisfied"; + + public static final String MSG_WARNING = "Warning"; + + public static final String MSG_INHERITED_FAILURE = "Failed - Inherited"; + + public static final String MSG_FAIL = "Failed"; + + public static final int MANDATORY = 0; + + public static final int MANDATORY_IF_IMPLEMENTED = 1; + + public static final int OPTIONAL = 2; + + static final String XSL_NS = Test.XSL_NS; + static final String CTL_NS = Test.CTL_NS; + static final String TE_NS = Test.TE_NS; + static final String INDENT = " "; + static final QName TECORE_QNAME = new QName("te", TE_NS, "core"); + static final QName TEPARAMS_QNAME = new QName("te", TE_NS, "params"); + static final QName LOCALNAME_QNAME = new QName("local-name"); + static final QName LABEL_QNAME = new QName("label"); + static final String HEADER_BLOCKS = "header-blocks"; + + private static Logger jlogger = Logger.getLogger("com.occamlab.te.TECore"); + + public static DocumentBuilderFactory icFactory; + + public static DocumentBuilder icBuilder; + + public static Document doc; + + public static Element mainRootElement; + + public static DocumentBuilderFactory icFactoryClause; + + public static DocumentBuilder icBuilderClause; + + public static Document docClause; + + public static Element mainRootElementClause; + + public static String TESTNAME = ""; + + public static int rootNo = 0; + + public static String Clause = ""; + + public static String Purpose = ""; + + public static ArrayList rootTestName = new ArrayList<>(); + + public Document userInputs = null; + + public Boolean supportHtmlReport = false; + + public final ImageHandler imageHandler; + + public TECore() { + this.opts = null; + this.imageHandler = null; + } + + public TECore(Engine engine, Index index, RuntimeOptions opts) { + this.engine = engine; + this.index = index; + this.opts = opts; + this.recordedForms = new RecordedForms(opts.getRecordedForms()); + this.testPath = opts.getSessionId(); + this.out = System.out; + this.imageHandler = new ImageHandler(opts.getLogDir(), opts.getSessionId()); + this.fnCallStack = new Stack<>(); + } + + public TestEntry getParentTest() { + if (testStack.size() < 2) { + return testStack.peek(); + } + else { + return testStack.get(1); + } + } + + public String getParamsXML(List params) throws Exception { + String paramsXML = ""; + for (int i = 0; i < params.size(); i++) { + String param = params.get(i); + String name = param.substring(0, param.indexOf('=')); + String value = param.substring(param.indexOf('=') + 1); + if (params.get(i).indexOf('=') != 0) { + paramsXML += ""; + paramsXML += ""; + paramsXML += ""; + } + } + paramsXML += ""; + // System.out.println("paramsXML: "+paramsXML); + return paramsXML; + } + + XPathContext getXPathContext(TestEntry test, String sourcesName, XdmNode contextNode) throws Exception { + XPathContext context = null; + if (test.usesContext() && contextNode != null) { + XsltExecutable xe = engine.loadExecutable(test, sourcesName); + Executable ex = xe.getUnderlyingCompiledStylesheet().getExecutable(); + context = new XPathContextMajor(contextNode.getUnderlyingNode(), ex); + } + return context; + } + + // Execute tests + public void execute() throws Exception { + try { + TestEntry grandParent = new TestEntry(); + grandParent.setType("Mandatory"); + grandParent.setResult(CONTINUE); + testStack.push(grandParent); + String sessionId = opts.getSessionId(); + int mode = opts.getMode(); + ArrayList params = opts.getParams(); + + if (mode == Test.RESUME_MODE) { + reexecute_test(sessionId); + } + else if (mode == Test.REDO_FROM_CACHE_MODE) { + reexecute_test(sessionId); + } + else if (mode == Test.RETEST_MODE) { + for (String testPath : opts.getTestPaths()) { + reexecute_test(testPath); + } + } + else if (mode == Test.TEST_MODE || mode == Test.DOC_MODE) { + String testName = opts.getTestName(); + if (!testName.isEmpty()) { + // NOTE: getContextNode() always returns null + XdmNode contextNode = opts.getContextNode(); + execute_test(testName, params, contextNode); + } + else { + String suiteName = opts.getSuiteName(); + List profiles = opts.getProfiles(); + if (!suiteName.isEmpty() || profiles.size() == 0) { + execute_suite(suiteName, params); + } + if (profiles.contains("*")) { + for (String profile : index.getProfileKeys()) { + try { + execute_profile(profile, params, false); + } + catch (Exception e) { + jlogger.log(Level.WARNING, e.getMessage(), e.getCause()); + } + } + } + else { + for (String profile : profiles) { + try { + execute_profile(profile, params, true); + } + catch (Exception e) { + jlogger.log(Level.WARNING, e.getMessage(), e.getCause()); + } + } + } + } + } + else { + throw new Exception("Unsupported mode"); + } + } + finally { + if (!web) { + SwingForm.destroy(); + } + if (opts.getLogDir() != null) { + // Create xml execution report file + LogUtils.createFullReportLog(opts.getLogDir().getAbsolutePath() + File.separator + opts.getSessionId()); + File resultsDir = new File(opts.getLogDir(), opts.getSessionId()); + if (supportHtmlReport) { + Map testInputMap = new HashMap<>(); + testInputMap = extractTestInputs(userInputs, opts); + + if (!new File(resultsDir, "testng").exists() && null != testInputMap) { + /* + * Transform CTL result into EARL result, when the CTL test is + * executed through the webapp. + */ + try { + + File testLog = new File(resultsDir, "report_logs.xml"); + CtlEarlReporter report = new CtlEarlReporter(); + + if (null != opts.getSourcesName()) { + report.generateEarlReport(resultsDir, testLog, opts.getSourcesName(), testInputMap); + } + } + catch (IOException iox) { + throw new RuntimeException("Failed to serialize EARL results to " + iox); + } + } + } + } + } + } + + public void reexecute_test(String testPath) throws Exception { + File deleteExistingResultDir = new File( + opts.getLogDir() + File.separator + testPath + File.separator + "result"); + if (deleteExistingResultDir.exists()) { + Misc.deleteDir(deleteExistingResultDir); + } + File deleteExistingTestngDir = new File( + opts.getLogDir() + File.separator + testPath + File.separator + "testng"); + if (deleteExistingTestngDir.exists()) { + Misc.deleteDir(deleteExistingTestngDir); + } + Document log = LogUtils.readLog(opts.getLogDir(), testPath); + String testId = LogUtils.getTestIdFromLog(log); + TestEntry test = index.getTest(testId); + net.sf.saxon.s9api.DocumentBuilder builder = engine.getBuilder(); + XdmNode paramsNode = LogUtils.getParamsFromLog(builder, log); + XdmNode contextNode = LogUtils.getContextFromLog(builder, log); + XPathContext context = getXPathContext(test, opts.getSourcesName(), contextNode); + setTestPath(testPath); + executeTest(test, paramsNode, context); + if (testPath.equals(opts.getSessionId())) { + // Profile not executed in retest mode + suiteLog = LogUtils.readLog(opts.getLogDir(), testPath); + ArrayList params = opts.getParams(); + List profiles = opts.getProfiles(); + if (profiles.contains("*")) { + for (String profile : index.getProfileKeys()) { + try { + execute_profile(profile, params, false); + } + catch (Exception e) { + jlogger.log(Level.WARNING, e.getMessage(), e.getCause()); + } + } + } + else { + for (String profile : profiles) { + try { // 2011-12-21 PwD + execute_profile(profile, params, true); + } + catch (Exception e) { + jlogger.log(Level.WARNING, e.getMessage(), e.getCause()); + } + } + } + } + } + + public int execute_test(String testName, List params, XdmNode contextNode) throws Exception { + if (LOGR.isLoggable(FINE)) { + String logMsg = String.format("Preparing test %s for execution, using params:%n %s", testName, params); + LOGR.fine(logMsg); + } + TestEntry test = index.getTest(testName); + if (test == null) { + throw new Exception("Error: Test " + testName + " not found."); + } + XdmNode paramsNode = engine.getBuilder().build(new StreamSource(new StringReader(getParamsXML(params)))); + if (contextNode == null && test.usesContext()) { + String contextNodeXML = "" + test.getContext() + ""; + contextNode = engine.getBuilder().build(new StreamSource(new StringReader(contextNodeXML))); + } + XPathContext context = getXPathContext(test, opts.getSourcesName(), contextNode); + return executeTest(test, paramsNode, context); + } + + public void execute_suite(String suiteName, List params) throws Exception { + SuiteEntry suite = null; + if (suiteName == null || suiteName.isEmpty()) { + Iterator it = index.getSuiteKeys().iterator(); + if (!it.hasNext()) { + throw new Exception("Error: No suites in sources."); + } + suite = index.getSuite(it.next()); + if (it.hasNext()) { + throw new Exception( + "Error: Suite name must be specified since there is more than one suite in sources."); + } + } + else { + suite = index.getSuite(suiteName); + if (suite == null) { + throw new Exception("Error: Suite " + suiteName + " not found."); + } + } + defaultResultName = suite.getDefaultResult(); + defaultResult = defaultResultName.equals("BestPractice") ? BEST_PRACTICE : PASS; + testStack.peek().setDefaultResult(defaultResult); + testStack.peek().setResult(defaultResult); + + ArrayList kvps = new ArrayList<>(params); + Document form = suite.getForm(); + if (form != null) { + Document results = (Document) form(form, suite.getId()); + for (Element value : DomUtils.getElementsByTagName(results, "value")) { + kvps.add(value.getAttribute("key") + "=" + value.getTextContent()); + } + } + String name = suite.getPrefix() + ":" + suite.getLocalName(); + out.println( + "Testing suite " + name + " in " + getMode() + " with defaultResult of " + defaultResultName + " ..."); + RecordTestResult recordTestResult = new RecordTestResult(); + if (opts.getLogDir() != null) { + recordTestResult.recordingStartCheck(suite); + recordTestResult.recordingStartClause(suite); + } + setIndentLevel(1); + int result = execute_test(suite.getStartingTest().toString(), kvps, null); + recordTestResult.detailTestPath(); + reTestCount = 0; + out.print("Suite " + suite.getPrefix() + ":" + suite.getLocalName() + " "); + if (result == TECore.FAIL || result == TECore.INHERITED_FAILURE) { + out.println(MSG_FAIL); + } + else if (result == TECore.WARNING) { + out.println(MSG_WARNING); + } + else if (result == TECore.BEST_PRACTICE) { + out.println(MSG_BEST_PRACTICE); + } + else { + out.println(MSG_PASS); + } + if (opts.getLogDir() != null) { + recordTestResult.saveRecordingClause(suite, dirPath); + recordTestResult.saveRecordingData(suite, dirPath); + } + } + + public void execute_profile(String profileName, List params, boolean required) throws Exception { + ProfileEntry profile = index.getProfile(profileName); + if (profile == null) { + throw new Exception("Error: Profile " + profileName + " not found."); + } + SuiteEntry suite = index.getSuite(profile.getBaseSuite()); + if (suite == null) { + throw new Exception("Error: The base suite (" + profile.getBaseSuite().toString() + ") for the profile (" + + profileName + ") not found."); + } + String sessionId = opts.getSessionId(); + Document log = LogUtils.readLog(opts.getLogDir(), sessionId); + if (log == null) { + execute_suite(suite.getId(), params); + log = LogUtils.readLog(opts.getLogDir(), sessionId); + } + suiteLog = log; + String testId = LogUtils.getTestIdFromLog(log); + List baseParams = LogUtils.getParamListFromLog(engine.getBuilder(), log); + TestEntry test = index.getTest(testId); + if (suite.getStartingTest().equals(test.getQName())) { + ArrayList kvps = new ArrayList<>(); + kvps.addAll(baseParams); + kvps.addAll(params); + Document form = profile.getForm(); + if (form != null) { + Document results = (Document) form(form, profile.getId()); + for (Element value : DomUtils.getElementsByTagName(results, "value")) { + kvps.add(value.getAttribute("key") + "=" + value.getTextContent()); + } + } + setTestPath(sessionId + "/" + profile.getLocalName()); + String name = profile.getPrefix() + ":" + profile.getLocalName(); + out.println("\nTesting profile " + name + "..."); + Document baseLog = LogUtils.makeTestList(opts.getLogDir(), sessionId, profile.getExcludes()); + Element baseTest = DomUtils.getElement(baseLog); + // out.println(DomUtils.serializeNode(baseLog)); + out.print(TECore.INDENT + "Base tests from suite " + suite.getPrefix() + ":" + suite.getLocalName() + " "); + String summary = "Not complete"; + if ("yes".equals(baseTest.getAttribute("complete"))) { + int baseResult = Integer.parseInt(baseTest.getAttribute("result")); + summary = getResultDescription(baseResult); + } + out.println(summary); + setIndentLevel(1); + String defaultResultName = profile.getDefaultResult(); + defaultResult = defaultResultName.equals("BestPractice") ? BEST_PRACTICE : PASS; + out.println("\nExecuting profile " + name + " with defaultResult of " + defaultResultName + "..."); + int result = execute_test(profile.getStartingTest().toString(), kvps, null); + out.print("Profile " + profile.getPrefix() + ":" + profile.getLocalName() + " "); + summary = getResultDescription(result); + out.println(summary); + } + else { + if (required) { + throw new Exception( + "Error: Profile " + profileName + " is not a valid profile for session " + sessionId + "."); + } + } + } + + public XdmNode executeTemplate(TemplateEntry template, XdmNode params, XPathContext context) throws Exception { + if (stop) { + throw new Exception("Execution was stopped by the user."); + } + XsltExecutable executable = engine.loadExecutable(template, opts.getSourcesName()); + XsltTransformer xt = executable.load(); + XdmDestination dest = new XdmDestination(); + xt.setDestination(dest); + if (template.usesContext() && context != null) { + xt.setSource((NodeInfo) context.getContextItem()); + } + else { + xt.setSource(new StreamSource(new StringReader(""))); + } + xt.setParameter(TECORE_QNAME, new ObjValue(this)); + if (params != null) { + xt.setParameter(TEPARAMS_QNAME, params); + } + // test may set global verdict, e.g. by calling ctl:fail + if (LOGR.isLoggable(FINE)) { + LOGR.log(FINE, "Executing TemplateEntry {0}" + template.getQName()); + } + xt.transform(); + XdmNode ret = dest.getXdmNode(); + if (ret != null && LOGR.isLoggable(FINE)) { + LOGR.log(FINE, "Output:\n" + ret.toString()); + } + return ret; + } + + static String getLabel(XdmNode n) { + String label = n.getAttributeValue(LABEL_QNAME); + if (label == null) { + XdmNode value = (XdmNode) n.axisIterator(Axis.CHILD).next(); + XdmItem childItem = null; + try { + childItem = value.axisIterator(Axis.CHILD).next(); + } + catch (Exception e) { + // Not an error + } + if (childItem == null) { + XdmSequenceIterator it = value.axisIterator(Axis.ATTRIBUTE); + if (it.hasNext()) { + label = it.next().getStringValue(); + } + else { + label = ""; + } + } + else if (childItem.isAtomicValue()) { + label = childItem.getStringValue(); + } + else if (childItem instanceof XdmNode) { + XdmNode n2 = (XdmNode) childItem; + if (n2.getNodeKind() == XdmNodeKind.ELEMENT) { + label = "<" + n2.getNodeName().toString() + ">"; + } + else { + label = n2.toString(); + } + } + } + return label; + } + + String getAssertionValue(String text, XdmNode paramsVar) { + if (text.indexOf("$") < 0) { + return text; + } + String newText = text; + XdmNode params = (XdmNode) paramsVar.axisIterator(Axis.CHILD).next(); + XdmSequenceIterator it = params.axisIterator(Axis.CHILD); + while (it.hasNext()) { + XdmNode n = (XdmNode) it.next(); + QName qname = n.getNodeName(); + if (qname != null) { + String tagname = qname.getLocalName(); + if (tagname.equals("param")) { + String name = n.getAttributeValue(LOCALNAME_QNAME); + String label = getLabel(n); + newText = StringUtils.replaceAll(newText, "{$" + name + "}", label); + } + } + } + newText = StringUtils.replaceAll(newText, "{$context}", contextLabel); + return newText; + } + + static String getResultDescription(int result) { + if (result == CONTINUE) { + return MSG_CONTINUE; + } + else if (result == BEST_PRACTICE) { + return MSG_BEST_PRACTICE; + } + else if (result == PASS) { + return MSG_PASS; + } + else if (result == NOT_TESTED) { + return MSG_NOT_TESTED; + } + else if (result == SKIPPED) { + return MSG_SKIPPED; + } + else if (result == WARNING) { + return MSG_WARNING; + } + else if (result == INHERITED_FAILURE) { + return MSG_INHERITED_FAILURE; + } + else { + return MSG_FAIL; + } + } + + /** + * Executes a test implemented as an XSLT template. + * @param test Provides information about the test (gleaned from an entry in the test + * suite index). + * @param params A node representing test run arguments. + * @param context A context in which the template is evaluated. + * @return An integer value indicating the test result. + * @throws Exception If any error arises while executing the test. + */ + public int executeTest(TestEntry test, XdmNode params, XPathContext context) throws Exception { + testType = test.getType(); + // It is possible to get here without setting testPath. Make sure it is set. + if (testPath == null) + testPath = opts.getSessionId(); + defaultResult = test.getDefaultResult(); + defaultResultName = (defaultResult == BEST_PRACTICE) ? "BestPractice" : "Pass"; + Document oldPrevLog = prevLog; + if (opts.getMode() == Test.RESUME_MODE) { + prevLog = readLog(); + } + else if (opts.getMode() == Test.REDO_FROM_CACHE_MODE) { + prevLog = readLog(); + } + else { + prevLog = null; + } + String assertion = getAssertionValue(test.getAssertion(), params); + // seperate two sub test. + out.println( + "******************************************************************************************************************************"); + out.print(indent + "Testing "); + out.print(test.getName() + " type " + test.getType()); + + // Check test is contain client test main layer or not + + if (rootTestName != null && rootTestName.size() > 0) { + for (int i = 0; i < rootTestName.size(); i++) { + if ((test.getName()).contains(rootTestName.get(i))) { + methodCount = methodCount + 1; + } + } + } + + out.print(" in " + getMode() + " with defaultResult " + defaultResultName + " "); + String testName = test.getName() + " type " + test.getType(); + System.setProperty("TestName", testName); + out.println("(" + testPath + ")..."); + if (opts.getLogDir() != null) { + String logDir = opts.getLogDir() + "/" + testPath.split("/")[0]; + // Fortify Mod: Add TEPath validation of the log directory path + TEPath tpath = new TEPath(logDir); + // create log directory + if (tpath.isValid() && "True".equals(System.getProperty("Record"))) { + dirPath = new File(logDir + "/test_data"); + if (!dirPath.exists()) { + if (!dirPath.mkdir()) { + System.out.println("Failed to create Error Log!"); + } + } + } + } + + // Delete files for coverage report. + if (reTestCount == 0) { + if (getMode().contains("Retest")) { + if (null != dirPath) { + if (dirPath.isDirectory()) { + File[] files = dirPath.listFiles(); + if (files != null && files.length > 0) { + for (File aFile : files) { + aFile.delete(); + } + } + dirPath.delete(); + } + else { + dirPath.delete(); + } + } + reTestCount = 1; + } + } + String oldIndent = indent; + indent += INDENT; + if (test.usesContext()) { + out.println(indent + "Context: " + test.getContext()); + } + out.println(indent + "Assertion: " + assertion); + assertionMsz = assertion; + PrintWriter oldLogger = logger; + if (opts.getLogDir() != null) { + logger = createLog(); + logger.println(""); + logger.print(""); + logger.println("" + StringUtils.escapeXML(assertion) + ""); + if (params != null) { + logger.println(params.toString()); + pathURL = params.toString(); + } + if (test.usesContext()) { + logger.print(""); + logger.print(""); + logger.print(test.getContext()); + logger.print(""); + logger.println(""); + } + logger.println(""); + logger.flush(); + } + + test.setResult(CONTINUE); + RecordTestResult recordTestResult = new RecordTestResult(); + recordTestResult.storeStartTestDetail(test, dirPath); + try { + testStack.push(test); + executeTemplate(test, params, context); + if (test.getResult() == CONTINUE) { + test.setResult(defaultResult); + } + } + catch (SaxonApiException e) { + jlogger.log(SEVERE, e.getMessage()); + DateFormat dateFormat = new SimpleDateFormat(Constants.YYYY_M_MDD_H_HMMSS); + Date date = new Date(); + try { + String path = System.getProperty("PATH") + "/error_log"; + File file = new File(path); + if (!file.exists()) { + if (!file.mkdir()) { + System.out.println("Failed to create Error Log!"); + } + } + file = new File(path, "log.txt"); + if (!file.exists()) { + try { + boolean fileCreated = file.createNewFile(); + } + catch (IOException ioe) { + System.out.println("Error while creating empty file: " + ioe); + } + } + OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file, true), + StandardCharsets.UTF_8); + BufferedWriter fbw = new BufferedWriter(writer); + fbw.write(dateFormat.format(date) + " ERROR"); + fbw.newLine(); + fbw.write("Test Name : " + System.getProperty("TestName")); + fbw.newLine(); + fbw.write("Failed to execute the extension function: "); + e.printStackTrace(new PrintWriter(fbw)); + fbw.newLine(); + fbw.close(); + } + catch (IOException exep) { + System.out.println("Error: " + e.getMessage()); + } + if (logger != null) { + logger.println(""); + } + test.setResult(FAIL); + } + finally { + updateParentTestResult(test); + testStack.pop(); + if (logger != null) { + logger.println(""); + + if (test.isConformanceClass()) { + logger.println(""); + supportHtmlReport = true; + } + logger.println(""); + logger.flush(); + logger.close(); + } + // Add missing info in the log.xml E.g. endtag ' or' endtest ''. + if (opts.getLogDir() != null && testPath != null) { + String logDir = opts.getLogDir() + "/" + testPath; + addMissingInfo(logDir, test); + } + } + // Create node which contain all test detail. + if ("True".equals(System.getProperty("Record"))) { + mainRootElement.appendChild(RecordTestResult.getMethod()); + } + assertionMsz = ""; + pathURL = ""; + messageTest = ""; + logger = oldLogger; + prevLog = oldPrevLog; + indent = oldIndent; + DateFormat dateFormat = new SimpleDateFormat(Constants.YYYY_M_MDD_H_HMMSS); + Calendar cal = Calendar.getInstance(); + out.println(indent + "Test " + test.getName() + " " + getResultDescription(test.getResult())); + recordTestResult.storeFinalTestDetail(test, dateFormat, cal, dirPath); + if (LOGR.isLoggable(FINE)) { + String msg = String.format("Executed test %s - Verdict: %s", test.getLocalName(), + getResultDescription(test.getResult())); + LOGR.log(FINE, msg); + } + + return test.getResult(); + } + + public void addMissingInfo(String dir, TestEntry test) { + + String logdir = dir + File.separator + "log.xml"; + DocumentBuilderFactory dbf = null; + DocumentBuilder docBuilder = null; + Document doc = null; + File logfile = new File(logdir); + try { + dbf = DocumentBuilderFactory.newInstance(); + docBuilder = dbf.newDocumentBuilder(); + docBuilder.setErrorHandler(null); + doc = docBuilder.parse(logfile); + + } + catch (Exception e) { + + try { + FileWriter fw = new FileWriter(logdir, true); + BufferedWriter bw = new BufferedWriter(fw); + PrintWriter out = new PrintWriter(bw); + out.println(""); + out.close(); + bw.close(); + doc = docBuilder.parse(logfile); + } + catch (Exception ex) { + throw new RuntimeException("Unable to update missing information in " + logdir); + } + + } + + NodeList nl = doc.getElementsByTagName("endtest"); + if (nl.getLength() == 0) { + + Element root = doc.getDocumentElement(); + appendEndTestElement(test, doc, root); + appendConformanceClassElement(test, doc, root); + } + + try { + DOMSource source = new DOMSource(doc); + + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + StreamResult result = new StreamResult(logfile); + transformer.transform(source, result); + } + catch (Exception ex) { + throw new RuntimeException("Unable to update missing information in " + logdir); + } + + } + + private void appendEndTestElement(TestEntry test, Document doc, Element root) { + Element endtest = doc.createElement("endtest"); + + Attr resultAttribute = doc.createAttribute("result"); + resultAttribute.setValue(Integer.toString(test.getResult())); + + endtest.setAttributeNode(resultAttribute); + root.appendChild(endtest); + } + + private void appendConformanceClassElement(TestEntry test, Document doc, Element root) { + if (test.isConformanceClass()) { + Element conformanceClass = doc.createElement("conformanceClass"); + + Attr nameAttribute = doc.createAttribute("name"); + nameAttribute.setValue(test.getLocalName()); + + Attr isBasicAttribute = doc.createAttribute("isBasic"); + isBasicAttribute.setValue(Boolean.toString(test.isBasic())); + + Attr resultAttribute = doc.createAttribute("result"); + resultAttribute.setValue(Integer.toString(test.getResult())); + + conformanceClass.setAttributeNode(nameAttribute); + conformanceClass.setAttributeNode(isBasicAttribute); + conformanceClass.setAttributeNode(resultAttribute); + root.appendChild(conformanceClass); + } + + } + + /** + * Runs a subtest as directed by a <ctl:call-test> instruction. + * @param context The context in which the subtest is executed. + * @param localName The [local name] of the subtest. + * @param namespaceURI The [namespace name] of the subtest. + * @param params A NodeInfo object containing test parameters. + * @param callId A node identifier used to build a file path reference for the test + * results. + * @throws Exception If an error occcurs while executing the test. + */ + public synchronized void callTest(XPathContext context, String localName, String namespaceURI, NodeInfo params, + String callId) throws Exception { + String key = "{" + namespaceURI + "}" + localName; + TestEntry test = index.getTest(key); + if (logger != null) { + logger.println(""); + logger.flush(); + } + if (opts.getMode() == Test.RESUME_MODE) { + Document doc = LogUtils.readLog(opts.getLogDir(), testPath + "/" + callId); + int result = LogUtils.getResultFromLog(doc); + if (result == CONTINUE) { + throw new IllegalStateException( + "Error: 'continue' is not allowed when a test is called using 'call-test' instruction"); + } + else { + out.println(indent + "Test " + test.getName() + " " + getResultDescription(result)); + test.setResult(result); + updateParentTestResult(test); + return; + } + } + + String oldTestPath = testPath; + testPath += "/" + callId; + int result = CONTINUE; + try { + result = executeTest(test, S9APIUtils.makeNode(params), context); + } + catch (Exception e) { + + } + finally { + testPath = oldTestPath; + } + if (result == CONTINUE) { + throw new IllegalStateException( + "Error: 'continue' is not allowed when a test is called using 'call-test' instruction"); + } + } + + /** + * Modifies the result of the parent test according to the result of the current test. + * The parent test will be 'tainted' with an inherited failure if (a) a subtest + * failed, or (b) a required subtest was skipped. + * @param currTest The TestEntry for the current test. + */ + private void updateParentTestResult(TestEntry currTest) { + TestEntry parentTest = getParentTest(); + if (null == parentTest) + return; + if (LOGR.isLoggable(FINE)) { + LOGR.log(FINE, "Entered setParentTestResult with TestEntry {0} (result={1})", + new Object[] { currTest.getQName(), currTest.getResult() }); + LOGR.log(FINE, "Parent TestEntry is {0} (result={1})", + new Object[] { parentTest.getQName(), parentTest.getResult() }); + } + switch (currTest.getResult()) { + case FAIL: + // fall through + case INHERITED_FAILURE: + parentTest.setResult(INHERITED_FAILURE); + break; + case SKIPPED: + if (currTest.getType().equalsIgnoreCase("Mandatory")) { + parentTest.setResult(INHERITED_FAILURE); + } + break; + default: + parentTest.setResult(Integer.max(currTest.getResult(), parentTest.getResult())); + break; + } + } + + /* + * ctl:repeat-test is not documented and is not used in any + * https://github.com/opengeospatial ETS + */ + /* + * public void repeatTest(XPathContext context, String localName, String NamespaceURI, + * NodeInfo params, String callId, int count, int pause) throws Exception { String key + * = "{" + NamespaceURI + "}" + localName; TestEntry test = index.getTest(key); + * + * if (logger != null) { logger.println(""); logger.flush(); } if (opts.getMode() == Test.RESUME_MODE) { Document doc + * = LogUtils.readLog(opts.getLogDir(), testPath + "/" + callId); int result = + * LogUtils.getResultFromLog(doc); if (result >= 0) { out.println(indent + "Test " + + * test.getName() + " " + getResultDescription(result)); if (result == WARNING) { + * warning(); } else if (result != PASS) { inheritedFailure(); } return; } } int + * oldResult = verdict; String oldTestPath = testPath; testPath += "/" + callId; + * + * for (int i = 0; i < count; i++) { executeTest(test, S9APIUtils.makeNode(params), + * context); testPath = oldTestPath; if (verdict == FAIL && oldResult != FAIL) { // If + * the child result was FAIL and parent hasn't directly // failed, // set parent + * result to INHERITED_FAILURE verdict = INHERITED_FAILURE; + * + * return; } else if (verdict == CONTINUE) { // + * System.out.println("Pausing for..."+pause); if (pause > 0 && i < count - 1) { + * + * try { + * + * Thread.sleep(pause); } catch (Exception e) { e.printStackTrace(); } } + * + * } else if (verdict <= oldResult) { // Restore parent result if the child results + * aren't worse verdict = oldResult; return; + * + * } } verdict = FAIL; if (oldResult != FAIL) { // If the child result was FAIL and + * parent hasn't directly failed, // set parent result to INHERITED_FAILURE verdict = + * INHERITED_FAILURE; } + * + * } + */ + + public NodeInfo executeXSLFunction(XPathContext context, FunctionEntry fe, NodeInfo params) throws Exception { + String oldFnPath = fnPath; + CRC32 crc = new CRC32(); + crc.update((fe.getPrefix() + fe.getId()).getBytes()); + fnPath += Long.toHexString(crc.getValue()) + "/"; + XdmNode n = executeTemplate(fe, S9APIUtils.makeNode(params), context); + fnPath = oldFnPath; + if (n == null) { + return null; + } + return n.getUnderlyingNode(); + } + + public Object callFunction(XPathContext context, String localName, String namespaceURI, NodeInfo params) + throws Exception { + // System.out.println("callFunction {" + NamespaceURI + "}" + + // localName); + String key = "{" + namespaceURI + "}" + localName; + List functions = index.getFunctions(key); + Node paramsNode = NodeOverNodeInfo.wrap(params); + List paramElements = DomUtils.getElementsByTagName(paramsNode, "param"); + for (FunctionEntry fe : functions) { + if (!fe.isJava()) { + boolean valid = true; + for (Element el : paramElements) { + String uri = el.getAttribute("namespace-uri"); + String name = el.getAttribute("local-name"); + String prefix = el.getAttribute("prefix"); + javax.xml.namespace.QName qname = new javax.xml.namespace.QName(uri, name, prefix); + if (!fe.getParams().contains(qname)) { + valid = false; + break; + } + } + if (valid) { + if (opts.getMode() == Test.DOC_MODE) { + if (fnCallStack.contains(key)) { + return null; + } + else { + fnCallStack.add(key); + Object result = executeXSLFunction(context, fe, params); + fnCallStack.pop(); + return result; + } + } + else { + return executeXSLFunction(context, fe, params); + } + } + } + } + + if (opts.getMode() == Test.DOC_MODE) { + return null; + } + + for (FunctionEntry fe : functions) { + if (fe.isJava()) { + int argCount = paramElements.size(); + if (fe.getMinArgs() >= argCount && fe.getMaxArgs() <= argCount) { + TEClassLoader cl = engine.getClassLoader(opts.getSourcesName()); + Method method = Misc.getMethod(fe.getClassName(), fe.getMethod(), cl, argCount); + Class[] types = method.getParameterTypes(); + Object[] args = new Object[argCount]; + for (int i = 0; i < argCount; i++) { + Element el = DomUtils.getElementByTagName(paramElements.get(i), "value"); + if (types[i].equals(String.class)) { + Map attrs = DomUtils.getAttributes(el); + if (attrs.size() > 0) { + args[i] = attrs.values().iterator().next(); + } + else { + args[i] = el.getTextContent(); + } + } + else if (types[i].toString().equals("char")) { + args[i] = el.getTextContent().charAt(0); + } + else if (types[i].toString().equals("boolean")) { + args[i] = Boolean.parseBoolean(el.getTextContent()); + } + else if (types[i].toString().equals("byte")) { + args[i] = Byte.parseByte(el.getTextContent()); + } + else if (types[i].toString().equals("short")) { + args[i] = Short.parseShort(el.getTextContent()); + } + else if (types[i].toString().equals("int")) { + args[i] = Integer.parseInt(el.getTextContent()); + } + else if (types[i].toString().equals("long")) { + args[i] = Long.parseLong(el.getTextContent()); + } + else if (types[i].toString().equals("float")) { + args[i] = Float.parseFloat(el.getTextContent()); + } + else if (types[i].toString().equals("double")) { + args[i] = Double.parseDouble(el.getTextContent()); + } + else if (Document.class.isAssignableFrom(types[i])) { + args[i] = DomUtils.createDocument(DomUtils.getChildElement(el)); + } + else if (NodeList.class.isAssignableFrom(types[i])) { + args[i] = el.getChildNodes(); + } + else if (Node.class.isAssignableFrom(types[i])) { + args[i] = el.getFirstChild(); + } + else { + throw new Exception( + "Error: Function " + key + " uses unsupported Java type " + types[i].toString()); + } + } + try { + Object instance = null; + if (fe.isInitialized()) { + // String instkey = fe.getId() + "," + + // Integer.toString(fe.getMinArgs()) + "," + + // Integer.toString(fe.getMaxArgs()); + instance = getFunctionInstance(fe.hashCode()); + if (instance == null) { + try { + instance = Misc.makeInstance(fe.getClassName(), fe.getClassParams(), cl); + putFunctionInstance(fe.hashCode(), instance); + } + catch (Exception e) { + throw new XPathException(e); + } + } + } + return method.invoke(instance, args); + } + catch (java.lang.reflect.InvocationTargetException e) { + Throwable cause = e.getCause(); + String msg = "Error invoking function " + fe.getId() + "\n" + cause.getClass().getName(); + if (cause.getMessage() != null) { + msg += ": " + cause.getMessage(); + } + jlogger.log(SEVERE, "InvocationTargetException", e); + + throw new Exception(msg, cause); + } + } + } + } + throw new Exception("No function {" + namespaceURI + "}" + localName + " with a compatible signature."); + } + + public void _continue() { + testStack.peek().setResult(CONTINUE); + } + + public void bestPractice() { + if (testStack.peek().getResult() < BEST_PRACTICE) { + testStack.peek().setResult(BEST_PRACTICE); + } + } + + public void notTested() { + if (testStack.peek().getResult() < NOT_TESTED) { + testStack.peek().setResult(NOT_TESTED); + } + } + + public void skipped() { + if (testStack.peek().getResult() < SKIPPED) { + testStack.peek().setResult(SKIPPED); + } + } + + public void pass() { + if (testStack.peek().getResult() < PASS) { + testStack.peek().setResult(PASS); + } + } + + public void warning() { + if (testStack.peek().getResult() < WARNING) { + testStack.peek().setResult(WARNING); + } + } + + public void inheritedFailure() { + if (testStack.peek().getResult() < INHERITED_FAILURE) { + testStack.peek().setResult(INHERITED_FAILURE); + } + } + + public void fail() { + testStack.peek().setResult(FAIL); + } + + public String getResult() { + return getResultDescription(testStack.getLast().getResult()); + } + + public String getMode() { + return Test.getModeName(opts.getMode()); + } + + public void setContextLabel(String label) { + contextLabel = label; + } + + public String getFormHtml() { + return formHtml; + } + + public void setFormHtml(String html) { + this.formHtml = html; + } + + public Document getFormResults() { + return formResults; + } + + public void setFormResults(Document doc) { + try { + StringWriter sw = new StringWriter(); + // Fortify Mod: prevent external entity injection + TransformerFactory tf = TransformerFactory.newInstance(); + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer transformer = tf.newTransformer(); + // End Fortify Mod + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + transformer.transform(new DOMSource(doc), new StreamResult(sw)); + if (userInputs == null) { + userInputs = doc; + } + LOGR.info("Setting form results:\n " + sw.toString()); + } + catch (Exception e) { + LOGR.log(SEVERE, "Failed to log the form results", e); + } + this.formResults = doc; + } + + public Map getFormParsers() { + return formParsers; + } + + public Document readLog() throws Exception { + return LogUtils.readLog(opts.getLogDir(), testPath); + } + + public PrintWriter createLog() throws Exception { + return LogUtils.createLog(opts.getLogDir(), testPath); + } + + // Get a File pointer to a file reference (in XML) + public static File getFile(NodeList fileNodes) { + File file = null; + for (int i = 0; i < fileNodes.getLength(); i++) { + Element e = (Element) fileNodes.item(i); + String type = e.getAttribute("type"); + + try { + // URL, File, or Resource + if (type.equals("url")) { + URL url = new URL(e.getTextContent()); + file = new File(url.toURI()); + } + else if (type.equals("file")) { + file = new File(e.getTextContent()); + } + else if (type.equals("resource")) { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + file = new File(cl.getResource(e.getTextContent()).getFile()); + } + else { + System.out.println("Incorrect file reference: Unknown type!"); + } + } + catch (Exception exception) { + System.err.println("Error getting file. " + exception.getMessage()); + jlogger.log(SEVERE, "Error getting file. " + exception.getMessage(), e); + + return null; + } + } + return file; + } + + // BEGIN SOAP SUPPORT + public NodeList soap_request(Document ctlRequest, String id) throws Throwable { + Element request = (Element) ctlRequest.getElementsByTagNameNS(Test.CTL_NS, "soap-request").item(0); + if (opts.getMode() == Test.RESUME_MODE && prevLog != null) { + for (Element request_e : DomUtils.getElementsByTagName(prevLog, "soap-request")) { + if (request_e.getAttribute("id").equals(fnPath + id)) { + logger.println(DomUtils.serializeNode(request_e)); + logger.flush(); + Element response_e = DomUtils.getElementByTagName(request_e, "response"); + Element content_e = DomUtils.getElementByTagName(response_e, "content"); + return content_e.getChildNodes(); + // return DomUtils.getChildElement(content_e); + } + } + } + + String logTag = "\n"; + logTag += DomUtils.serializeNode(request) + "\n"; + // if (logger != null) { + // logger.println(""); + // logger.println(DomUtils.serializeNode(request)); + // } + Exception ex = null; + Element response = null; + Element parserInstruction = null; + NodeList nl = request.getChildNodes(); + long elapsedTime = 0; + for (int i = 0; i < nl.getLength(); i++) { + Node n = nl.item(i); + if (n.getNodeType() == Node.ELEMENT_NODE && !n.getNamespaceURI().equals(CTL_NS)) { + parserInstruction = (Element) n; + } + } + try { + Date before = new Date(); + URLConnection uc = build_soap_request(request); + response = parse(uc, parserInstruction); + Date after = new Date(); + elapsedTime = after.getTime() - before.getTime(); + + // Adding the exchange time in the response as comment the format is + // the following + // + // the comment is included in the first tag of the response + // SOAP:Envelope in case a SOAP message is returned the specific + // interface tag if a SOAP parser is applied + Element content = DomUtils.getElementByTagName(response, "content"); + if (content != null) { + nl = content.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node n = nl.item(i); + if (n.getNodeType() == Node.ELEMENT_NODE) { + Document doc; + doc = response.getOwnerDocument(); + Comment comm = doc.createComment("Response received in [" + elapsedTime + "] milliseconds"); + n.appendChild(comm); + } + } + } + + logTag += DomUtils.serializeNode(response) + "\n"; + jlogger.log(FINE, DomUtils.serializeNode(response)); + } + catch (Exception e) { + ex = e; + } + logTag += ""; + logTag += ""; + if (logger != null) { + logger.println(logTag); + logger.flush(); + } + if (ex == null) { + Element parser = DomUtils.getElementByTagName(response, "parser"); + if (parser != null) { + String text = parser.getTextContent(); + if (text.length() > 0) { + out.println(parser.getTextContent()); + } + } + Element content = DomUtils.getElementByTagName(response, "content"); + return content.getChildNodes(); + } + else { + throw ex; + } + } + + /** + * Create SOAP request, sends it and return an URL Connection ready to be parsed. + * @param xml the soap-request node (from CTL) + * @return The URL Connection + * @throws Exception the exception + * + * <soap-request version="1.1|1.2" charset="UTF-8"> + * <url>http://blah</url> <action>Some-URI</action> + * <headers> <header MutUnderstand="true" rely="true" role="http://etc"> + * <t:Transaction xmlns:t="some-URI" >5</t:Transaction> </header> + * </headers> <body> <m:GetLastTradePrice xmlns:m="Some-URI"> + * <symbol>DEF</symbol> </m:GetLastTradePrice> </body> + * <parsers:SOAPParser return="content"> <parsers:XMLValidatingParser> + * <parsers:schemas> <parsers:schema + * type="url">http://blah/schema.xsd</parsers:schema> + * </parsers:schemas> </parsers:XMLValidatingParser> + * </parsers:SOAPParser> </soap-request> + */ + static public URLConnection build_soap_request(Node xml) throws Exception { + String sUrl = null; + String method = "POST"; + String charset = ((Element) xml).getAttribute("charset").isEmpty() ? ((Element) xml).getAttribute("charset") + : "UTF-8"; + String version = ((Element) xml).getAttribute("version"); + String action = ""; + String contentType = ""; + Element body = null; + + // Read in the test information (from CTL) + NodeList nl = xml.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node n = nl.item(i); + if (n.getNodeType() == Node.ELEMENT_NODE) { + if (n.getLocalName().equals("url")) { + sUrl = n.getTextContent(); + } + else if (n.getLocalName().equals("action")) { + action = n.getTextContent(); + } + // else if (n.getLocalName().equals("header")) { + // header = (org.w3c.dom.Element) n; + /* + * } + */else if (n.getLocalName().equals("body")) { + body = (org.w3c.dom.Element) n; + } + } + } + + // Get the list of the header blocks needed to build the SOAP Header + // section + List headerBloks = DomUtils.getElementsByTagNameNS(xml, CTL_NS, HEADER_BLOCKS); + // Open the URLConnection + URLConnection uc = new URL(sUrl).openConnection(); + if (uc instanceof HttpURLConnection) { + ((HttpURLConnection) uc).setRequestMethod(method); + } + + uc.setDoOutput(true); + byte[] bytes = null; + + // SOAP POST + bytes = SoapUtils.getSoapMessageAsByte(version, headerBloks, body, charset); + // System.out.println("SOAP MESSAGE " + new String(bytes)); + + uc.setRequestProperty("User-Agent", "Team Engine 1.2"); + uc.setRequestProperty("Cache-Control", "no-cache"); + uc.setRequestProperty("Pragma", "no-cache"); + uc.setRequestProperty("charset", charset); + uc.setRequestProperty("Content-Length", Integer.toString(bytes.length)); + + if (version.equals(SOAP_V_1_1)) { + // Handle HTTP binding for SOAP 1.1 + // uc.setRequestProperty("Accept", "application/soap+xml"); + uc.setRequestProperty("Accept", "text/xml"); + uc.setRequestProperty("SOAPAction", action); + contentType = "text/xml"; + if (!charset.isEmpty()) { + contentType = contentType + "; charset=" + charset; + } + uc.setRequestProperty("Content-Type", contentType); + } + else { + // Handle HTTP binding for SOAP 1.2 + uc.setRequestProperty("Accept", "application/soap+xml"); + contentType = "application/soap+xml"; + if (!charset.isEmpty()) { + contentType = contentType + "; charset=" + charset; + } + if (!action.isEmpty()) { + contentType = contentType + "; action=" + action; + } + uc.setRequestProperty("Content-Type", contentType); + } + OutputStream os = uc.getOutputStream(); + os.write(bytes); + return uc; + + } + + /** + * Implements ctl:request. Create and send an HTTP request then return an + * HttpResponse. Invoke any specified parsers on the response to validate it, change + * its format or derive specific information from it. + */ + public NodeList request(Document ctlRequest, String id) throws Throwable { + Element request = (Element) ctlRequest.getElementsByTagNameNS(Test.CTL_NS, "request").item(0); + if (opts.getMode() == Test.RESUME_MODE && prevLog != null) { + for (Element request_e : DomUtils.getElementsByTagName(prevLog, "request")) { + if (request_e.getAttribute("id").equals(fnPath + id)) { + logger.println(DomUtils.serializeNode(request_e)); + logger.flush(); + Element response_e = DomUtils.getElementByTagName(request_e, "response"); + Element content_e = DomUtils.getElementByTagName(response_e, "content"); + return content_e.getChildNodes(); + // return DomUtils.getChildElement(content_e); + } + } + } + + String logTag = "\n"; + logTag += DomUtils.serializeNode(request) + "\n"; + // if (logger != null) { + // logger.println(""); + // logger.println(DomUtils.serializeNode(request)); + // } + long elapsedTime = 0; + Exception ex = null; + Element response = null; + Element parserInstruction = null; + NodeList nl = request.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node n = nl.item(i); + if (n.getNodeType() == Node.ELEMENT_NODE && !n.getNamespaceURI().equals(CTL_NS)) { + parserInstruction = (Element) n; + } + } + + try { + Date before = new Date(); + URLConnection uc = build_request(request); + response = parse(uc, parserInstruction); + Date after = new Date(); + elapsedTime = after.getTime() - before.getTime(); + + // Adding the exchange time in the response as comment the format is + // the following + // + // the comment is included in the first tag of the response + Element content = DomUtils.getElementByTagName(response, "content"); + if (content != null) { + nl = content.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node n = nl.item(i); + if (n.getNodeType() == Node.ELEMENT_NODE) { + Document doc; + doc = response.getOwnerDocument(); + Comment comm = doc.createComment("Response received in [" + elapsedTime + "] milliseconds"); + n.appendChild(comm); + } + } + } + + logTag += DomUtils.serializeNode(response) + "\n"; + // if (logger != null) { + // logger.println(DomUtils.serializeNode(response)); + // } + } + catch (Exception e) { + ex = e; + } + // logTag += ""; + logTag += ""; + if (logger != null) { + // logger.println(""); + logger.println(logTag); + logger.flush(); + } + if (ex == null) { + Element parser = DomUtils.getElementByTagName(response, "parser"); + if (parser != null) { + String text = parser.getTextContent(); + if (text.length() > 0) { + out.println(parser.getTextContent()); + } + } + Element content = DomUtils.getElementByTagName(response, "content"); + return content.getChildNodes(); + } + else { + throw ex; + } + } + + /** + * Submits a request to some HTTP endpoint using the given request details. + * @param xml An ctl:request element. + * @return A URLConnection object representing an open communications link. + * @throws Exception If any error occurs while submitting the request or establishing + * a conection. + */ + public URLConnection build_request(Node xml) throws Exception { + Node body = null; + ArrayList headers = new ArrayList<>(); + ArrayList parts = new ArrayList<>(); + String sUrl = null; + String sParams = ""; + String method = "GET"; + String charset = "UTF-8"; + boolean multipart = false; + + // Read in the test information (from CTL) + NodeList nl = xml.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node n = nl.item(i); + if (n.getNodeType() == Node.ELEMENT_NODE) { + if (n.getLocalName().equals("url")) { + sUrl = n.getTextContent(); + } + else if (n.getLocalName().equals("method")) { + method = n.getTextContent().toUpperCase(); + } + else if (n.getLocalName().equals("header")) { + headers.add(new String[] { ((Element) n).getAttribute("name"), n.getTextContent() }); + } + else if (n.getLocalName().equals("param")) { + if (sParams.length() > 0) { + sParams += "&"; + } + sParams += ((Element) n).getAttribute("name") + "=" + n.getTextContent(); + // WARNING! May break some existing test suites + // + URLEncoder.encode(n.getTextContent(), "UTF-8"); + } + else if (n.getLocalName().equals("dynamicParam")) { + String name = null; + String val = null; + NodeList dpnl = n.getChildNodes(); + for (int j = 0; j < dpnl.getLength(); j++) { + Node dpn = dpnl.item(j); + if (dpn.getNodeType() == Node.ELEMENT_NODE) { + if (dpn.getLocalName().equals("name")) { + name = dpn.getTextContent(); + } + else if (dpn.getLocalName().equals("value")) { + val = dpn.getTextContent(); + // val = + // URLEncoder.encode(dpn.getTextContent(),"UTF-8"); + } + } + } + if (name != null && val != null) { + if (sParams.length() > 0) + sParams += "&"; + sParams += name + "=" + val; + } + } + else if (n.getLocalName().equals("body")) { + body = n; + } + else if (n.getLocalName().equals("part")) { + parts.add(n); + } + } + } + + // Complete GET KVP syntax + // Fortify Mod: Added check for null sUrl. Shouldn't happen but ---- + // if (method.equals("GET") && sParams.length() > 0) { + if (method.equals("GET") && sParams.length() > 0 && sUrl != null) { + if (sUrl.indexOf("?") == -1) { + sUrl += "?"; + } + else if (!sUrl.endsWith("?") && !sUrl.endsWith("&")) { + sUrl += "&"; + } + sUrl += sParams; + } + + // System.out.println(sUrl); + TransformerFactory tf = TransformerFactory.newInstance(); + // Fortify Mod: prevent external entity injection + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer t = tf.newTransformer(); + + // Open the URLConnection + URLConnection uc = new URL(sUrl).openConnection(); + if (uc instanceof HttpURLConnection) { + HttpURLConnection httpUc = (HttpURLConnection) uc; + httpUc.setRequestMethod(method); + boolean redirect = checkForRedirect(httpUc); + if (redirect) { + String redirectURL = httpUc.getHeaderField("Location"); + uc = new URL(redirectURL).openConnection(); + if (uc instanceof HttpURLConnection) { + ((HttpURLConnection) uc).setRequestMethod(method); + } + } + else { + // https://github.com/opengeospatial/teamengine/issues/553 + // need to re-connect, as the check for redirects already opened the + // connection + uc = new URL(sUrl).openConnection(); + } + } + + // POST setup (XML payload and header information) + if (method.equals("POST") || method.equals("PUT")) { + uc.setDoOutput(true); + byte[] bytes = null; + String mime = null; + + // KVP over POST + if (body == null) { + bytes = sParams.getBytes(); + mime = "application/x-www-form-urlencoded"; + } // XML POST + else { + String bodyContent = ""; + + NodeList children = body.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + if (children.item(i).getNodeType() == Node.ELEMENT_NODE) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + t.transform(new DOMSource(children.item(i)), new StreamResult(baos)); + bodyContent = baos.toString(); + bytes = baos.toByteArray(); + + if (mime == null) { + mime = "application/xml; charset=" + charset; + } + break; + } + } + if (bytes == null) { + bytes = body.getTextContent().getBytes(); + mime = "text/plain"; + } + + // Add parts if present + if (parts.size() > 0) { + String prefix = "--"; + String boundary = "7bdc3bba-e2c9-11db-8314-0800200c9a66"; + String newline = "\r\n"; + multipart = true; + + // Set main body and related headers + ByteArrayOutputStream contentBytes = new ByteArrayOutputStream(); + String bodyPart = prefix + boundary + newline; + bodyPart += "Content-Type: " + mime + newline + newline; + bodyPart += bodyContent; + writeBytes(contentBytes, bodyPart.getBytes(charset)); + + // Append all parts to the original body, seperated by the + // boundary sequence + for (int i = 0; i < parts.size(); i++) { + Element currentPart = (Element) parts.get(i); + String cid = currentPart.getAttribute("cid"); + if (cid.indexOf("cid:") != -1) { + cid = cid.substring(cid.indexOf("cid:") + "cid:".length()); + } + String contentType = currentPart.getAttribute("content-type"); + + // Default encodings and content-type + if (contentType.equals("application/xml")) { + contentType = "application/xml; charset=" + charset; + } + if (contentType == null || contentType.isEmpty()) { + contentType = "application/octet-stream"; + } + + // Set headers for each part + String partHeaders = newline + prefix + boundary + newline; + partHeaders += "Content-Type: " + contentType + newline; + partHeaders += "Content-ID: <" + cid + ">" + newline + newline; + writeBytes(contentBytes, partHeaders.getBytes(charset)); + + // Get the fileName, if it exists + NodeList files = currentPart.getElementsByTagNameNS(CTL_NS, "file"); + + // Get part for a specified file + if (files.getLength() > 0) { + File contentFile = getFile(files); + + InputStream is = new FileInputStream(contentFile); + long length = contentFile.length(); + byte[] fileBytes = new byte[(int) length]; + int offset = 0; + int numRead = 0; + while (offset < fileBytes.length + && (numRead = is.read(fileBytes, offset, fileBytes.length - offset)) >= 0) { + offset += numRead; + } + is.close(); + + writeBytes(contentBytes, fileBytes); + } // Get part from inline data (or xi:include) + else { + // Text + if (currentPart.getFirstChild() instanceof Text) { + writeBytes(contentBytes, currentPart.getTextContent().getBytes(charset)); + } // XML + else { + writeBytes(contentBytes, + DomUtils.serializeNode(currentPart.getFirstChild()).getBytes(charset)); + } + } + } + + String endingBoundary = newline + prefix + boundary + prefix + newline; + writeBytes(contentBytes, endingBoundary.getBytes(charset)); + + bytes = contentBytes.toByteArray(); + + // Global Content-Type and Length to be added after the + // parts have been parsed + mime = "multipart/related; type=\"" + mime + "\"; boundary=\"" + boundary + "\""; + + // String contentsString = new String(bytes, charset); + // System.out.println("Content-Type: "+mime+"\n"+contentsString); + } + } + + // Set headers + if (body != null) { + String mid = ((Element) body).getAttribute("mid"); + if (mid != null && !mid.isEmpty()) { + if (mid.indexOf("mid:") != -1) { + mid = mid.substring(mid.indexOf("mid:") + "mid:".length()); + } + uc.setRequestProperty("Message-ID", "<" + mid + ">"); + } + } + uc.setRequestProperty("Content-Type", mime); + uc.setRequestProperty("Content-Length", Integer.toString(bytes.length)); + + // Enter the custom headers (overwrites the defaults if present) + for (int i = 0; i < headers.size(); i++) { + String[] header = headers.get(i); + if (multipart && header[0].toLowerCase().equals("content-type")) { + } + else { + uc.setRequestProperty(header[0], header[1]); + } + } + + OutputStream os = uc.getOutputStream(); + os.write(bytes); + } + else { + for (int i = 0; i < headers.size(); ++i) { + String[] header = headers.get(i); + uc.setRequestProperty(header[0], header[1]); + } + } + + return uc; + } + + public static void writeBytes(ByteArrayOutputStream baos, byte[] bytes) { + baos.write(bytes, 0, bytes.length); + } + + public Element parse(Document parse_instruction, String xsl_version) throws Throwable { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + // Fortify Mod: prevent external entity injection + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + + TransformerFactory tf = TransformerFactory.newInstance(); + // Fortify Mod: prevent external entity injection + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer t = null; + Node content = null; + Document parser_instruction = null; + + Element parse_element = (Element) parse_instruction.getElementsByTagNameNS(CTL_NS, "parse").item(0); + + NodeList children = parse_element.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + if (children.item(i).getNodeType() == Node.ELEMENT_NODE) { + Element e = (Element) children.item(i); + if (e.getNamespaceURI().equals(XSL_NS) && e.getLocalName().equals("output")) { + Document doc = db.newDocument(); + Element transform = doc.createElementNS(XSL_NS, "transform"); + transform.setAttribute("version", xsl_version); + doc.appendChild(transform); + Element output = doc.createElementNS(XSL_NS, "output"); + NamedNodeMap atts = e.getAttributes(); + for (int j = 0; j < atts.getLength(); j++) { + Attr a = (Attr) atts.item(i); + output.setAttribute(a.getName(), a.getValue()); + } + transform.appendChild(output); + Element template = doc.createElementNS(XSL_NS, "template"); + template.setAttribute("match", "node()|@*"); + transform.appendChild(template); + Element copy = doc.createElementNS(XSL_NS, "copy"); + template.appendChild(copy); + Element apply = doc.createElementNS(XSL_NS, "apply-templates"); + apply.setAttribute("select", "node()|@*"); + copy.appendChild(apply); + t = tf.newTransformer(new DOMSource(doc)); + } + else if (e.getLocalName().equals("content")) { + NodeList children2 = e.getChildNodes(); + for (int j = 0; j < children2.getLength(); j++) { + if (children2.item(j).getNodeType() == Node.ELEMENT_NODE) { + content = children2.item(j); + } + } + if (content == null) { + content = children2.item(0); + } + } + else { + parser_instruction = db.newDocument(); + tf.newTransformer().transform(new DOMSource(e), new DOMResult(parser_instruction)); + } + } + } + if (t == null) { + t = tf.newTransformer(); + } + File temp = File.createTempFile("$te_", ".xml"); + // Fortify Mod: It is possible to get here without assigning a value to content. + // if (content.getNodeType() == Node.TEXT_NODE) { + if (content != null && content.getNodeType() == Node.TEXT_NODE) { + RandomAccessFile raf = new RandomAccessFile(temp, "rw"); + raf.writeBytes(((Text) content).getTextContent()); + raf.close(); + } + else { + t.transform(new DOMSource(content), new StreamResult(temp)); + } + URLConnection uc = temp.toURI().toURL().openConnection(); + Element result = parse(uc, parser_instruction); + temp.delete(); + return result; + } + + /** + * Parses the content retrieved from some URI and builds a DOM Document containing + * information extracted from the response message. Subsidiary parsers are invoked in + * accord with the supplied parser instructions. + * @param uc A URLConnection object. + * @param instruction A Document or Element node containing parser instructions. + * @return An Element containing selected info from a URLConnection as specified by + * instruction Element and children. + */ + public Element parse(URLConnection uc, Node instruction) throws Throwable { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + // Fortify Mod: Disable entity expansion to foil External Entity Injections + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document response_doc = db.newDocument(); + return parse(uc, instruction, response_doc); + } + + /** + * Invoke a parser or chain of parsers as specified by instruction element and + * children. Parsers in chain share uc, strip off their own instructions, and pass + * child instructions to next parser in chain. Final parser in chain modifies content. + * All parsers in chain can return info in attributes and child elements of + * instructions. If parser specified in instruction, call it to return specified info + * from uc. + */ + public Element parse(URLConnection uc, Node instruction, Document response_doc) throws Exception { + // Fortify Mod: To prevent external entity injections + TransformerFactory tf = TransformerFactory.newInstance(); + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer idt = tf.newTransformer(); + // End Fortify Mod + Element parser_e = response_doc.createElement("parser"); + Element response_e = response_doc.createElement("response"); + Element content_e = response_doc.createElement("content"); + if (instruction == null) { + InputStream is = null; + uc.connect(); + String contentType = uc.getContentType(); + try { + is = URLConnectionUtils.getInputStream(uc); + if (contentType != null && contentType.contains("xml")) { // a crude check + idt.transform(new StreamSource(is), new DOMResult(content_e)); + } + else { + content_e.setTextContent(IOUtils.inputStreamToString(is)); + } + } + finally { + if (null != is) + is.close(); + } + } + else { + Element instruction_e; + if (instruction instanceof Element) { + instruction_e = (Element) instruction; + } + else { + instruction_e = ((Document) instruction).getDocumentElement(); + } + String key = "{" + instruction_e.getNamespaceURI() + "}" + instruction_e.getLocalName(); + ParserEntry pe = index.getParser(key); + Object instance = null; + + // Instantiate the parser object if requested. + if (pe.isInitialized()) { + instance = parserInstances.get(key); + if (instance == null) { + try { + TEClassLoader cl = engine.getClassLoader(opts.getSourcesName()); + instance = Misc.makeInstance(pe.getClassName(), pe.getClassParams(), cl); + } + catch (Exception e) { + throw new Exception("Can't instantiate parser " + pe.getName(), e); + } + parserInstances.put(key, instance); + } + } + + Method method = parserMethods.get(key); + if (method == null) { + TEClassLoader cl = engine.getClassLoader(opts.getSourcesName()); + method = Misc.getMethod(pe.getClassName(), pe.getMethod(), cl, 3, 4); + parserMethods.put(key, method); + } + StringWriter swLogger = new StringWriter(); + PrintWriter pwLogger = new PrintWriter(swLogger); + int arg_count = method.getParameterTypes().length; + Object[] args = new Object[arg_count]; + args[0] = uc; + args[1] = instruction_e; + args[2] = pwLogger; + if (arg_count > 3) { + args[3] = this; + } + Object return_object; + try { + if (LOGR.isLoggable(Level.FINER)) { + LOGR.finer("Invoking method " + method.toGenericString() + "size args[] = " + args.length + + "\n args[0]: " + args[0].toString() + "\n args[1]:\n" + + DomUtils.serializeNode((Node) args[1])); + } + return_object = method.invoke(instance, args); + } + catch (java.lang.reflect.InvocationTargetException e) { + Throwable cause = e.getCause(); + String msg = "Error invoking parser " + pe.getId() + "\n" + cause.getClass().getName(); + if (cause.getMessage() != null) { + msg += ": " + cause.getMessage(); + } + jlogger.log(SEVERE, msg, e); + // CTL says parsers should return null if they encounter an error. + // Apparently this parser is broken. Wrap the thrown exception in a + // RuntimeException since we really know nothing about what went wrong. + throw new RuntimeException("Parser " + pe.getId() + " threw an exception.", cause); + } + pwLogger.close(); + if (return_object instanceof Node) { + idt.transform(new DOMSource((Node) return_object), new DOMResult(content_e)); + } + else if (return_object != null) { + content_e.appendChild(response_doc.createTextNode(return_object.toString())); + } + parser_e.setAttribute("prefix", instruction_e.getPrefix()); + parser_e.setAttribute("local-name", instruction_e.getLocalName()); + parser_e.setAttribute("namespace-uri", instruction_e.getNamespaceURI()); + parser_e.setTextContent(swLogger.toString()); + } + response_e.appendChild(parser_e); + response_e.appendChild(content_e); + return response_e; + } + + public Node message(String message, String id) { + String formatted_message = indent + message.trim().replaceAll("\n", "\n" + indent); + String messageTrim = message.trim().replaceAll("\n", "\n" + indent); + if (!(messageTrim.contains("Clause") || messageTrim.contains("Purpose") || messageTrim.contains("TestName"))) { + out.println(formatted_message); + messageTest = message; + } + else { + if (messageTrim.contains("TestName")) { + TESTNAME = messageTrim.replace("TestName : ", ""); + if (rootTestName != null && rootTestName.size() > 0) { + for (int i = 0; i < rootTestName.size(); i++) { + if (messageTrim.contains(rootTestName.get(i))) { + rootNo = i + 1; + } + } + } + } + else if (messageTrim.contains("Clause")) { + Clause = messageTrim.replace("Clause : ", ""); + } + else { + Purpose = messageTrim.replace("Purpose : ", ""); + } + if ((rootNo != 0) && (!"".equals(Clause)) && (!"".equals(Purpose))) { + mainRootElementClause.appendChild(RecordTestResult.getClause()); + Clause = ""; + Purpose = ""; + rootNo = 0; + } + } + if (logger != null) { + logger.println(""); + } + return null; + } + + public void putLogCache(String id, Document xmlToCache) { + if (logger != null) { + String xmlString = DomUtils.serializeNode(xmlToCache); + logger.println("" + xmlString + ""); + } + } + + public Element getLogCache(String id) { + Element child_e = null; + if (prevLog != null) { + for (Element cache_e : DomUtils.getElementsByTagName(prevLog, "cache")) { + if (cache_e.getAttribute("id").equals(id)) { + child_e = DomUtils.getChildElement(cache_e); + } + } + } + if (suiteLog != null && child_e == null) { + for (Element cache_e : DomUtils.getElementsByTagName(suiteLog, "cache")) { + if (cache_e.getAttribute("id").equals(id)) { + child_e = DomUtils.getChildElement(cache_e); + } + } + } + return child_e; + } + + /** + * Converts CTL input form elements to generate a Swing-based or XHTML form and + * reports the results of processing the submitted form. The results document is + * produced in (web context) or + * {@link com.occamlab.te.SwingForm.CustomFormView#submitData(String)}. + * @param ctlForm a DOM Document representing a <ctl:form> element. + * @throws java.lang.Exception + * @return a DOM Document containing the resulting <values> element as the + * document element. + */ + public Node form(Document ctlForm, String id) throws Exception { + if (opts.getMode() == Test.RESUME_MODE && prevLog != null) { + for (Element e : DomUtils.getElementsByTagName(prevLog, "formresults")) { + if (e.getAttribute("id").equals(fnPath + id)) { + logger.println(DomUtils.serializeNode(e)); + logger.flush(); + return DomUtils.getChildElement(e); + } + } + } + + String name = Thread.currentThread().getName(); + Element form = (Element) ctlForm.getElementsByTagNameNS(CTL_NS, "form").item(0); + + NamedNodeMap attrs = form.getAttributes(); + Attr attr = (Attr) attrs.getNamedItem("name"); + if (attr != null) { + name = attr.getValue(); + } + + for (Element parseInstruction : DomUtils.getElementsByTagNameNS(form, CTL_NS, "parse")) { + String key = parseInstruction.getAttribute("file"); + formParsers.put(key, DomUtils.getChildElement(parseInstruction)); + } + + // Determine if there are file widgets or not + boolean hasFiles = false; + List inputs = DomUtils.getElementsByTagName(form, "input"); + inputs.addAll(DomUtils.getElementsByTagNameNS(form, "http://www.w3.org/1999/xhtml", "input")); + for (Element input : inputs) { + if (input.getAttribute("type").toLowerCase().equals("file")) { + hasFiles = true; + break; + } + } + + // Get "method" attribute - "post" or "get" + attr = (Attr) attrs.getNamedItem("method"); + String method = "get"; + if (attr != null) { + method = attr.getValue().toLowerCase(); + } + else if (hasFiles) { + method = "post"; + } + imageHandler.saveImages(form); + + XsltTransformer formTransformer = engine.getFormExecutable().load(); + formTransformer.setSource(new DOMSource(ctlForm)); + formTransformer.setParameter(new QName("title"), new XdmAtomicValue(name)); + formTransformer.setParameter(new QName("web"), new XdmAtomicValue(web ? "yes" : "no")); + formTransformer.setParameter(new QName("files"), new XdmAtomicValue(hasFiles ? "yes" : "no")); + formTransformer.setParameter(new QName("thread"), + new XdmAtomicValue(Long.toString(Thread.currentThread().getId()))); + formTransformer.setParameter(new QName("method"), new XdmAtomicValue(method)); + formTransformer.setParameter(new QName("base"), new XdmAtomicValue(opts.getBaseURI())); + formTransformer.setParameter(new QName("action"), new XdmAtomicValue(getTestServletURL())); + StringWriter sw = new StringWriter(); + Serializer serializer = new Serializer(); + serializer.setOutputWriter(sw); + serializer.setOutputProperty(Serializer.Property.OMIT_XML_DECLARATION, "yes"); + formTransformer.setDestination(serializer); + formTransformer.transform(); + this.formHtml = sw.toString(); + if (LOGR.isLoggable(FINE)) + LOGR.fine(this.formHtml); + + if (!recordedForms.isEmpty()) { + RecordedForm.create(recordedForms.next(), this); + } + else if (!web) { + int width = 700; + int height = 500; + attr = (Attr) attrs.getNamedItem("width"); + if (attr != null) { + width = Integer.parseInt(attr.getValue()); + } + attr = (Attr) attrs.getNamedItem("height"); + if (attr != null) { + height = Integer.parseInt(attr.getValue()); + } + SwingForm.create(name, width, height, this); + } + + while (formResults == null) { + if (stop) { + formParsers.clear(); + throw new Exception("Execution was stopped by the user."); + } + Thread.sleep(250); + } + + Document doc = formResults; + if (LOGR.isLoggable(FINE)) + LOGR.fine(DomUtils.serializeNode(doc)); + formResults = null; + formParsers.clear(); + + if (logger != null) { + logger.println(""); + logger.println(DomUtils.serializeNode(doc)); + logger.println(""); + } + return doc; + } + + public void setIndentLevel(int level) { + indent = ""; + for (int i = 0; i < level; i++) { + indent += INDENT; + } + } + + public String getOutput() { + String output = threadOutput.toString(); + threadOutput.reset(); + return output; + } + + public void stopThread() throws Exception { + stop = true; + while (!threadComplete) { + Thread.sleep(100); + } + } + + public boolean isThreadComplete() { + return threadComplete; + } + + public void run() { + threadComplete = false; + // activeThread = Thread.currentThread(); + try { + opts.getLogDir().mkdir(); + threadOutput = new ByteArrayOutputStream(); + out = new PrintStream(threadOutput); + execute(); + out.close(); + } + catch (Exception e) { + jlogger.log(SEVERE, "", e); + } + // activeThread = null; + threadComplete = true; + } + + public File getLogDir() { + return opts.getLogDir(); + } + + public PrintStream getOut() { + return out; + } + + public void setOut(PrintStream out) { + this.out = out; + } + + public String getTestPath() { + return testPath; + } + + /** + * Returns the location of the directory containing the test run output. + * @return A String representing a file URI denoting the path name of a directory. + */ + public String getTestRunDirectory() { + String logDirURI = opts.getLogDir().toURI().toString(); + return logDirURI + opts.getSessionId(); + } + + /** + * Updates the local testPath value. C. Heazel made private since it is never called + * by an external object Could be removed since local classes can set it directly. Or + * augmented by value validation. + */ + private void setTestPath(String testPath) { + this.testPath = testPath; + } + + public boolean isWeb() { + return web; + } + + public void setWeb(boolean web) { + this.web = web; + } + + public Object getFunctionInstance(Integer key) { + return functionInstances.get(key); + } + + public Object putFunctionInstance(Integer key, Object instance) { + return functionInstances.put(key, instance); + } + + public Engine getEngine() { + return engine; + } + + public Index getIndex() { + return index; + } + + public RuntimeOptions getOpts() { + return opts; + } + + public String getTestServletURL() { + return testServletURL; + } + + public void setTestServletURL(String testServletURL) { + this.testServletURL = testServletURL; + } + + /** + * Transform EARL result into HTML report using XSLT. + * @param outputDir + */ + // Fortify Mod: Changed to a private method so that the value of the + // outputDir parameter can be managed. + // Note: that there is no indication that this method is ever called. + public boolean earlHtmlReport(String outputDir) { + TEPath tpath = new TEPath(outputDir); + if (!tpath.isValid()) { + System.out.println("ViewLog Error: Invalid log file name " + outputDir); + return false; + } + EarlToHtmlTransformation earlToHtml = new EarlToHtmlTransformation(); + earlToHtml.earlHtmlReport(outputDir); + return true; + } + + /** + * This method is used to extract the test input into Map from the document element. + * @param userInput Document node + * @param runOpts + * @return User Input Map + */ + private Map extractTestInputs(Document userInput, RuntimeOptions runOpts) { + Map inputMap = new HashMap<>(); + if (null != userInputs) { + NodeList values = userInputs.getDocumentElement().getElementsByTagName("value"); + if (values.getLength() == 0) { + inputMap = Collections.emptyMap(); + } + else { + for (int i = 0; i < values.getLength(); i++) { + Element value = (Element) values.item(i); + inputMap.put(value.getAttribute("key"), value.getTextContent()); + } + } + } + else if (null != opts.getParams()) { + List runParams = opts.getParams(); + for (String param : runParams) { + String[] kvp = param.split("="); + inputMap.put(kvp[0], kvp[1]); + } + } + return inputMap; + } + + private boolean checkForRedirect(HttpURLConnection conn) throws IOException { + int status = conn.getResponseCode(); + if (status != HttpURLConnection.HTTP_OK) { + if (status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_MOVED_PERM + || status == HttpURLConnection.HTTP_SEE_OTHER) + return true; + } + return false; + } + + /** + * Builds a DOM Document representing a classpath resource. + * @param name The name of an XML resource. + * @return A Document node, or {@code null} if the resource cannot be parsed for any + * reason. + */ + public Document findXMLResource(String name) { + URL url = this.getClass().getResource(name); + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + docFactory.setNamespaceAware(true); + // Fortify Mod: Disable entity expansion to foil External Entity Injections + docFactory.setExpandEntityReferences(false); + Document doc = null; + try { + DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); + doc = docBuilder.parse(url.toURI().toString()); + } + catch (Exception e) { + LOGR.log(Level.WARNING, "Failed to parse classpath resource " + name, e); + } + return doc; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/TeErrorListener.java b/teamengine-core/src/main/java/com/occamlab/te/TeErrorListener.java index d583dfd99..439482289 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/TeErrorListener.java +++ b/teamengine-core/src/main/java/com/occamlab/te/TeErrorListener.java @@ -13,6 +13,26 @@ C. Heazel (WiSC) Modifications to address Fortify issues. ****************************************************************************/ package com.occamlab.te; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.BufferedReader; import java.io.CharArrayReader; import java.io.File; diff --git a/teamengine-core/src/main/java/com/occamlab/te/Test.java b/teamengine-core/src/main/java/com/occamlab/te/Test.java index c224ced2a..177c335cb 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/Test.java +++ b/teamengine-core/src/main/java/com/occamlab/te/Test.java @@ -1,525 +1,545 @@ -/* - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): - 2009 F. Vitale vitale@imaa.cnr.it - 2018 C. Heazel cheazel@wiscenterprisesl.com - - Modifications: - 2/14/18 - - Addressed path manipulation vulnerabilities and general cleanup. - - Identified Issues which need further discussion. - - */ - -package com.occamlab.te; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FilenameFilter; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.w3c.dom.Document; -import org.w3c.dom.NodeList; - -import com.occamlab.te.index.Index; -import com.occamlab.te.util.LogUtils; - -/** - * - * The main class for the TEAM Engine command line interface. - * - */ -public class Test { - - private static final Logger LOGR = Logger.getLogger(Test.class.getName()); - - public static final int TEST_MODE = 0; - - public static final int RETEST_MODE = 1; - - public static final int RESUME_MODE = 2; - - public static final int REDO_FROM_CACHE_MODE = 3; - - public static final int DOC_MODE = 4; - - public static final int CHECK_MODE = 5; - - public static final String XSL_NS = "http://www.w3.org/1999/XSL/Transform"; - - public static final String TE_NS = "http://www.occamlab.com/te"; - - public static final String CTL_NS = "http://www.occamlab.com/ctl"; - - public static final String CTLP_NS = "http://www.occamlab.com/te/parsers"; - - SetupOptions setupOpts; - - RuntimeOptions runOpts; - - /** - * Constructs a test executor with default options. - */ - public Test() { - this.setupOpts = new SetupOptions(); - this.runOpts = new RuntimeOptions(); - } - - /** - * Replace the SetupOptions with a new copy - * @param setupOpts The new copy of the setup options - * - * ISSUE: SetupOptions are established when the Teamengin is initialized. they should - * be the same for all tests. Why do we allow them to be modified? ISSUE: when and how - * are the setup options validated? ANSWER: Delete this method since it is never - * called. - */ - // void setSetupOptions(SetupOptions setupOpts) { - // this.setupOpts = setupOpts; - // } - - /** - * Replace the RuntimeOptions with a new copy - * @param runOpts The new copy of the runtime options - * - * ISSUE: when and how are the runtime options validated? ANSWER: make RuntimeOptions - * self-validating. - */ - void setRuntimeOptions(RuntimeOptions runOpts) { - this.runOpts = runOpts; - } - - // This method does not appear to be used. Consider deleting it. - // Changed from public to private until we validate that is can be removed. - - private void executeTest(String relativePathToMainCtl) throws Exception { - // File file =Misc.getResourceAsFile(relativePathToMainCtl); - String[] arguments = new String[1]; - arguments[0] = "-source=" + relativePathToMainCtl; - execute(arguments); - } - - /** - * Entry point from the command line. Creates a new test object then executes it. - * @param args An array of command line arguments - * @throws Exception - */ - public static void main(String[] args) throws Exception { - Test test = new Test(); - test.execute(args); - } - - /** - * Executes a test suite. - * @param args Command line arguments - * @throws Exception - */ - public void execute(String[] args) throws Exception { - @SuppressWarnings("unused") - boolean rslt; - - // Copy work directory from setup options to runtime - File workDir = setupOpts.getWorkDir(); - rslt = runOpts.setWorkDir(workDir); - - // Initialize the rest of the test context - String cmd = "java com.occamlab.te.Test"; - File logDir = runOpts.getLogDir(); - String session = null; - boolean hasSessionArg = false; - int mode = TEST_MODE; - - // Parse arguments from command-line - for (int i = 0; i < args.length; i++) { - String arg = args[i]; - if (arg.startsWith("-cmd=")) { - cmd = arg.substring(5); - } - else if (arg.equals("-h") || arg.equals("-help") || arg.equals("-?")) { - syntax(cmd); - return; - // The path to the test script. If the file name is not an absolute - // path then it must be under the Scripts directory. - // Issue: should we restrict the range of valid paths for source files? - } - else if (arg.startsWith("-source=")) { - String sourcePath = arg.substring(8); - File sourceFile = new File(sourcePath); - if (!sourceFile.isAbsolute()) { - File scriptsDir = new File(SetupOptions.getBaseConfigDirectory(), "scripts"); - sourceFile = new File(scriptsDir, sourcePath); - } - // Fortify Mod: Validate the sourceFile. It must both exist - // and pass validation by setupOptions - if (!sourceFile.exists() || !setupOpts.addSourceWithValidation(sourceFile)) { - System.out.println("Error: Cannot find CTL script(s) at " + sourceFile.getAbsolutePath()); - return; - } - } - else if (args[i].startsWith("-logdir=")) { - String path = args[i].substring(8); - File file = new File(path); - if (file.isAbsolute()) { - logDir = file; - } - else { - logDir = new File(SetupOptions.getBaseConfigDirectory(), path); - } - if (!logDir.exists() || !runOpts.setLogDir(logDir)) { - System.out.println("Error: Cannot use logdir " + logDir.getAbsolutePath()); - return; - } - } - else if (arg.startsWith("-session=")) { - // Issue: session is not validated but it is used as part of a file path. - hasSessionArg = true; - session = arg.substring(9); - } - else if (arg.startsWith("-base=")) { - rslt = runOpts.setBaseURI(arg.substring(6)); - } - else if (arg.startsWith("-test=")) { - rslt = runOpts.setTestName(arg.substring(6)); - } - else if (arg.startsWith("-suite=")) { - rslt = runOpts.setSuiteName(arg.substring(7)); - } - else if (arg.startsWith("-profile=")) { - rslt = runOpts.addProfile(arg.substring(9)); - } - else if (arg.startsWith("@")) { - rslt = runOpts.addParam(arg.substring(1)); - } - else if (arg.equals("-mode=test")) { - mode = TEST_MODE; - } - else if (arg.equals("-mode=retest")) { - mode = RETEST_MODE; - } - else if (arg.equals("-mode=resume")) { - mode = RESUME_MODE; - } - else if (arg.equals("-mode=doc")) { - mode = DOC_MODE; - } - else if (arg.equals("-mode=check")) { - mode = CHECK_MODE; - } - else if (arg.equals("-mode=cache")) { - mode = REDO_FROM_CACHE_MODE; - } - else if (arg.startsWith("-mode=")) { - System.out.println("Error: Invalid mode."); - return; - } - else if (arg.equals("-validate=no")) { - setupOpts.setValidate(false); - } - else if ((arg.startsWith("-form="))) { - rslt = runOpts.addRecordedForm(arg.substring(6)); - } - else if (!arg.startsWith("-")) { - if (mode == RETEST_MODE || mode == REDO_FROM_CACHE_MODE) { - if (hasSessionArg) { - if (arg.startsWith(session)) { - rslt = runOpts.addTestPath(arg); - } - else { - rslt = runOpts.addTestPath(session + "/" + arg); - } - } - else { - int slash = (arg).indexOf("/"); - if (slash >= 0) { - if (session == null) { - session = arg.substring(0, slash); - } - else if (!arg.substring(0, slash).equals(session)) { - System.out.println("Each test path must be within the same session."); - return; - } - rslt = runOpts.addTestPath(arg); - } - } - } - else { - System.out.println("Unrecognized parameter \"" + arg + "\""); - } - } - else { - System.out.println("Unrecognized parameter \"" + arg + "\""); - } - } - - // Set mode - rslt = runOpts.setMode(mode); - rslt = runOpts.setSessionId(session); - - if (mode == RETEST_MODE || mode == RESUME_MODE || mode == REDO_FROM_CACHE_MODE) { - if (logDir == null || session == null) { - syntax(cmd); - return; - } - if (setupOpts.getSources().isEmpty()) { - loadSources(); - } - } - - // Syntax checks - if (setupOpts.getSources().isEmpty()) { - System.out.println("Error: At least one -source parameter is required"); - return; - } - if (runOpts.getProfiles().size() > 0 && logDir == null) { - System.out.println("Error: A -logdir parameter is required for testing profiles"); - return; - } - - // Set session - if (session == null) { - session = System.getProperty("team.session"); - } - // CMH - changed session format to UUID. - // BPR - changed back to previous format - if (session == null) { - if (logDir == null) { - session = "s0001"; - } - else { - session = LogUtils.generateSessionId(logDir); - } - rslt = runOpts.setSessionId(session); - } - - Thread.currentThread().setName("TEAM Engine"); - Index masterIndex = new Index(); - File indexFile = null; - if (logDir != null && session != null) { - File dir = new File(logDir, runOpts.getSessionId()); - indexFile = new File(dir, "index.xml"); - } - - boolean regenerate = false; - - if (mode == TEST_MODE || mode == CHECK_MODE) { - regenerate = true; - } - else if (mode == DOC_MODE) { - masterIndex = Generator.generateDocXsl(setupOpts); - } - else { - if (indexFile == null || !indexFile.canRead()) { - System.out.println("Error: Can't read index file."); - regenerate = true; - } - else { - masterIndex = new Index(indexFile); - if (masterIndex.outOfDate()) { - System.out.println("Warning: Scripts have changed since this session was first executed."); - if (mode == REDO_FROM_CACHE_MODE) { - System.out.println("Regenerating masterIndex from source scripts"); - regenerate = true; - } - } - } - } - - if (regenerate) { - masterIndex = Generator.generateXsl(setupOpts); - if (indexFile != null) { - masterIndex.persist(indexFile); - } - } - - if (mode == REDO_FROM_CACHE_MODE) { - boolean hasCache = ViewLog.checkCache(logDir, session); - if (!hasCache) { - File dir = new File(logDir, runOpts.getSessionId()); - throw new Exception("Error: no cache for " + dir.getAbsolutePath()); - } - } - - // Fortify Mod: Make sure masterIndex is not null - // masterIndex.setElements(null); - if (masterIndex != null) { - masterIndex.setElements(null); - } - else { - masterIndex = new Index(); - } - List resourcesDirs = new ArrayList<>(); - for (File sourceFile : setupOpts.getSources()) { - File resourcesDir = findResourcesDirectory(sourceFile); - if (!resourcesDirs.contains(resourcesDir)) { - resourcesDirs.add(resourcesDir); - } - } - TEClassLoader cl = new TEClassLoader(resourcesDirs); - Engine engine = new Engine(masterIndex, setupOpts.getSourcesName(), cl); - - if (setupOpts.isPreload() || mode == CHECK_MODE) { - engine.preload(masterIndex, setupOpts.getSourcesName()); - } - - if (LOGR.isLoggable(Level.FINE)) { - LOGR.fine(runOpts.toString()); - } - - if (mode == TEST_MODE) { - saveSources(); - } - - if (mode != CHECK_MODE) { - TECore core = new TECore(engine, masterIndex, runOpts); - core.execute(); - } - - } - - /** - * Seeks a "resources" directory by searching the file system from a starting location - * and continuing upwards into ancestor directories. - * @param sourceFile A File denoting a file system location (file or directory). - * @return A File representing a directory named "resources", or {@code null} if one - * cannot be found. - */ - static File findResourcesDirectory(File sourceFile) { - File parent = sourceFile.getParentFile(); - if (null == parent) { - return null; - } - File[] resourceDirs = parent.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return (name.equalsIgnoreCase("resources") && new File(dir, name).isDirectory()); - } - }); - if (resourceDirs.length > 0) { - return resourceDirs[0]; - } - return findResourcesDirectory(parent); - } - - /** - * Displays startup command syntax. - * @param cmd Name of the startup command (i.e. test.bat or test.sh) - */ - static void syntax(String cmd) { - System.out.println(); - System.out.println("Test mode:"); - System.out.println(" Use to start a test session.\n"); - System.out.println(" " + cmd + " [-mode=test] -source=ctlfile|dir ..."); - System.out.println(" [-logdir=dir] [-session=session] [-base=baseURI]"); - System.out.println(" -suite=qname [-profile=qname|*] ... | -test=qname [@param-name=value] ...\n"); - System.out.println(" qname=[namespace_uri,|prefix:]local_name\n"); - System.out.println("Resume mode:"); - System.out.println(" Use to resume a test session that was interrupted before completion.\n"); - System.out.println(" " + cmd + " -mode=resume [-logdir=dir] -session=session\n"); - System.out.println("Retest mode:"); - System.out.println(" Use to reexecute individual tests.\n"); - System.out.println(" " + cmd + " -mode=retest [-logdir=dir] testpath1 [testpath2] ...\n"); - System.out.println("Redo From Cache Mode:"); - System.out.println(" Use to rerun tests with cached server responses when the test has changed.\n"); - System.out.println(" " + cmd + "-mode=cache [-logdir=dir] [-session=session] [testpath1 [testpath2]]\n"); - System.out.println(" Warning: Test changes may make cached server responses invalid.\n"); - System.out.println("Check mode:"); - System.out.println(" Use to validate source files.\n"); - System.out.println(" " + cmd + " -mode=check -source=ctlfile|dir ...\n"); - System.out.println("Doc mode:"); - System.out.println(" Use to visit all subtests and generate log files without executing them.\n"); - System.out.println(" " + cmd + " -mode=doc -source=ctlfile|dir ... [-suite=qname]\n"); - - /* - * Doc mode once again behaves as it originally did in - * https://sourceforge.net/p/teamengine/code/1 The entry point for the - * PseudoCTLDocumentation generator (which was called with -mode=doc starting with - * https://sourceforge.net/p/teamengine/code/459) is now the main method of - * DocumentationHelper. - */ - - /* - * The entry point for the PrettyPrintLogs functionality which was called with - * -mode=pplogs is now in the main method of ViewLog and is activated with its - * -html parameter. - */ - } - - /** - * Returns name of mode. - * @param mode - */ - public static String getModeName(int mode) { - switch (mode) { - case 0: - return "Test Mode"; - case 1: - return "Retest Mode"; - case 2: - return "Resume Mode"; - case 3: - return "Redo From Cache Mode"; - case 4: - return "Doc Mode"; - case 5: - return "Check Mode"; - default: - return "Invalid Mode"; - } - } - - private void saveSources() { - if (runOpts.getLogDir() != null && runOpts.getSessionId() != null) { - File sessionDir = new File(runOpts.getLogDir(), runOpts.getSessionId()); - File sourcesFile = new File(sessionDir, "sources.xml"); - try (PrintWriter writer = new PrintWriter(sourcesFile)) { - writer.println(""); - for (File file : setupOpts.getSources()) { - writer.println("" + file.getPath() + ""); - } - writer.println(""); - } - catch (FileNotFoundException e) { - e.printStackTrace(); - } - } - } - - private void loadSources() { - if (runOpts.getLogDir() != null && runOpts.getSessionId() != null) { - File sessionDir = new File(runOpts.getLogDir(), runOpts.getSessionId()); - File sourcesFile = new File(sessionDir, "sources.xml"); - if (sourcesFile.exists()) { - try { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.parse(sourcesFile); - NodeList nl = doc.getElementsByTagName("source"); - for (int i = 0; i < nl.getLength(); i++) { - String sourcePath = nl.item(i).getTextContent(); - File sourceFile = new File(sourcePath); - setupOpts.addSourceWithValidation(sourceFile); - } - } - catch (Exception e) { - e.printStackTrace(); - } - } - } - } - -} +/* + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): + 2009 F. Vitale vitale@imaa.cnr.it + 2018 C. Heazel cheazel@wiscenterprisesl.com + + Modifications: + 2/14/18 + - Addressed path manipulation vulnerabilities and general cleanup. + - Identified Issues which need further discussion. + + */ + +package com.occamlab.te; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; + +import com.occamlab.te.index.Index; +import com.occamlab.te.util.LogUtils; + +/** + * + * The main class for the TEAM Engine command line interface. + * + */ +public class Test { + + private static final Logger LOGR = Logger.getLogger(Test.class.getName()); + + public static final int TEST_MODE = 0; + + public static final int RETEST_MODE = 1; + + public static final int RESUME_MODE = 2; + + public static final int REDO_FROM_CACHE_MODE = 3; + + public static final int DOC_MODE = 4; + + public static final int CHECK_MODE = 5; + + public static final String XSL_NS = "http://www.w3.org/1999/XSL/Transform"; + + public static final String TE_NS = "http://www.occamlab.com/te"; + + public static final String CTL_NS = "http://www.occamlab.com/ctl"; + + public static final String CTLP_NS = "http://www.occamlab.com/te/parsers"; + + SetupOptions setupOpts; + + RuntimeOptions runOpts; + + /** + * Constructs a test executor with default options. + */ + public Test() { + this.setupOpts = new SetupOptions(); + this.runOpts = new RuntimeOptions(); + } + + /** + * Replace the SetupOptions with a new copy + * @param setupOpts The new copy of the setup options + * + * ISSUE: SetupOptions are established when the Teamengin is initialized. they should + * be the same for all tests. Why do we allow them to be modified? ISSUE: when and how + * are the setup options validated? ANSWER: Delete this method since it is never + * called. + */ + // void setSetupOptions(SetupOptions setupOpts) { + // this.setupOpts = setupOpts; + // } + + /** + * Replace the RuntimeOptions with a new copy + * @param runOpts The new copy of the runtime options + * + * ISSUE: when and how are the runtime options validated? ANSWER: make RuntimeOptions + * self-validating. + */ + void setRuntimeOptions(RuntimeOptions runOpts) { + this.runOpts = runOpts; + } + + // This method does not appear to be used. Consider deleting it. + // Changed from public to private until we validate that is can be removed. + + private void executeTest(String relativePathToMainCtl) throws Exception { + // File file =Misc.getResourceAsFile(relativePathToMainCtl); + String[] arguments = new String[1]; + arguments[0] = "-source=" + relativePathToMainCtl; + execute(arguments); + } + + /** + * Entry point from the command line. Creates a new test object then executes it. + * @param args An array of command line arguments + * @throws Exception + */ + public static void main(String[] args) throws Exception { + Test test = new Test(); + test.execute(args); + } + + /** + * Executes a test suite. + * @param args Command line arguments + * @throws Exception + */ + public void execute(String[] args) throws Exception { + @SuppressWarnings("unused") + boolean rslt; + + // Copy work directory from setup options to runtime + File workDir = setupOpts.getWorkDir(); + rslt = runOpts.setWorkDir(workDir); + + // Initialize the rest of the test context + String cmd = "java com.occamlab.te.Test"; + File logDir = runOpts.getLogDir(); + String session = null; + boolean hasSessionArg = false; + int mode = TEST_MODE; + + // Parse arguments from command-line + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if (arg.startsWith("-cmd=")) { + cmd = arg.substring(5); + } + else if (arg.equals("-h") || arg.equals("-help") || arg.equals("-?")) { + syntax(cmd); + return; + // The path to the test script. If the file name is not an absolute + // path then it must be under the Scripts directory. + // Issue: should we restrict the range of valid paths for source files? + } + else if (arg.startsWith("-source=")) { + String sourcePath = arg.substring(8); + File sourceFile = new File(sourcePath); + if (!sourceFile.isAbsolute()) { + File scriptsDir = new File(SetupOptions.getBaseConfigDirectory(), "scripts"); + sourceFile = new File(scriptsDir, sourcePath); + } + // Fortify Mod: Validate the sourceFile. It must both exist + // and pass validation by setupOptions + if (!sourceFile.exists() || !setupOpts.addSourceWithValidation(sourceFile)) { + System.out.println("Error: Cannot find CTL script(s) at " + sourceFile.getAbsolutePath()); + return; + } + } + else if (args[i].startsWith("-logdir=")) { + String path = args[i].substring(8); + File file = new File(path); + if (file.isAbsolute()) { + logDir = file; + } + else { + logDir = new File(SetupOptions.getBaseConfigDirectory(), path); + } + if (!logDir.exists() || !runOpts.setLogDir(logDir)) { + System.out.println("Error: Cannot use logdir " + logDir.getAbsolutePath()); + return; + } + } + else if (arg.startsWith("-session=")) { + // Issue: session is not validated but it is used as part of a file path. + hasSessionArg = true; + session = arg.substring(9); + } + else if (arg.startsWith("-base=")) { + rslt = runOpts.setBaseURI(arg.substring(6)); + } + else if (arg.startsWith("-test=")) { + rslt = runOpts.setTestName(arg.substring(6)); + } + else if (arg.startsWith("-suite=")) { + rslt = runOpts.setSuiteName(arg.substring(7)); + } + else if (arg.startsWith("-profile=")) { + rslt = runOpts.addProfile(arg.substring(9)); + } + else if (arg.startsWith("@")) { + rslt = runOpts.addParam(arg.substring(1)); + } + else if (arg.equals("-mode=test")) { + mode = TEST_MODE; + } + else if (arg.equals("-mode=retest")) { + mode = RETEST_MODE; + } + else if (arg.equals("-mode=resume")) { + mode = RESUME_MODE; + } + else if (arg.equals("-mode=doc")) { + mode = DOC_MODE; + } + else if (arg.equals("-mode=check")) { + mode = CHECK_MODE; + } + else if (arg.equals("-mode=cache")) { + mode = REDO_FROM_CACHE_MODE; + } + else if (arg.startsWith("-mode=")) { + System.out.println("Error: Invalid mode."); + return; + } + else if (arg.equals("-validate=no")) { + setupOpts.setValidate(false); + } + else if ((arg.startsWith("-form="))) { + rslt = runOpts.addRecordedForm(arg.substring(6)); + } + else if (!arg.startsWith("-")) { + if (mode == RETEST_MODE || mode == REDO_FROM_CACHE_MODE) { + if (hasSessionArg) { + if (arg.startsWith(session)) { + rslt = runOpts.addTestPath(arg); + } + else { + rslt = runOpts.addTestPath(session + "/" + arg); + } + } + else { + int slash = (arg).indexOf("/"); + if (slash >= 0) { + if (session == null) { + session = arg.substring(0, slash); + } + else if (!arg.substring(0, slash).equals(session)) { + System.out.println("Each test path must be within the same session."); + return; + } + rslt = runOpts.addTestPath(arg); + } + } + } + else { + System.out.println("Unrecognized parameter \"" + arg + "\""); + } + } + else { + System.out.println("Unrecognized parameter \"" + arg + "\""); + } + } + + // Set mode + rslt = runOpts.setMode(mode); + rslt = runOpts.setSessionId(session); + + if (mode == RETEST_MODE || mode == RESUME_MODE || mode == REDO_FROM_CACHE_MODE) { + if (logDir == null || session == null) { + syntax(cmd); + return; + } + if (setupOpts.getSources().isEmpty()) { + loadSources(); + } + } + + // Syntax checks + if (setupOpts.getSources().isEmpty()) { + System.out.println("Error: At least one -source parameter is required"); + return; + } + if (runOpts.getProfiles().size() > 0 && logDir == null) { + System.out.println("Error: A -logdir parameter is required for testing profiles"); + return; + } + + // Set session + if (session == null) { + session = System.getProperty("team.session"); + } + // CMH - changed session format to UUID. + // BPR - changed back to previous format + if (session == null) { + if (logDir == null) { + session = "s0001"; + } + else { + session = LogUtils.generateSessionId(logDir); + } + rslt = runOpts.setSessionId(session); + } + + Thread.currentThread().setName("TEAM Engine"); + Index masterIndex = new Index(); + File indexFile = null; + if (logDir != null && session != null) { + File dir = new File(logDir, runOpts.getSessionId()); + indexFile = new File(dir, "index.xml"); + } + + boolean regenerate = false; + + if (mode == TEST_MODE || mode == CHECK_MODE) { + regenerate = true; + } + else if (mode == DOC_MODE) { + masterIndex = Generator.generateDocXsl(setupOpts); + } + else { + if (indexFile == null || !indexFile.canRead()) { + System.out.println("Error: Can't read index file."); + regenerate = true; + } + else { + masterIndex = new Index(indexFile); + if (masterIndex.outOfDate()) { + System.out.println("Warning: Scripts have changed since this session was first executed."); + if (mode == REDO_FROM_CACHE_MODE) { + System.out.println("Regenerating masterIndex from source scripts"); + regenerate = true; + } + } + } + } + + if (regenerate) { + masterIndex = Generator.generateXsl(setupOpts); + if (indexFile != null) { + masterIndex.persist(indexFile); + } + } + + if (mode == REDO_FROM_CACHE_MODE) { + boolean hasCache = ViewLog.checkCache(logDir, session); + if (!hasCache) { + File dir = new File(logDir, runOpts.getSessionId()); + throw new Exception("Error: no cache for " + dir.getAbsolutePath()); + } + } + + // Fortify Mod: Make sure masterIndex is not null + // masterIndex.setElements(null); + if (masterIndex != null) { + masterIndex.setElements(null); + } + else { + masterIndex = new Index(); + } + List resourcesDirs = new ArrayList<>(); + for (File sourceFile : setupOpts.getSources()) { + File resourcesDir = findResourcesDirectory(sourceFile); + if (!resourcesDirs.contains(resourcesDir)) { + resourcesDirs.add(resourcesDir); + } + } + TEClassLoader cl = new TEClassLoader(resourcesDirs); + Engine engine = new Engine(masterIndex, setupOpts.getSourcesName(), cl); + + if (setupOpts.isPreload() || mode == CHECK_MODE) { + engine.preload(masterIndex, setupOpts.getSourcesName()); + } + + if (LOGR.isLoggable(Level.FINE)) { + LOGR.fine(runOpts.toString()); + } + + if (mode == TEST_MODE) { + saveSources(); + } + + if (mode != CHECK_MODE) { + TECore core = new TECore(engine, masterIndex, runOpts); + core.execute(); + } + + } + + /** + * Seeks a "resources" directory by searching the file system from a starting location + * and continuing upwards into ancestor directories. + * @param sourceFile A File denoting a file system location (file or directory). + * @return A File representing a directory named "resources", or {@code null} if one + * cannot be found. + */ + static File findResourcesDirectory(File sourceFile) { + File parent = sourceFile.getParentFile(); + if (null == parent) { + return null; + } + File[] resourceDirs = parent.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return (name.equalsIgnoreCase("resources") && new File(dir, name).isDirectory()); + } + }); + if (resourceDirs.length > 0) { + return resourceDirs[0]; + } + return findResourcesDirectory(parent); + } + + /** + * Displays startup command syntax. + * @param cmd Name of the startup command (i.e. test.bat or test.sh) + */ + static void syntax(String cmd) { + System.out.println(); + System.out.println("Test mode:"); + System.out.println(" Use to start a test session.\n"); + System.out.println(" " + cmd + " [-mode=test] -source=ctlfile|dir ..."); + System.out.println(" [-logdir=dir] [-session=session] [-base=baseURI]"); + System.out.println(" -suite=qname [-profile=qname|*] ... | -test=qname [@param-name=value] ...\n"); + System.out.println(" qname=[namespace_uri,|prefix:]local_name\n"); + System.out.println("Resume mode:"); + System.out.println(" Use to resume a test session that was interrupted before completion.\n"); + System.out.println(" " + cmd + " -mode=resume [-logdir=dir] -session=session\n"); + System.out.println("Retest mode:"); + System.out.println(" Use to reexecute individual tests.\n"); + System.out.println(" " + cmd + " -mode=retest [-logdir=dir] testpath1 [testpath2] ...\n"); + System.out.println("Redo From Cache Mode:"); + System.out.println(" Use to rerun tests with cached server responses when the test has changed.\n"); + System.out.println(" " + cmd + "-mode=cache [-logdir=dir] [-session=session] [testpath1 [testpath2]]\n"); + System.out.println(" Warning: Test changes may make cached server responses invalid.\n"); + System.out.println("Check mode:"); + System.out.println(" Use to validate source files.\n"); + System.out.println(" " + cmd + " -mode=check -source=ctlfile|dir ...\n"); + System.out.println("Doc mode:"); + System.out.println(" Use to visit all subtests and generate log files without executing them.\n"); + System.out.println(" " + cmd + " -mode=doc -source=ctlfile|dir ... [-suite=qname]\n"); + + /* + * Doc mode once again behaves as it originally did in + * https://sourceforge.net/p/teamengine/code/1 The entry point for the + * PseudoCTLDocumentation generator (which was called with -mode=doc starting with + * https://sourceforge.net/p/teamengine/code/459) is now the main method of + * DocumentationHelper. + */ + + /* + * The entry point for the PrettyPrintLogs functionality which was called with + * -mode=pplogs is now in the main method of ViewLog and is activated with its + * -html parameter. + */ + } + + /** + * Returns name of mode. + * @param mode + */ + public static String getModeName(int mode) { + switch (mode) { + case 0: + return "Test Mode"; + case 1: + return "Retest Mode"; + case 2: + return "Resume Mode"; + case 3: + return "Redo From Cache Mode"; + case 4: + return "Doc Mode"; + case 5: + return "Check Mode"; + default: + return "Invalid Mode"; + } + } + + private void saveSources() { + if (runOpts.getLogDir() != null && runOpts.getSessionId() != null) { + File sessionDir = new File(runOpts.getLogDir(), runOpts.getSessionId()); + File sourcesFile = new File(sessionDir, "sources.xml"); + try (PrintWriter writer = new PrintWriter(sourcesFile)) { + writer.println(""); + for (File file : setupOpts.getSources()) { + writer.println("" + file.getPath() + ""); + } + writer.println(""); + } + catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + } + + private void loadSources() { + if (runOpts.getLogDir() != null && runOpts.getSessionId() != null) { + File sessionDir = new File(runOpts.getLogDir(), runOpts.getSessionId()); + File sourcesFile = new File(sessionDir, "sources.xml"); + if (sourcesFile.exists()) { + try { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.parse(sourcesFile); + NodeList nl = doc.getElementsByTagName("source"); + for (int i = 0; i < nl.getLength(); i++) { + String sourcePath = nl.item(i).getTextContent(); + File sourceFile = new File(sourcePath); + setupOpts.addSourceWithValidation(sourceFile); + } + } + catch (Exception e) { + e.printStackTrace(); + } + } + } + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/ViewLog.java b/teamengine-core/src/main/java/com/occamlab/te/ViewLog.java index c98435a23..232badf61 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/ViewLog.java +++ b/teamengine-core/src/main/java/com/occamlab/te/ViewLog.java @@ -1,284 +1,304 @@ -/**************************************************************************** - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): - Charles Heazel (WiSC): Modifications to address Fortify issues - - ****************************************************************************/ -package com.occamlab.te; - -import java.io.File; -import java.io.InputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.Templates; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.occamlab.te.html.EarlToHtmlTransformation; -import com.occamlab.te.util.DocumentationHelper; -import com.occamlab.te.util.DomUtils; -import com.occamlab.te.util.LogUtils; -import com.occamlab.te.util.Misc; -import com.occamlab.te.util.NullWriter; -import com.occamlab.te.util.TEPath; // Fortify addition - -/** - * Presents a test log for display. - * - */ -public class ViewLog { - - static public boolean hasCache = false; - static String testName = " "; - - public static TransformerFactory transformerFactory = TransformerFactory.newInstance(); - - public static boolean view_log(String suiteName, File logdir, String session, ArrayList tests, - Templates templates, Writer out) throws Exception { - return view_log(suiteName, logdir, session, tests, templates, out, 1); - } - - public static boolean view_log(String suiteName, File logdir, String session, ArrayList tests, - Templates templates, Writer out, int testnum) throws Exception { - // Fortify mod: Validate logDir path - TEPath tpath = new TEPath(logdir.getAbsolutePath()); - if (!tpath.isValid()) { - System.out.println("ViewLog Error: Invalid log file name " + logdir); - return false; - } - hasCache = false; - Transformer t; - if (templates == null) { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - InputStream stream = cl.getResourceAsStream("com/occamlab/te/logstyles/default.xsl"); - t = transformerFactory.newTemplates(new StreamSource(stream)).newTransformer(); - } - else { - t = templates.newTransformer(); - } - t.setParameter("sessionDir", session); - t.setParameter("TESTNAME", suiteName); - t.setParameter("logdir", logdir.getAbsolutePath()); - t.setParameter("testnum", Integer.toString(testnum)); - DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - - if (tests.isEmpty() && session == null) { - Document doc = db.newDocument(); - Element sessions_e = doc.createElement("sessions"); - doc.appendChild(sessions_e); - String[] children = logdir.list(); - for (int i = 0; i < children.length; i++) { - if (new File(logdir, children[i]).isDirectory()) { - Element session_e = doc.createElement("session"); - session_e.setAttribute("id", children[i]); - sessions_e.appendChild(session_e); - } - } - t.transform(new DOMSource(doc), new StreamResult(out)); - return true; - } - else if (tests.isEmpty()) { - File session_dir = new File(logdir, session); - if (!session_dir.isDirectory()) { - System.out.println("Error: Directory " + session_dir.getAbsolutePath() + " does not exist."); - return false; - } - Document doc = LogUtils.makeTestList(logdir, session); - if (doc == null) { - return false; - } - // increment_counts(doc.getDocumentElement()); - t.transform(new DOMSource(doc), new StreamResult(out)); - Element testElement = DomUtils.getElementByTagName(doc, "test"); - if (testElement == null) { - return false; - } - else { - setHasCache(testElement); - return testElement.getAttribute("complete").equals("yes"); - } - } - else { - boolean ret = true; - for (String test : tests) { - File f = new File(new File(logdir, test), "log.xml"); - if (f.exists()) { - Document doc = LogUtils.makeTestList(logdir, test); - if (doc == null) { - return false; - } - Element testElement = DomUtils.getElementByTagName(doc, "test"); - if (testElement != null) { - setHasCache(testElement); - } - t.setParameter("index", doc); - Document log = LogUtils.readLog(logdir, test); - t.transform(new DOMSource(log), new StreamResult(out)); - Element logElement = (Element) (log.getElementsByTagName("log").item(0)); - NodeList endtestlist = logElement.getElementsByTagName("endtest"); - ret = ret && (endtestlist.getLength() > 0); - } - else { - System.out.println("Error: " + f.getAbsolutePath() + " does not exist."); - ret = ret && false; - } - } - return ret; - } - } - - static void setHasCache(Element testElement) { - String hasCacheAttributeValue = testElement.getAttribute("hasCache"); - hasCache = (hasCacheAttributeValue == null) ? false : (hasCacheAttributeValue.equals("yes") ? true : false); - } - - public static boolean hasCache() { - return hasCache; - } - - public static boolean checkCache(File logdir, String session) throws Exception { - view_log(null, logdir, session, new ArrayList<>(), null, new NullWriter(), 1); - return hasCache; - } - - public static void main(String[] args) throws Exception { - String testName = null; - File logDir = (new RuntimeOptions()).getLogDir(); - String session = null; - ArrayList tests = new ArrayList<>(); - String cmd = "java com.occamlab.te.ViewLog"; - String style = null; - boolean listSessions = false; - boolean ppLogs = false; - boolean generateHtml = false; - - for (int i = 0; i < args.length; i++) { - if (args[i].startsWith("-style=")) { - style = args[i].substring(7); - } - else if (args[i].startsWith("-cmd=")) { - cmd = args[i].substring(5); - } - else if (args[i].equals("-h") || args[i].equals("-help") || args[i].equals("-?")) { - syntax(cmd); - return; - } - else if (args[i].startsWith("-logdir=")) { - String path = args[i].substring(8); - File file = new File(path); - if (file.isAbsolute()) { - logDir = file; - } - else { - logDir = new File(SetupOptions.getBaseConfigDirectory(), path); - } - } - else if (args[i].equals("-sessions")) { - listSessions = true; - } - else if (args[i].startsWith("-session=")) { - session = args[i].substring(9); - } - else if (args[i].equals("-pp")) { - ppLogs = true; - } - else if (args[i].equals("-html")) { - generateHtml = true; - } - else if (!args[i].startsWith("-")) { - tests.add(args[i]); - } - } - - if (ppLogs) { - if (session == null) { - syntax(cmd); - return; - } - File sessionDir = new File(logDir, session); - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - DocumentationHelper docLogs = new DocumentationHelper( - cl.getResource("com/occamlab/te/test_report_html.xsl")); - File report = docLogs.prettyPrintsReport(sessionDir); - if (report != null) { - System.out.println("Generated " + report); - } - return; - } - - if (generateHtml) { - if (session == null) { - syntax(cmd); - return; - } - File sessionDir = new File(logDir, session); - File testLog = new File(sessionDir, "report_logs.xml"); - RuntimeOptions opts = new RuntimeOptions(); - opts.setLogDir(logDir); - opts.setSessionId(session); - Map testInputMap = new HashMap<>(); - CtlEarlReporter reporter = new CtlEarlReporter(); - reporter.generateEarlReport(sessionDir, testLog, opts.getSourcesName(), testInputMap); - EarlToHtmlTransformation earlToHtml = new EarlToHtmlTransformation(); - System.out.println("Generated EARL report " + earlToHtml.findEarlResultFile(sessionDir.getAbsolutePath())); - File htmlResult = earlToHtml.earlHtmlReport(sessionDir.getAbsolutePath()); - System.out.println("Generated HTML report " + new File(htmlResult, "index.html")); - return; - } - - if (tests.isEmpty() && session == null && !listSessions) { - syntax(cmd); - return; - } - - Templates templates = null; - if (style != null) { - File stylesheet = Misc.getResourceAsFile("com/occamlab/te/logstyles/default.xsl"); - stylesheet = new File(stylesheet.getParent(), style + ".xsl"); - if (!stylesheet.exists()) { - System.out - .println("Invalid style '" + style + "': " + stylesheet.getAbsolutePath() + " does not exist."); - return; - } - templates = transformerFactory.newTemplates(new StreamSource(stylesheet)); - } - - Writer out = new OutputStreamWriter(System.out); - view_log(testName, logDir, session, tests, templates, out); - } - - static void syntax(String cmd) { - System.out.println(); - System.out.println("To list user sessions:"); - System.out.println(" " + cmd + " [-logdir=dir] -sessions\n"); - System.out.println("To list tests in a session:"); - System.out.println(" " + cmd + " [-logdir=dir] -session=session\n"); - System.out.println("To view text results for individual tests:"); - System.out.println(" " + cmd + " [-logdir=dir] testpath1 [testpath2] ...\n"); - System.out.println("To \"Pretty Print\" the session results:"); - System.out.println(" " + cmd + " [-logdir=dir] -session=session -pp"); - System.out.println("To generate EARL and HTML reports of session results:"); - System.out.println(" " + cmd + " [-logdir=dir] -session=session -html"); - } - -} +/**************************************************************************** + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): + Charles Heazel (WiSC): Modifications to address Fortify issues + + ****************************************************************************/ +package com.occamlab.te; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.occamlab.te.html.EarlToHtmlTransformation; +import com.occamlab.te.util.DocumentationHelper; +import com.occamlab.te.util.DomUtils; +import com.occamlab.te.util.LogUtils; +import com.occamlab.te.util.Misc; +import com.occamlab.te.util.NullWriter; +import com.occamlab.te.util.TEPath; // Fortify addition + +/** + * Presents a test log for display. + * + */ +public class ViewLog { + + static public boolean hasCache = false; + static String testName = " "; + + public static TransformerFactory transformerFactory = TransformerFactory.newInstance(); + + public static boolean view_log(String suiteName, File logdir, String session, ArrayList tests, + Templates templates, Writer out) throws Exception { + return view_log(suiteName, logdir, session, tests, templates, out, 1); + } + + public static boolean view_log(String suiteName, File logdir, String session, ArrayList tests, + Templates templates, Writer out, int testnum) throws Exception { + // Fortify mod: Validate logDir path + TEPath tpath = new TEPath(logdir.getAbsolutePath()); + if (!tpath.isValid()) { + System.out.println("ViewLog Error: Invalid log file name " + logdir); + return false; + } + hasCache = false; + Transformer t; + if (templates == null) { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + InputStream stream = cl.getResourceAsStream("com/occamlab/te/logstyles/default.xsl"); + t = transformerFactory.newTemplates(new StreamSource(stream)).newTransformer(); + } + else { + t = templates.newTransformer(); + } + t.setParameter("sessionDir", session); + t.setParameter("TESTNAME", suiteName); + t.setParameter("logdir", logdir.getAbsolutePath()); + t.setParameter("testnum", Integer.toString(testnum)); + DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + + if (tests.isEmpty() && session == null) { + Document doc = db.newDocument(); + Element sessions_e = doc.createElement("sessions"); + doc.appendChild(sessions_e); + String[] children = logdir.list(); + for (int i = 0; i < children.length; i++) { + if (new File(logdir, children[i]).isDirectory()) { + Element session_e = doc.createElement("session"); + session_e.setAttribute("id", children[i]); + sessions_e.appendChild(session_e); + } + } + t.transform(new DOMSource(doc), new StreamResult(out)); + return true; + } + else if (tests.isEmpty()) { + File session_dir = new File(logdir, session); + if (!session_dir.isDirectory()) { + System.out.println("Error: Directory " + session_dir.getAbsolutePath() + " does not exist."); + return false; + } + Document doc = LogUtils.makeTestList(logdir, session); + if (doc == null) { + return false; + } + // increment_counts(doc.getDocumentElement()); + t.transform(new DOMSource(doc), new StreamResult(out)); + Element testElement = DomUtils.getElementByTagName(doc, "test"); + if (testElement == null) { + return false; + } + else { + setHasCache(testElement); + return testElement.getAttribute("complete").equals("yes"); + } + } + else { + boolean ret = true; + for (String test : tests) { + File f = new File(new File(logdir, test), "log.xml"); + if (f.exists()) { + Document doc = LogUtils.makeTestList(logdir, test); + if (doc == null) { + return false; + } + Element testElement = DomUtils.getElementByTagName(doc, "test"); + if (testElement != null) { + setHasCache(testElement); + } + t.setParameter("index", doc); + Document log = LogUtils.readLog(logdir, test); + t.transform(new DOMSource(log), new StreamResult(out)); + Element logElement = (Element) (log.getElementsByTagName("log").item(0)); + NodeList endtestlist = logElement.getElementsByTagName("endtest"); + ret = ret && (endtestlist.getLength() > 0); + } + else { + System.out.println("Error: " + f.getAbsolutePath() + " does not exist."); + ret = ret && false; + } + } + return ret; + } + } + + static void setHasCache(Element testElement) { + String hasCacheAttributeValue = testElement.getAttribute("hasCache"); + hasCache = (hasCacheAttributeValue == null) ? false : (hasCacheAttributeValue.equals("yes") ? true : false); + } + + public static boolean hasCache() { + return hasCache; + } + + public static boolean checkCache(File logdir, String session) throws Exception { + view_log(null, logdir, session, new ArrayList<>(), null, new NullWriter(), 1); + return hasCache; + } + + public static void main(String[] args) throws Exception { + String testName = null; + File logDir = (new RuntimeOptions()).getLogDir(); + String session = null; + ArrayList tests = new ArrayList<>(); + String cmd = "java com.occamlab.te.ViewLog"; + String style = null; + boolean listSessions = false; + boolean ppLogs = false; + boolean generateHtml = false; + + for (int i = 0; i < args.length; i++) { + if (args[i].startsWith("-style=")) { + style = args[i].substring(7); + } + else if (args[i].startsWith("-cmd=")) { + cmd = args[i].substring(5); + } + else if (args[i].equals("-h") || args[i].equals("-help") || args[i].equals("-?")) { + syntax(cmd); + return; + } + else if (args[i].startsWith("-logdir=")) { + String path = args[i].substring(8); + File file = new File(path); + if (file.isAbsolute()) { + logDir = file; + } + else { + logDir = new File(SetupOptions.getBaseConfigDirectory(), path); + } + } + else if (args[i].equals("-sessions")) { + listSessions = true; + } + else if (args[i].startsWith("-session=")) { + session = args[i].substring(9); + } + else if (args[i].equals("-pp")) { + ppLogs = true; + } + else if (args[i].equals("-html")) { + generateHtml = true; + } + else if (!args[i].startsWith("-")) { + tests.add(args[i]); + } + } + + if (ppLogs) { + if (session == null) { + syntax(cmd); + return; + } + File sessionDir = new File(logDir, session); + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + DocumentationHelper docLogs = new DocumentationHelper( + cl.getResource("com/occamlab/te/test_report_html.xsl")); + File report = docLogs.prettyPrintsReport(sessionDir); + if (report != null) { + System.out.println("Generated " + report); + } + return; + } + + if (generateHtml) { + if (session == null) { + syntax(cmd); + return; + } + File sessionDir = new File(logDir, session); + File testLog = new File(sessionDir, "report_logs.xml"); + RuntimeOptions opts = new RuntimeOptions(); + opts.setLogDir(logDir); + opts.setSessionId(session); + Map testInputMap = new HashMap<>(); + CtlEarlReporter reporter = new CtlEarlReporter(); + reporter.generateEarlReport(sessionDir, testLog, opts.getSourcesName(), testInputMap); + EarlToHtmlTransformation earlToHtml = new EarlToHtmlTransformation(); + System.out.println("Generated EARL report " + earlToHtml.findEarlResultFile(sessionDir.getAbsolutePath())); + File htmlResult = earlToHtml.earlHtmlReport(sessionDir.getAbsolutePath()); + System.out.println("Generated HTML report " + new File(htmlResult, "index.html")); + return; + } + + if (tests.isEmpty() && session == null && !listSessions) { + syntax(cmd); + return; + } + + Templates templates = null; + if (style != null) { + File stylesheet = Misc.getResourceAsFile("com/occamlab/te/logstyles/default.xsl"); + stylesheet = new File(stylesheet.getParent(), style + ".xsl"); + if (!stylesheet.exists()) { + System.out + .println("Invalid style '" + style + "': " + stylesheet.getAbsolutePath() + " does not exist."); + return; + } + templates = transformerFactory.newTemplates(new StreamSource(stylesheet)); + } + + Writer out = new OutputStreamWriter(System.out); + view_log(testName, logDir, session, tests, templates, out); + } + + static void syntax(String cmd) { + System.out.println(); + System.out.println("To list user sessions:"); + System.out.println(" " + cmd + " [-logdir=dir] -sessions\n"); + System.out.println("To list tests in a session:"); + System.out.println(" " + cmd + " [-logdir=dir] -session=session\n"); + System.out.println("To view text results for individual tests:"); + System.out.println(" " + cmd + " [-logdir=dir] testpath1 [testpath2] ...\n"); + System.out.println("To \"Pretty Print\" the session results:"); + System.out.println(" " + cmd + " [-logdir=dir] -session=session -pp"); + System.out.println("To generate EARL and HTML reports of session results:"); + System.out.println(" " + cmd + " [-logdir=dir] -session=session -html"); + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/config/Config.java b/teamengine-core/src/main/java/com/occamlab/te/config/Config.java index d750c85ab..850c35ef1 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/config/Config.java +++ b/teamengine-core/src/main/java/com/occamlab/te/config/Config.java @@ -19,6 +19,26 @@ C. Heazel (WiSC): Added Fortify adjudication changes ****************************************************************************/ package com.occamlab.te.config; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.File; import java.io.IOException; import java.io.InputStream; diff --git a/teamengine-core/src/main/java/com/occamlab/te/config/ConfigComparator.java b/teamengine-core/src/main/java/com/occamlab/te/config/ConfigComparator.java index cab27d8fb..e3dc9adea 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/config/ConfigComparator.java +++ b/teamengine-core/src/main/java/com/occamlab/te/config/ConfigComparator.java @@ -1,37 +1,57 @@ -package com.occamlab.te.config; - -import java.util.Comparator; - -/** - * Compares two ConfigEntry objects for order. - * - */ -public class ConfigComparator implements Comparator { - - private String denull(String s) { - return s == null ? "" : s; - } - - public int compare(ConfigEntry o1, ConfigEntry o2) { - int i = o1.organization.compareTo(o2.organization); - if (i != 0) - return i; - i = o1.standard.compareTo(o2.standard); - if (i != 0) - return i; - i = o1.version.compareTo(o2.version); - if (i != 0) - return i; - if (o1.suite != null && o2.suite != null) { - return denull(o1.revision).compareTo(denull(o2.revision)); - } - if (o1.suite == null && o2.suite != null) { - return -1; - } - if (o1.suite != null && o2.suite == null) { - return 1; - } - return 0; - } - -} +package com.occamlab.te.config; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.Comparator; + +/** + * Compares two ConfigEntry objects for order. + * + */ +public class ConfigComparator implements Comparator { + + private String denull(String s) { + return s == null ? "" : s; + } + + public int compare(ConfigEntry o1, ConfigEntry o2) { + int i = o1.organization.compareTo(o2.organization); + if (i != 0) + return i; + i = o1.standard.compareTo(o2.standard); + if (i != 0) + return i; + i = o1.version.compareTo(o2.version); + if (i != 0) + return i; + if (o1.suite != null && o2.suite != null) { + return denull(o1.revision).compareTo(denull(o2.revision)); + } + if (o1.suite == null && o2.suite != null) { + return -1; + } + if (o1.suite != null && o2.suite == null) { + return 1; + } + return 0; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/config/ConfigEntry.java b/teamengine-core/src/main/java/com/occamlab/te/config/ConfigEntry.java index 2e7060911..9b2eefce6 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/config/ConfigEntry.java +++ b/teamengine-core/src/main/java/com/occamlab/te/config/ConfigEntry.java @@ -1,169 +1,189 @@ -/** - * ************************************************************************** - * - * Contributor(s): - * C. Heazel (WiSC): Added Fortify adjudication changes - * - *************************************************************************** - */ -package com.occamlab.te.config; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import javax.xml.namespace.QName; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -/* Used exclusively in ConfigFileBuilder and ConfigComparator */ -public final class ConfigEntry { - - public String organization = null; - - public String standard = null; - - public String version = null; - - public String revision = null; - - public QName suite = null; - - public String title = null; - - public String description = null; - - public String link = null; - - public String dataLink = null; - - public List profiles = new ArrayList<>(); - - public List profileTitles = new ArrayList<>(); - - public List profileDescriptions = new ArrayList<>(); - - public List sources = new ArrayList<>(); - - public File resources; - - public String webdir; - - ConfigEntry(File file) throws Exception { - readConfigFile(file); - } - - void readConfigFile(File file) throws Exception { - // Fortify Mod: prevent external entity injection - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - // DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - Document doc = db.parse(file); - Element config = doc.getDocumentElement(); - Element organizationEl = getElementByTagName(config, "organization"); - if (organizationEl != null) { - organization = getElementByTagName(organizationEl, "name").getTextContent(); - } - Element standardEl = getElementByTagName(config, "standard"); - if (standardEl != null) { - standard = getElementByTagName(standardEl, "name").getTextContent(); - } - Element versionEl = getElementByTagName(config, "version"); - if (versionEl != null) { - version = getElementByTagName(versionEl, "name").getTextContent(); - } - Element revisionEl = getElementByTagName(config, "revision"); - if (revisionEl != null) { - revision = getElementByTagName(revisionEl, "name").getTextContent(); - } - Element suiteEl = getElementByTagName(config, "suite"); - if (suiteEl != null) { - String localName = getElementByTagName(suiteEl, "local-name").getTextContent(); - String namespaceUri = getElementByTagName(suiteEl, "namespace-uri").getTextContent(); - String prefix = getElementByTagName(suiteEl, "prefix").getTextContent(); - suite = new QName(namespaceUri, localName, prefix); - Element titleEl = getElementByTagName(suiteEl, "title"); - if (titleEl != null) { - title = titleEl.getTextContent(); - } - Element descriptionEl = getElementByTagName(suiteEl, "description"); - if (descriptionEl != null) { - description = descriptionEl.getTextContent(); - } - NodeList linkNodes = suiteEl.getElementsByTagName("link"); - for (int i = 0; i < linkNodes.getLength(); i++) { - Element linkEl = (Element) linkNodes.item(i); - String value = linkEl.getTextContent(); - if ("data".equals(linkEl.getAttribute("linkType"))) { - dataLink = file.getParentFile().getName() + "/" + value; - } - else if (value.startsWith("data/")) { - dataLink = file.getParentFile().getName() + "/" + value; - } - else { - link = value; - } - } - } - NodeList profileNodes = config.getElementsByTagName("profile"); - for (int i = 0; i < profileNodes.getLength(); i++) { - Element profileEl = (Element) profileNodes.item(i); - String localName = getElementByTagName(profileEl, "local-name").getTextContent(); - String namespaceUri = getElementByTagName(profileEl, "namespace-uri").getTextContent(); - String prefix = getElementByTagName(profileEl, "prefix").getTextContent(); - profiles.add(new QName(namespaceUri, localName, prefix)); - Element titleEl = getElementByTagName(profileEl, "title"); - profileTitles.add(titleEl == null ? "" : titleEl.getTextContent()); - Element descriptionEl = getElementByTagName(profileEl, "description"); - profileDescriptions.add(descriptionEl == null ? "" : descriptionEl.getTextContent()); - } - NodeList sourceNodes = config.getElementsByTagName("source"); - for (int i = 0; i < sourceNodes.getLength(); i++) { - Element sourceEl = (Element) sourceNodes.item(i); - sources.add(new File(file.getParentFile(), sourceEl.getTextContent())); - } - Element resourcesEl = getElementByTagName(config, "resources"); - if (resourcesEl != null) { - resources = new File(file.getParentFile(), resourcesEl.getTextContent()); - } - webdir = file.getParentFile().getName(); - Element webEl = getElementByTagName(config, "web"); - if (webEl != null) { - String dirname = webEl.getAttribute("dirname"); - if (dirname.length() > 0) { - webdir = dirname; - } - } - } - - void add(ConfigEntry config) { - profiles.addAll(config.profiles); - profileTitles.addAll(config.profileTitles); - profileDescriptions.addAll(config.profileDescriptions); - sources.addAll(config.sources); - } - - Element getElementByTagName(Node node, String tagname) { - NodeList nl; - if (node.getNodeType() == Node.DOCUMENT_NODE) { - nl = ((Document) node).getElementsByTagName(tagname); - } - else if (node.getNodeType() == Node.ELEMENT_NODE) { - nl = ((Element) node).getElementsByTagName(tagname); - } - else { - return null; - } - if (nl.getLength() >= 0) { - return (Element) nl.item(0); - } - else { - return null; - } - } - -} +/** + * ************************************************************************** + * + * Contributor(s): + * C. Heazel (WiSC): Added Fortify adjudication changes + * + *************************************************************************** + */ +package com.occamlab.te.config; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/* Used exclusively in ConfigFileBuilder and ConfigComparator */ +public final class ConfigEntry { + + public String organization = null; + + public String standard = null; + + public String version = null; + + public String revision = null; + + public QName suite = null; + + public String title = null; + + public String description = null; + + public String link = null; + + public String dataLink = null; + + public List profiles = new ArrayList<>(); + + public List profileTitles = new ArrayList<>(); + + public List profileDescriptions = new ArrayList<>(); + + public List sources = new ArrayList<>(); + + public File resources; + + public String webdir; + + ConfigEntry(File file) throws Exception { + readConfigFile(file); + } + + void readConfigFile(File file) throws Exception { + // Fortify Mod: prevent external entity injection + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + // DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document doc = db.parse(file); + Element config = doc.getDocumentElement(); + Element organizationEl = getElementByTagName(config, "organization"); + if (organizationEl != null) { + organization = getElementByTagName(organizationEl, "name").getTextContent(); + } + Element standardEl = getElementByTagName(config, "standard"); + if (standardEl != null) { + standard = getElementByTagName(standardEl, "name").getTextContent(); + } + Element versionEl = getElementByTagName(config, "version"); + if (versionEl != null) { + version = getElementByTagName(versionEl, "name").getTextContent(); + } + Element revisionEl = getElementByTagName(config, "revision"); + if (revisionEl != null) { + revision = getElementByTagName(revisionEl, "name").getTextContent(); + } + Element suiteEl = getElementByTagName(config, "suite"); + if (suiteEl != null) { + String localName = getElementByTagName(suiteEl, "local-name").getTextContent(); + String namespaceUri = getElementByTagName(suiteEl, "namespace-uri").getTextContent(); + String prefix = getElementByTagName(suiteEl, "prefix").getTextContent(); + suite = new QName(namespaceUri, localName, prefix); + Element titleEl = getElementByTagName(suiteEl, "title"); + if (titleEl != null) { + title = titleEl.getTextContent(); + } + Element descriptionEl = getElementByTagName(suiteEl, "description"); + if (descriptionEl != null) { + description = descriptionEl.getTextContent(); + } + NodeList linkNodes = suiteEl.getElementsByTagName("link"); + for (int i = 0; i < linkNodes.getLength(); i++) { + Element linkEl = (Element) linkNodes.item(i); + String value = linkEl.getTextContent(); + if ("data".equals(linkEl.getAttribute("linkType"))) { + dataLink = file.getParentFile().getName() + "/" + value; + } + else if (value.startsWith("data/")) { + dataLink = file.getParentFile().getName() + "/" + value; + } + else { + link = value; + } + } + } + NodeList profileNodes = config.getElementsByTagName("profile"); + for (int i = 0; i < profileNodes.getLength(); i++) { + Element profileEl = (Element) profileNodes.item(i); + String localName = getElementByTagName(profileEl, "local-name").getTextContent(); + String namespaceUri = getElementByTagName(profileEl, "namespace-uri").getTextContent(); + String prefix = getElementByTagName(profileEl, "prefix").getTextContent(); + profiles.add(new QName(namespaceUri, localName, prefix)); + Element titleEl = getElementByTagName(profileEl, "title"); + profileTitles.add(titleEl == null ? "" : titleEl.getTextContent()); + Element descriptionEl = getElementByTagName(profileEl, "description"); + profileDescriptions.add(descriptionEl == null ? "" : descriptionEl.getTextContent()); + } + NodeList sourceNodes = config.getElementsByTagName("source"); + for (int i = 0; i < sourceNodes.getLength(); i++) { + Element sourceEl = (Element) sourceNodes.item(i); + sources.add(new File(file.getParentFile(), sourceEl.getTextContent())); + } + Element resourcesEl = getElementByTagName(config, "resources"); + if (resourcesEl != null) { + resources = new File(file.getParentFile(), resourcesEl.getTextContent()); + } + webdir = file.getParentFile().getName(); + Element webEl = getElementByTagName(config, "web"); + if (webEl != null) { + String dirname = webEl.getAttribute("dirname"); + if (dirname.length() > 0) { + webdir = dirname; + } + } + } + + void add(ConfigEntry config) { + profiles.addAll(config.profiles); + profileTitles.addAll(config.profileTitles); + profileDescriptions.addAll(config.profileDescriptions); + sources.addAll(config.sources); + } + + Element getElementByTagName(Node node, String tagname) { + NodeList nl; + if (node.getNodeType() == Node.DOCUMENT_NODE) { + nl = ((Document) node).getElementsByTagName(tagname); + } + else if (node.getNodeType() == Node.ELEMENT_NODE) { + nl = ((Element) node).getElementsByTagName(tagname); + } + else { + return null; + } + if (nl.getLength() >= 0) { + return (Element) nl.item(0); + } + else { + return null; + } + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/config/ConfigFileBuilder.java b/teamengine-core/src/main/java/com/occamlab/te/config/ConfigFileBuilder.java index d55f9e48d..dfc2db635 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/config/ConfigFileBuilder.java +++ b/teamengine-core/src/main/java/com/occamlab/te/config/ConfigFileBuilder.java @@ -1,187 +1,207 @@ -package com.occamlab.te.config; - -import java.io.File; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.SortedSet; -import java.util.TreeSet; - -import javax.xml.namespace.QName; - -public class ConfigFileBuilder { - - /* - * Build an example master teamengine config file. To aggregate config files from - * several ETSs into a master config file, use ConfigFileCreator instead. - */ - public static void main(String[] args) throws Exception { - String home = ""; - String scriptsDir = "webapps/teamengine/WEB-INF/scripts"; - String workDir = "webapps/teamengine/WEB-INF/work"; - String usersDir = "webapps/teamengine/WEB-INF/users"; - String resourcesDir = null; - String defaultRevision = (new SimpleDateFormat("yyyy-MM-dd")).format(new Date()); - - // Parse arguments from command-line - for (int i = 0; i < args.length; i++) { - if (args[i].startsWith("-home=")) { - home = args[i].substring(6); - } - else if (args[i].startsWith("-scriptsdir=")) { - scriptsDir = args[i].substring(12); - } - else if (args[i].startsWith("-resourcesdir=")) { - scriptsDir = args[i].substring(14); - } - else if (args[i].startsWith("-usersdir=")) { - usersDir = args[i].substring(10); - } - else if (args[i].startsWith("-workdir=")) { - workDir = args[i].substring(9); - } - else if (args[i].startsWith("-defaultrev=")) { - defaultRevision = args[i].substring(12); - } - } - - if (resourcesDir == null) { - resourcesDir = scriptsDir; - } - - SortedSet configs = new TreeSet<>(new ConfigComparator()); - - File[] scriptDirs = new File(".").listFiles(); - for (File dir : scriptDirs) { - File file = new File(dir, "config.xml"); - if (file.canRead()) { - ConfigEntry config = new ConfigEntry(file); - File profilesDir = new File(dir, "profiles"); - if (profilesDir.isDirectory()) { - File[] profileDirs = profilesDir.listFiles(); - for (File pdir : profileDirs) { - File pfile = new File(pdir, "config.xml"); - if (pfile.canRead()) { - config.add(new ConfigEntry(pfile)); - } - } - } - configs.add(config); - } - } - - System.out.println(""); - System.out.println(" " + home + ""); - System.out.println(" " + scriptsDir + ""); - System.out.println(" " + resourcesDir + ""); - System.out.println(" " + usersDir + ""); - System.out.println(" " + workDir + ""); - System.out.println(" "); - - Iterator it = configs.iterator(); - ConfigEntry config = it.hasNext() ? it.next() : null; - while (config != null) { - String organization = config.organization; - System.out.println(" "); - System.out.println(" " + organization + ""); - while (config != null && config.organization.equals(organization)) { - String standard = config.standard; - System.out.println(" "); - System.out.println(" " + standard + ""); - while (config != null && config.organization.equals(organization) && config.standard.equals(standard)) { - String version = config.version; - System.out.println(" "); - System.out.println(" " + version + ""); - System.out.println(" "); - System.out - .println(" " + config.suite.getNamespaceURI() + ""); - System.out.println(" " + config.suite.getPrefix() + ""); - System.out.println(" " + config.suite.getLocalPart() + ""); - String title = config.title; - if (title == null) { - title = organization + " " + standard + " " + version + " Test Suite"; - } - System.out.println(" " + title + ""); - if (config.description != null) { - System.out.println(" " + config.description + ""); - } - if (config.link != null) { - System.out.println(" " + config.link + ""); - } - if (config.dataLink != null) { - System.out.println(" " + config.dataLink + ""); - } - System.out.println(" "); - while (config != null && config.organization.equals(organization) - && config.standard.equals(standard) && config.version.equals(version)) { - List profiles = new ArrayList<>(); - List profileTitles = new ArrayList<>(); - List profileDescriptions = new ArrayList<>(); - List sources = new ArrayList<>(); - while (config != null && config.suite == null) { - profiles.addAll(config.profiles); - profileTitles.addAll(config.profileTitles); - profileDescriptions.addAll(config.profileDescriptions); - sources.addAll(config.sources); - config = it.hasNext() ? it.next() : null; - } - if (config != null) { - profiles.addAll(config.profiles); - profileTitles.addAll(config.profileTitles); - profileDescriptions.addAll(config.profileDescriptions); - sources.addAll(config.sources); - String revision = config.revision; - if (revision == null) { - revision = defaultRevision; - } - System.out.println(" "); - System.out.println(" " + revision + ""); - System.out.println(" "); - for (File source : sources) { - String path = source.getPath().substring(2).replace('\\', '/'); - System.out.println(" " + path + ""); - } - System.out.println(" "); - if (config.resources != null) { - String path = config.resources.getPath().substring(2).replace('\\', '/'); - System.out.println(" " + path + ""); - } - if (config.webdir != null) { - System.out.println(" " + config.webdir + ""); - } - for (int i = 0; i < profiles.size(); i++) { - System.out.println(" "); - System.out.println(" " + profiles.get(i).getNamespaceURI() - + ""); - System.out - .println(" " + profiles.get(i).getPrefix() + ""); - System.out.println(" " + profiles.get(i).getLocalPart() - + ""); - String profileTitle = profileTitles.get(i); - if (profileTitle == null) - profileTitle = profiles.get(i).getLocalPart(); - System.out.println(" " + profileTitle + ""); - String profileDescription = profileDescriptions.get(i); - if (profileDescription != null) { - System.out - .println(" " + profileDescription + ""); - } - System.out.println(" "); - } - System.out.println(" "); - config = it.hasNext() ? it.next() : null; - } - } - System.out.println(" "); - } - System.out.println(" "); - } - System.out.println(" "); - } - System.out.println(" "); - System.out.println(""); - } - -} +package com.occamlab.te.config; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.xml.namespace.QName; + +public class ConfigFileBuilder { + + /* + * Build an example master teamengine config file. To aggregate config files from + * several ETSs into a master config file, use ConfigFileCreator instead. + */ + public static void main(String[] args) throws Exception { + String home = ""; + String scriptsDir = "webapps/teamengine/WEB-INF/scripts"; + String workDir = "webapps/teamengine/WEB-INF/work"; + String usersDir = "webapps/teamengine/WEB-INF/users"; + String resourcesDir = null; + String defaultRevision = (new SimpleDateFormat("yyyy-MM-dd")).format(new Date()); + + // Parse arguments from command-line + for (int i = 0; i < args.length; i++) { + if (args[i].startsWith("-home=")) { + home = args[i].substring(6); + } + else if (args[i].startsWith("-scriptsdir=")) { + scriptsDir = args[i].substring(12); + } + else if (args[i].startsWith("-resourcesdir=")) { + scriptsDir = args[i].substring(14); + } + else if (args[i].startsWith("-usersdir=")) { + usersDir = args[i].substring(10); + } + else if (args[i].startsWith("-workdir=")) { + workDir = args[i].substring(9); + } + else if (args[i].startsWith("-defaultrev=")) { + defaultRevision = args[i].substring(12); + } + } + + if (resourcesDir == null) { + resourcesDir = scriptsDir; + } + + SortedSet configs = new TreeSet<>(new ConfigComparator()); + + File[] scriptDirs = new File(".").listFiles(); + for (File dir : scriptDirs) { + File file = new File(dir, "config.xml"); + if (file.canRead()) { + ConfigEntry config = new ConfigEntry(file); + File profilesDir = new File(dir, "profiles"); + if (profilesDir.isDirectory()) { + File[] profileDirs = profilesDir.listFiles(); + for (File pdir : profileDirs) { + File pfile = new File(pdir, "config.xml"); + if (pfile.canRead()) { + config.add(new ConfigEntry(pfile)); + } + } + } + configs.add(config); + } + } + + System.out.println(""); + System.out.println(" " + home + ""); + System.out.println(" " + scriptsDir + ""); + System.out.println(" " + resourcesDir + ""); + System.out.println(" " + usersDir + ""); + System.out.println(" " + workDir + ""); + System.out.println(" "); + + Iterator it = configs.iterator(); + ConfigEntry config = it.hasNext() ? it.next() : null; + while (config != null) { + String organization = config.organization; + System.out.println(" "); + System.out.println(" " + organization + ""); + while (config != null && config.organization.equals(organization)) { + String standard = config.standard; + System.out.println(" "); + System.out.println(" " + standard + ""); + while (config != null && config.organization.equals(organization) && config.standard.equals(standard)) { + String version = config.version; + System.out.println(" "); + System.out.println(" " + version + ""); + System.out.println(" "); + System.out + .println(" " + config.suite.getNamespaceURI() + ""); + System.out.println(" " + config.suite.getPrefix() + ""); + System.out.println(" " + config.suite.getLocalPart() + ""); + String title = config.title; + if (title == null) { + title = organization + " " + standard + " " + version + " Test Suite"; + } + System.out.println(" " + title + ""); + if (config.description != null) { + System.out.println(" " + config.description + ""); + } + if (config.link != null) { + System.out.println(" " + config.link + ""); + } + if (config.dataLink != null) { + System.out.println(" " + config.dataLink + ""); + } + System.out.println(" "); + while (config != null && config.organization.equals(organization) + && config.standard.equals(standard) && config.version.equals(version)) { + List profiles = new ArrayList<>(); + List profileTitles = new ArrayList<>(); + List profileDescriptions = new ArrayList<>(); + List sources = new ArrayList<>(); + while (config != null && config.suite == null) { + profiles.addAll(config.profiles); + profileTitles.addAll(config.profileTitles); + profileDescriptions.addAll(config.profileDescriptions); + sources.addAll(config.sources); + config = it.hasNext() ? it.next() : null; + } + if (config != null) { + profiles.addAll(config.profiles); + profileTitles.addAll(config.profileTitles); + profileDescriptions.addAll(config.profileDescriptions); + sources.addAll(config.sources); + String revision = config.revision; + if (revision == null) { + revision = defaultRevision; + } + System.out.println(" "); + System.out.println(" " + revision + ""); + System.out.println(" "); + for (File source : sources) { + String path = source.getPath().substring(2).replace('\\', '/'); + System.out.println(" " + path + ""); + } + System.out.println(" "); + if (config.resources != null) { + String path = config.resources.getPath().substring(2).replace('\\', '/'); + System.out.println(" " + path + ""); + } + if (config.webdir != null) { + System.out.println(" " + config.webdir + ""); + } + for (int i = 0; i < profiles.size(); i++) { + System.out.println(" "); + System.out.println(" " + profiles.get(i).getNamespaceURI() + + ""); + System.out + .println(" " + profiles.get(i).getPrefix() + ""); + System.out.println(" " + profiles.get(i).getLocalPart() + + ""); + String profileTitle = profileTitles.get(i); + if (profileTitle == null) + profileTitle = profiles.get(i).getLocalPart(); + System.out.println(" " + profileTitle + ""); + String profileDescription = profileDescriptions.get(i); + if (profileDescription != null) { + System.out + .println(" " + profileDescription + ""); + } + System.out.println(" "); + } + System.out.println(" "); + config = it.hasNext() ? it.next() : null; + } + } + System.out.println(" "); + } + System.out.println(" "); + } + System.out.println(" "); + } + System.out.println(" "); + System.out.println(""); + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/config/ConfigFileCreator.java b/teamengine-core/src/main/java/com/occamlab/te/config/ConfigFileCreator.java index f72e881a8..c9ed9f915 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/config/ConfigFileCreator.java +++ b/teamengine-core/src/main/java/com/occamlab/te/config/ConfigFileCreator.java @@ -14,6 +14,26 @@ */ package com.occamlab.te.config; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.File; import java.io.FileOutputStream; import java.util.ArrayList; diff --git a/teamengine-core/src/main/java/com/occamlab/te/config/TEBaseNotFoundException.java b/teamengine-core/src/main/java/com/occamlab/te/config/TEBaseNotFoundException.java index 236fc6077..763523adb 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/config/TEBaseNotFoundException.java +++ b/teamengine-core/src/main/java/com/occamlab/te/config/TEBaseNotFoundException.java @@ -7,6 +7,26 @@ */ package com.occamlab.te.config; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + /** * Exception thrown when TE_BASE is not found. * diff --git a/teamengine-core/src/main/java/com/occamlab/te/config/TEConfigException.java b/teamengine-core/src/main/java/com/occamlab/te/config/TEConfigException.java index bf925aa2a..1a513ea8c 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/config/TEConfigException.java +++ b/teamengine-core/src/main/java/com/occamlab/te/config/TEConfigException.java @@ -7,6 +7,26 @@ */ package com.occamlab.te.config; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + public class TEConfigException extends RuntimeException { /** diff --git a/teamengine-core/src/main/java/com/occamlab/te/config/package-info.java b/teamengine-core/src/main/java/com/occamlab/te/config/package-info.java index 2cc2bea6e..0028fc4b4 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/config/package-info.java +++ b/teamengine-core/src/main/java/com/occamlab/te/config/package-info.java @@ -1,4 +1,23 @@ -/** - * This package provides classes for building and reading configuration files. - */ -package com.occamlab.te.config; \ No newline at end of file +/** + * This package provides classes for building and reading configuration files. + */ +package com.occamlab.te.config; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ diff --git a/teamengine-core/src/main/java/com/occamlab/te/form/ImageHandler.java b/teamengine-core/src/main/java/com/occamlab/te/form/ImageHandler.java index 3e7deed9a..92696eee3 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/form/ImageHandler.java +++ b/teamengine-core/src/main/java/com/occamlab/te/form/ImageHandler.java @@ -1,5 +1,25 @@ package com.occamlab.te.form; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; diff --git a/teamengine-core/src/main/java/com/occamlab/te/html/EarlToHtmlTransformation.java b/teamengine-core/src/main/java/com/occamlab/te/html/EarlToHtmlTransformation.java index 8c02dee4f..5bbf2ccec 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/html/EarlToHtmlTransformation.java +++ b/teamengine-core/src/main/java/com/occamlab/te/html/EarlToHtmlTransformation.java @@ -1,5 +1,25 @@ package com.occamlab.te.html; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import static java.util.logging.Level.FINE; import static java.util.logging.Level.SEVERE; diff --git a/teamengine-core/src/main/java/com/occamlab/te/index/FunctionEntry.java b/teamengine-core/src/main/java/com/occamlab/te/index/FunctionEntry.java index 27191df33..f84655019 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/index/FunctionEntry.java +++ b/teamengine-core/src/main/java/com/occamlab/te/index/FunctionEntry.java @@ -1,195 +1,215 @@ -package com.occamlab.te.index; - -import java.util.ArrayList; -import java.util.List; - -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -public class FunctionEntry extends TemplateEntry { - - boolean java; - - boolean initialized; - - String className; - - String method; - - int minArgs; - - int maxArgs; - - List classParams = null; - - FunctionEntry() { - super(); - } - - // public void persistAttributes(PrintWriter out) { - // super.persistAttributes(out); - // out.print(" type=\"" + (java ? "java" : "xsl") + "\""); - // } - // - // public void persistTags(PrintWriter out) { - // super.persistTags(out); - // if (minArgs != maxArgs) { - // int min = minArgs; - // int max = maxArgs; - // if (getParams() != null) { - // min -= getParams().size(); - // max -= getParams().size(); - // } - // if (usesContext()) { - // min--; - // max--; - // } - // out.println(""); - // } - // } - // - // public void persist(PrintWriter out) { - // persist(out, "function"); - // } - - FunctionEntry(Element function) { - super(function); - // System.out.println(DomUtils.serializeNode(function)); - // try { - String type = function.getAttribute("type"); - if (type.equals("xsl")) { - setJava(false); - // setTemplateFile(new File(new - // URI(function.getAttribute("file")))); - } - else if (type.equals("java")) { - // System.out.println(this.getId()); - setJava(true); - } - else { - throw new RuntimeException("Invalid function type"); - } - // NodeList nl = function.getElementsByTagName("param"); - // minArgs = nl.getLength(); - minArgs = 0; - if (this.getParams() != null) { - minArgs = this.getParams().size(); - } - maxArgs = minArgs; - // params = new ArrayList(); - // if (minArgs > 0) { - // for (int i = 0; i < minArgs; i++) { - // Element el = (Element)nl.item(i); - // String prefix = el.getAttribute("prefix"); - // String namespaceUri = el.getAttribute("namespace-uri"); - // String localName = el.getAttribute("local-name"); - // params.add(new QName(namespaceUri, localName, prefix)); - // } - // } - NodeList nl = function.getElementsByTagName("var-params"); - if (nl.getLength() > 0) { - Element varParams = (Element) nl.item(0); - String min = varParams.getAttribute("min"); - if (min != null) { - minArgs += Integer.parseInt(min); - } - String max = varParams.getAttribute("max"); - if (max != null) { - maxArgs += Integer.parseInt(max); - } - } - // setUsesContext(Boolean.parseBoolean(function.getAttribute("uses-context"))); - if (usesContext()) { - minArgs++; - maxArgs++; - } - Element e = (Element) function.getElementsByTagName("java").item(0); - if (e != null) { - setClassName(e.getAttribute("class")); - setMethod(e.getAttribute("method")); - setInitialized(Boolean.parseBoolean(e.getAttribute("initialized"))); - nl = e.getElementsByTagName("with-param"); - if (initialized && nl.getLength() > 0) { - classParams = new ArrayList<>(); - for (int i = 0; i < nl.getLength(); i++) { - Element el = (Element) nl.item(i); - Node value = null; - NodeList children = el.getChildNodes(); - for (int j = 0; j < children.getLength(); j++) { - Node n = children.item(j); - if (n.getNodeType() == Node.TEXT_NODE) { - value = n; - } - if (n.getNodeType() == Node.ELEMENT_NODE) { - value = n; - break; - } - } - classParams.add(value); - } - } - } - // } catch (URISyntaxException e) { - // throw new RuntimeException(e); - // } - } - - public String getClassName() { - return className; - } - - public void setClassName(String className) { - this.className = className; - } - - public boolean isInitialized() { - return initialized; - } - - public void setInitialized(boolean initialized) { - this.initialized = initialized; - } - - public boolean isJava() { - return java; - } - - public void setJava(boolean java) { - this.java = java; - } - - public int getMaxArgs() { - return maxArgs; - } - - public void setMaxArgs(int maxArgs) { - this.maxArgs = maxArgs; - } - - public int getMinArgs() { - return minArgs; - } - - public void setMinArgs(int minArgs) { - this.minArgs = minArgs; - } - - public String getMethod() { - return method; - } - - public void setMethod(String method) { - this.method = method; - } - - public List getClassParams() { - return classParams; - } - - public void setClassParams(List classParams) { - this.classParams = classParams; - } - -} +package com.occamlab.te.index; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.ArrayList; +import java.util.List; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class FunctionEntry extends TemplateEntry { + + boolean java; + + boolean initialized; + + String className; + + String method; + + int minArgs; + + int maxArgs; + + List classParams = null; + + FunctionEntry() { + super(); + } + + // public void persistAttributes(PrintWriter out) { + // super.persistAttributes(out); + // out.print(" type=\"" + (java ? "java" : "xsl") + "\""); + // } + // + // public void persistTags(PrintWriter out) { + // super.persistTags(out); + // if (minArgs != maxArgs) { + // int min = minArgs; + // int max = maxArgs; + // if (getParams() != null) { + // min -= getParams().size(); + // max -= getParams().size(); + // } + // if (usesContext()) { + // min--; + // max--; + // } + // out.println(""); + // } + // } + // + // public void persist(PrintWriter out) { + // persist(out, "function"); + // } + + FunctionEntry(Element function) { + super(function); + // System.out.println(DomUtils.serializeNode(function)); + // try { + String type = function.getAttribute("type"); + if (type.equals("xsl")) { + setJava(false); + // setTemplateFile(new File(new + // URI(function.getAttribute("file")))); + } + else if (type.equals("java")) { + // System.out.println(this.getId()); + setJava(true); + } + else { + throw new RuntimeException("Invalid function type"); + } + // NodeList nl = function.getElementsByTagName("param"); + // minArgs = nl.getLength(); + minArgs = 0; + if (this.getParams() != null) { + minArgs = this.getParams().size(); + } + maxArgs = minArgs; + // params = new ArrayList(); + // if (minArgs > 0) { + // for (int i = 0; i < minArgs; i++) { + // Element el = (Element)nl.item(i); + // String prefix = el.getAttribute("prefix"); + // String namespaceUri = el.getAttribute("namespace-uri"); + // String localName = el.getAttribute("local-name"); + // params.add(new QName(namespaceUri, localName, prefix)); + // } + // } + NodeList nl = function.getElementsByTagName("var-params"); + if (nl.getLength() > 0) { + Element varParams = (Element) nl.item(0); + String min = varParams.getAttribute("min"); + if (min != null) { + minArgs += Integer.parseInt(min); + } + String max = varParams.getAttribute("max"); + if (max != null) { + maxArgs += Integer.parseInt(max); + } + } + // setUsesContext(Boolean.parseBoolean(function.getAttribute("uses-context"))); + if (usesContext()) { + minArgs++; + maxArgs++; + } + Element e = (Element) function.getElementsByTagName("java").item(0); + if (e != null) { + setClassName(e.getAttribute("class")); + setMethod(e.getAttribute("method")); + setInitialized(Boolean.parseBoolean(e.getAttribute("initialized"))); + nl = e.getElementsByTagName("with-param"); + if (initialized && nl.getLength() > 0) { + classParams = new ArrayList<>(); + for (int i = 0; i < nl.getLength(); i++) { + Element el = (Element) nl.item(i); + Node value = null; + NodeList children = el.getChildNodes(); + for (int j = 0; j < children.getLength(); j++) { + Node n = children.item(j); + if (n.getNodeType() == Node.TEXT_NODE) { + value = n; + } + if (n.getNodeType() == Node.ELEMENT_NODE) { + value = n; + break; + } + } + classParams.add(value); + } + } + } + // } catch (URISyntaxException e) { + // throw new RuntimeException(e); + // } + } + + public String getClassName() { + return className; + } + + public void setClassName(String className) { + this.className = className; + } + + public boolean isInitialized() { + return initialized; + } + + public void setInitialized(boolean initialized) { + this.initialized = initialized; + } + + public boolean isJava() { + return java; + } + + public void setJava(boolean java) { + this.java = java; + } + + public int getMaxArgs() { + return maxArgs; + } + + public void setMaxArgs(int maxArgs) { + this.maxArgs = maxArgs; + } + + public int getMinArgs() { + return minArgs; + } + + public void setMinArgs(int minArgs) { + this.minArgs = minArgs; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public List getClassParams() { + return classParams; + } + + public void setClassParams(List classParams) { + this.classParams = classParams; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/index/Index.java b/teamengine-core/src/main/java/com/occamlab/te/index/Index.java index cecfa235e..7bf027547 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/index/Index.java +++ b/teamengine-core/src/main/java/com/occamlab/te/index/Index.java @@ -1,275 +1,295 @@ -/* - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): - C. Heazel (WiSC): Added Fortify adjudication changes - C. Heazel (WiSC): Modified setElements() to correctly handle a null argumet - */ - -package com.occamlab.te.index; - -import java.io.File; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.xml.namespace.QName; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import com.occamlab.te.util.DomUtils; - -public class Index { - - File indexFile = null; - - List dependencies = new ArrayList<>(); - - Map> functionsMap = new HashMap<>(); - - Map parserMap = new HashMap<>(); - - Map suiteMap = new HashMap<>(); - - Map profileMap = new HashMap<>(); - - Map testMap = new HashMap<>(); - - List elements = new ArrayList<>(); - - public Index() { - } - - public Index(File indexFile) throws Exception { - if (null == indexFile || !indexFile.exists()) { - throw new IllegalArgumentException("indexFile is null or does not exist."); - } - this.indexFile = indexFile; - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - // Fortify Mod: prevent external entity injection - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.parse(indexFile); - Element index = (Element) doc.getDocumentElement(); - NodeList nodes = index.getChildNodes(); - for (int i = 0; i < nodes.getLength(); i++) { - Node node = nodes.item(i); - if (node.getNodeType() == Node.ELEMENT_NODE) { - Element el = (Element) node; - elements.add(el); - String name = el.getNodeName(); - if (name.equals("dependency")) { - File file = new File(el.getAttribute("file").substring(5)); - dependencies.add(file); - } - else if (name.equals("suite")) { - SuiteEntry se = new SuiteEntry(el); - suiteMap.put(se.getId(), se); - } - else if (name.equals("profile")) { - ProfileEntry pe = new ProfileEntry(el); - profileMap.put(pe.getId(), pe); - } - else if (name.equals("test")) { - TestEntry te = new TestEntry(el); - testMap.put(te.getId(), te); - } - else if (name.equals("function")) { - FunctionEntry fe = new FunctionEntry(el); - List functions = functionsMap.get(fe.getId()); - if (functions == null) { - functions = new ArrayList<>(); - functions.add(fe); - functionsMap.put(fe.getId(), functions); - } - else { - functions.add(fe); - } - } - else if (name.equals("parser")) { - ParserEntry pe = new ParserEntry(el); - parserMap.put(pe.getId(), pe); - } - } - } - } - - public void persist(File file) throws Exception { - file.getParentFile().mkdirs(); - PrintWriter out = new PrintWriter(file); - out.println(""); - for (Element el : elements) { - out.println(DomUtils.serializeNode(el)); - } - out.println(""); - out.close(); - } - - public boolean outOfDate() { - if (indexFile != null) { - long indexDate = indexFile.lastModified(); - for (File file : dependencies) { - if (file.lastModified() + 1000 > indexDate) { - return true; - } - } - } - return false; - } - - public void add(Index index) { - elements.addAll(index.elements); - dependencies.addAll(index.dependencies); - functionsMap.putAll(index.functionsMap); - suiteMap.putAll(index.suiteMap); - profileMap.putAll(index.profileMap); - testMap.putAll(index.testMap); - parserMap.putAll(index.parserMap); - } - - public List getFunctions(String name) { - if (name.startsWith("{")) { - return functionsMap.get(name); - } - throw new RuntimeException("Invalid function name"); - } - - public List getFunctions(QName qname) { - return getFunctions("{" + qname.getNamespaceURI() + "}" + qname.getLocalPart()); - } - - public Set getFunctionKeys() { - return functionsMap.keySet(); - } - - public ParserEntry getParser(String name) { - return (ParserEntry) getEntry(parserMap, name); - } - - public ParserEntry getParser(QName qname) { - return (ParserEntry) getEntry(parserMap, qname); - } - - public Set getParserKeys() { - return parserMap.keySet(); - } - - public SuiteEntry getSuite(String name) { - return (SuiteEntry) getEntry(suiteMap, name); - } - - public SuiteEntry getSuite(QName qname) { - return (SuiteEntry) getEntry(suiteMap, qname); - } - - public Set getSuiteKeys() { - return suiteMap.keySet(); - } - - public ProfileEntry getProfile(String name) { - return (ProfileEntry) getEntry(profileMap, name); - } - - public ProfileEntry getProfile(QName qname) { - return (ProfileEntry) getEntry(profileMap, qname); - } - - public Set getProfileKeys() { - return profileMap.keySet(); - } - - public Collection getProfiles() { - return profileMap.values(); - } - - public TestEntry getTest(String name) { - return (TestEntry) getEntry(testMap, name); - } - - public TestEntry getTest(QName qname) { - return (TestEntry) getEntry(testMap, qname); - } - - public Set getTestKeys() { - return testMap.keySet(); - } - - private IndexEntry getEntry(Map map, QName qname) { - return getEntry(map, "{" + qname.getNamespaceURI() + "}" + qname.getLocalPart()); - } - - private IndexEntry getEntry(Map map, String name) { - if (name == null) { - return map.values().iterator().next(); - } - - if (name.startsWith("{")) { - return map.get(name); - } - - int i = name.lastIndexOf(','); - if (i >= 0) { - String key = "{" + name.substring(0, i) + "}" + name.substring(i + 1); - return map.get(key); - } - - String prefix = null; - String localName = name; - i = name.indexOf(':'); - if (i >= 0) { - prefix = name.substring(0, i); - localName = name.substring(i + 1); - } - - Iterator it = map.values().iterator(); - while (it.hasNext()) { - IndexEntry entry = it.next(); - if (entry.getLocalName().equals(localName)) { - if (prefix == null) { - return entry; - } - else { - if (entry.getPrefix().equals(prefix)) { - return entry; - } - } - } - } - - return null; - } - - public void setElements(List elements) { - // Mod to handle a null argument - if (elements != null) - this.elements = elements; - else - this.elements = new ArrayList<>(); - } - - public List getDependencies() { - return dependencies; - } - - public void setDependencies(List dependencies) { - this.dependencies = dependencies; - } - -} +/* + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): + C. Heazel (WiSC): Added Fortify adjudication changes + C. Heazel (WiSC): Modified setElements() to correctly handle a null argumet + */ + +package com.occamlab.te.index; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.occamlab.te.util.DomUtils; + +public class Index { + + File indexFile = null; + + List dependencies = new ArrayList<>(); + + Map> functionsMap = new HashMap<>(); + + Map parserMap = new HashMap<>(); + + Map suiteMap = new HashMap<>(); + + Map profileMap = new HashMap<>(); + + Map testMap = new HashMap<>(); + + List elements = new ArrayList<>(); + + public Index() { + } + + public Index(File indexFile) throws Exception { + if (null == indexFile || !indexFile.exists()) { + throw new IllegalArgumentException("indexFile is null or does not exist."); + } + this.indexFile = indexFile; + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + // Fortify Mod: prevent external entity injection + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.parse(indexFile); + Element index = (Element) doc.getDocumentElement(); + NodeList nodes = index.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + Element el = (Element) node; + elements.add(el); + String name = el.getNodeName(); + if (name.equals("dependency")) { + File file = new File(el.getAttribute("file").substring(5)); + dependencies.add(file); + } + else if (name.equals("suite")) { + SuiteEntry se = new SuiteEntry(el); + suiteMap.put(se.getId(), se); + } + else if (name.equals("profile")) { + ProfileEntry pe = new ProfileEntry(el); + profileMap.put(pe.getId(), pe); + } + else if (name.equals("test")) { + TestEntry te = new TestEntry(el); + testMap.put(te.getId(), te); + } + else if (name.equals("function")) { + FunctionEntry fe = new FunctionEntry(el); + List functions = functionsMap.get(fe.getId()); + if (functions == null) { + functions = new ArrayList<>(); + functions.add(fe); + functionsMap.put(fe.getId(), functions); + } + else { + functions.add(fe); + } + } + else if (name.equals("parser")) { + ParserEntry pe = new ParserEntry(el); + parserMap.put(pe.getId(), pe); + } + } + } + } + + public void persist(File file) throws Exception { + file.getParentFile().mkdirs(); + PrintWriter out = new PrintWriter(file); + out.println(""); + for (Element el : elements) { + out.println(DomUtils.serializeNode(el)); + } + out.println(""); + out.close(); + } + + public boolean outOfDate() { + if (indexFile != null) { + long indexDate = indexFile.lastModified(); + for (File file : dependencies) { + if (file.lastModified() + 1000 > indexDate) { + return true; + } + } + } + return false; + } + + public void add(Index index) { + elements.addAll(index.elements); + dependencies.addAll(index.dependencies); + functionsMap.putAll(index.functionsMap); + suiteMap.putAll(index.suiteMap); + profileMap.putAll(index.profileMap); + testMap.putAll(index.testMap); + parserMap.putAll(index.parserMap); + } + + public List getFunctions(String name) { + if (name.startsWith("{")) { + return functionsMap.get(name); + } + throw new RuntimeException("Invalid function name"); + } + + public List getFunctions(QName qname) { + return getFunctions("{" + qname.getNamespaceURI() + "}" + qname.getLocalPart()); + } + + public Set getFunctionKeys() { + return functionsMap.keySet(); + } + + public ParserEntry getParser(String name) { + return (ParserEntry) getEntry(parserMap, name); + } + + public ParserEntry getParser(QName qname) { + return (ParserEntry) getEntry(parserMap, qname); + } + + public Set getParserKeys() { + return parserMap.keySet(); + } + + public SuiteEntry getSuite(String name) { + return (SuiteEntry) getEntry(suiteMap, name); + } + + public SuiteEntry getSuite(QName qname) { + return (SuiteEntry) getEntry(suiteMap, qname); + } + + public Set getSuiteKeys() { + return suiteMap.keySet(); + } + + public ProfileEntry getProfile(String name) { + return (ProfileEntry) getEntry(profileMap, name); + } + + public ProfileEntry getProfile(QName qname) { + return (ProfileEntry) getEntry(profileMap, qname); + } + + public Set getProfileKeys() { + return profileMap.keySet(); + } + + public Collection getProfiles() { + return profileMap.values(); + } + + public TestEntry getTest(String name) { + return (TestEntry) getEntry(testMap, name); + } + + public TestEntry getTest(QName qname) { + return (TestEntry) getEntry(testMap, qname); + } + + public Set getTestKeys() { + return testMap.keySet(); + } + + private IndexEntry getEntry(Map map, QName qname) { + return getEntry(map, "{" + qname.getNamespaceURI() + "}" + qname.getLocalPart()); + } + + private IndexEntry getEntry(Map map, String name) { + if (name == null) { + return map.values().iterator().next(); + } + + if (name.startsWith("{")) { + return map.get(name); + } + + int i = name.lastIndexOf(','); + if (i >= 0) { + String key = "{" + name.substring(0, i) + "}" + name.substring(i + 1); + return map.get(key); + } + + String prefix = null; + String localName = name; + i = name.indexOf(':'); + if (i >= 0) { + prefix = name.substring(0, i); + localName = name.substring(i + 1); + } + + Iterator it = map.values().iterator(); + while (it.hasNext()) { + IndexEntry entry = it.next(); + if (entry.getLocalName().equals(localName)) { + if (prefix == null) { + return entry; + } + else { + if (entry.getPrefix().equals(prefix)) { + return entry; + } + } + } + } + + return null; + } + + public void setElements(List elements) { + // Mod to handle a null argument + if (elements != null) + this.elements = elements; + else + this.elements = new ArrayList<>(); + } + + public List getDependencies() { + return dependencies; + } + + public void setDependencies(List dependencies) { + this.dependencies = dependencies; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/index/IndexEntry.java b/teamengine-core/src/main/java/com/occamlab/te/index/IndexEntry.java index a485328fb..62974fd50 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/index/IndexEntry.java +++ b/teamengine-core/src/main/java/com/occamlab/te/index/IndexEntry.java @@ -1,65 +1,85 @@ -package com.occamlab.te.index; - -import javax.xml.namespace.QName; - -import org.w3c.dom.Element; - -public class IndexEntry implements NamedEntry { - - QName qname = null; - - IndexEntry() { - } - - IndexEntry(Element el) { - String prefix = el.getAttribute("prefix"); - String namespaceUri = el.getAttribute("namespace-uri"); - String localName = el.getAttribute("local-name"); - setQName(new QName(namespaceUri, localName, prefix)); - } - - public String getName() { - if (qname == null) { - return null; - } - String prefix = qname.getPrefix(); - if (prefix == null) { - return qname.getLocalPart(); - } - else { - return prefix + ":" + qname.getLocalPart(); - } - } - - public String getLocalName() { - return qname.getLocalPart(); - } - - public String getNamespaceURI() { - return qname.getNamespaceURI(); - } - - public String getPrefix() { - return qname.getPrefix(); - } - - public QName getQName() { - return qname; - } - - public void setQName(QName qname) { - this.qname = qname; - } - - public String getId() { - return "{" + qname.getNamespaceURI() + "}" + qname.getLocalPart(); - } - - public String toString() { - if (qname == null) { - return super.toString(); - } - return qname.toString(); - } - -} +package com.occamlab.te.index; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import javax.xml.namespace.QName; + +import org.w3c.dom.Element; + +public class IndexEntry implements NamedEntry { + + QName qname = null; + + IndexEntry() { + } + + IndexEntry(Element el) { + String prefix = el.getAttribute("prefix"); + String namespaceUri = el.getAttribute("namespace-uri"); + String localName = el.getAttribute("local-name"); + setQName(new QName(namespaceUri, localName, prefix)); + } + + public String getName() { + if (qname == null) { + return null; + } + String prefix = qname.getPrefix(); + if (prefix == null) { + return qname.getLocalPart(); + } + else { + return prefix + ":" + qname.getLocalPart(); + } + } + + public String getLocalName() { + return qname.getLocalPart(); + } + + public String getNamespaceURI() { + return qname.getNamespaceURI(); + } + + public String getPrefix() { + return qname.getPrefix(); + } + + public QName getQName() { + return qname; + } + + public void setQName(QName qname) { + this.qname = qname; + } + + public String getId() { + return "{" + qname.getNamespaceURI() + "}" + qname.getLocalPart(); + } + + public String toString() { + if (qname == null) { + return super.toString(); + } + return qname.toString(); + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/index/NamedEntry.java b/teamengine-core/src/main/java/com/occamlab/te/index/NamedEntry.java index 1c1cffc3a..312be5f45 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/index/NamedEntry.java +++ b/teamengine-core/src/main/java/com/occamlab/te/index/NamedEntry.java @@ -1,21 +1,41 @@ -package com.occamlab.te.index; - -import javax.xml.namespace.QName; - -public interface NamedEntry { - - String getName(); - - String getLocalName(); - - String getNamespaceURI(); - - String getPrefix(); - - QName getQName(); - - void setQName(QName qname); - - String getId(); - -} +package com.occamlab.te.index; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import javax.xml.namespace.QName; + +public interface NamedEntry { + + String getName(); + + String getLocalName(); + + String getNamespaceURI(); + + String getPrefix(); + + QName getQName(); + + void setQName(QName qname); + + String getId(); + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/index/ParserEntry.java b/teamengine-core/src/main/java/com/occamlab/te/index/ParserEntry.java index 213f48194..a62e07b59 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/index/ParserEntry.java +++ b/teamengine-core/src/main/java/com/occamlab/te/index/ParserEntry.java @@ -1,90 +1,110 @@ -package com.occamlab.te.index; - -import java.util.ArrayList; -import java.util.List; - -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import com.occamlab.te.util.DomUtils; - -public class ParserEntry extends IndexEntry { - - boolean initialized; - - String className; - - String method; - - List classParams = null; - - ParserEntry() { - super(); - } - - ParserEntry(Element parser) throws Exception { - super(parser); - Element e = (Element) parser.getElementsByTagName("java").item(0); - if (e != null) { - setClassName(e.getAttribute("class")); - setMethod(e.getAttribute("method")); - setInitialized(Boolean.parseBoolean(e.getAttribute("initialized"))); - NodeList nl = e.getElementsByTagName("with-param"); - if (nl.getLength() > 0) { - setInitialized(true); - classParams = new ArrayList<>(); - for (int i = 0; i < nl.getLength(); i++) { - Element el = (Element) nl.item(i); - // System.out.println(DomUtils.serializeNode(el)); - Node value = null; - NodeList children = el.getChildNodes(); - for (int j = 0; j < children.getLength(); j++) { - Node n = children.item(j); - if (n.getNodeType() == Node.TEXT_NODE) { - value = n; - } - if (n.getNodeType() == Node.ELEMENT_NODE) { - value = DomUtils.createDocument(n); - break; - } - } - classParams.add(value); - } - } - } - } - - public String getClassName() { - return className; - } - - public void setClassName(String className) { - this.className = className; - } - - public boolean isInitialized() { - return initialized; - } - - public void setInitialized(boolean initialized) { - this.initialized = initialized; - } - - public String getMethod() { - return method; - } - - public void setMethod(String method) { - this.method = method; - } - - public List getClassParams() { - return classParams; - } - - public void setClassParams(List classParams) { - this.classParams = classParams; - } - -} +package com.occamlab.te.index; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.ArrayList; +import java.util.List; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.occamlab.te.util.DomUtils; + +public class ParserEntry extends IndexEntry { + + boolean initialized; + + String className; + + String method; + + List classParams = null; + + ParserEntry() { + super(); + } + + ParserEntry(Element parser) throws Exception { + super(parser); + Element e = (Element) parser.getElementsByTagName("java").item(0); + if (e != null) { + setClassName(e.getAttribute("class")); + setMethod(e.getAttribute("method")); + setInitialized(Boolean.parseBoolean(e.getAttribute("initialized"))); + NodeList nl = e.getElementsByTagName("with-param"); + if (nl.getLength() > 0) { + setInitialized(true); + classParams = new ArrayList<>(); + for (int i = 0; i < nl.getLength(); i++) { + Element el = (Element) nl.item(i); + // System.out.println(DomUtils.serializeNode(el)); + Node value = null; + NodeList children = el.getChildNodes(); + for (int j = 0; j < children.getLength(); j++) { + Node n = children.item(j); + if (n.getNodeType() == Node.TEXT_NODE) { + value = n; + } + if (n.getNodeType() == Node.ELEMENT_NODE) { + value = DomUtils.createDocument(n); + break; + } + } + classParams.add(value); + } + } + } + } + + public String getClassName() { + return className; + } + + public void setClassName(String className) { + this.className = className; + } + + public boolean isInitialized() { + return initialized; + } + + public void setInitialized(boolean initialized) { + this.initialized = initialized; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public List getClassParams() { + return classParams; + } + + public void setClassParams(List classParams) { + this.classParams = classParams; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/index/ProfileEntry.java b/teamengine-core/src/main/java/com/occamlab/te/index/ProfileEntry.java index 7cba0de78..e5917a1ff 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/index/ProfileEntry.java +++ b/teamengine-core/src/main/java/com/occamlab/te/index/ProfileEntry.java @@ -1,119 +1,139 @@ -package com.occamlab.te.index; - -import java.util.ArrayList; -import java.util.List; - -import javax.xml.namespace.QName; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import com.occamlab.te.Test; -import com.occamlab.te.util.DomUtils; - -public class ProfileEntry extends IndexEntry { - - String defaultResult = "Pass"; - - QName baseSuite; - - List> excludes = new ArrayList<>(); - - QName startingTest; - - Document form = null; - - String title = null; - - String description = null; - - public ProfileEntry() { - super(); - } - - public ProfileEntry(Element profile) throws Exception { - super(profile); - title = DomUtils.getElementByTagName(profile, "title").getTextContent(); - description = DomUtils.getElementByTagName(profile, "description").getTextContent(); - Element base = DomUtils.getElementByTagName(profile, "base"); - baseSuite = getQName(base); - for (Element exclude : DomUtils.getElementsByTagName(profile, "exclude")) { - ArrayList list = new ArrayList<>(); - for (Element test : DomUtils.getElementsByTagName(exclude, "test")) { - list.add(getQName(test)); - } - excludes.add(list); - } - setDefaultResult(DomUtils.getElementByTagName(profile, "defaultResult").getTextContent()); - Element e = DomUtils.getElementByTagName(profile, "starting-test"); - startingTest = getQName(e); - Element form_e = DomUtils.getElementByTagNameNS(profile, Test.CTL_NS, "form"); - if (form_e != null) { - form = DomUtils.createDocument(form_e); - } - } - - public QName getStartingTest() { - return startingTest; - } - - public void setStartingTest(QName startingTest) { - this.startingTest = startingTest; - } - - public Document getForm() { - return form; - } - - public void setForm(Document form) { - this.form = form; - } - - public QName getBaseSuite() { - return baseSuite; - } - - public void setBaseSuite(QName baseSuite) { - this.baseSuite = baseSuite; - } - - public List> getExcludes() { - return excludes; - } - - public void setExcludes(List> excludes) { - this.excludes = excludes; - } - - QName getQName(Element e) { - String prefix = e.getAttribute("prefix"); - String namespaceUri = e.getAttribute("namespace-uri"); - String localName = e.getAttribute("local-name"); - return new QName(namespaceUri, localName, prefix); - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getDefaultResult() { - return defaultResult; - } - - public void setDefaultResult(String defaultResult) { - this.defaultResult = defaultResult; - } - -} +package com.occamlab.te.index; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import com.occamlab.te.Test; +import com.occamlab.te.util.DomUtils; + +public class ProfileEntry extends IndexEntry { + + String defaultResult = "Pass"; + + QName baseSuite; + + List> excludes = new ArrayList<>(); + + QName startingTest; + + Document form = null; + + String title = null; + + String description = null; + + public ProfileEntry() { + super(); + } + + public ProfileEntry(Element profile) throws Exception { + super(profile); + title = DomUtils.getElementByTagName(profile, "title").getTextContent(); + description = DomUtils.getElementByTagName(profile, "description").getTextContent(); + Element base = DomUtils.getElementByTagName(profile, "base"); + baseSuite = getQName(base); + for (Element exclude : DomUtils.getElementsByTagName(profile, "exclude")) { + ArrayList list = new ArrayList<>(); + for (Element test : DomUtils.getElementsByTagName(exclude, "test")) { + list.add(getQName(test)); + } + excludes.add(list); + } + setDefaultResult(DomUtils.getElementByTagName(profile, "defaultResult").getTextContent()); + Element e = DomUtils.getElementByTagName(profile, "starting-test"); + startingTest = getQName(e); + Element form_e = DomUtils.getElementByTagNameNS(profile, Test.CTL_NS, "form"); + if (form_e != null) { + form = DomUtils.createDocument(form_e); + } + } + + public QName getStartingTest() { + return startingTest; + } + + public void setStartingTest(QName startingTest) { + this.startingTest = startingTest; + } + + public Document getForm() { + return form; + } + + public void setForm(Document form) { + this.form = form; + } + + public QName getBaseSuite() { + return baseSuite; + } + + public void setBaseSuite(QName baseSuite) { + this.baseSuite = baseSuite; + } + + public List> getExcludes() { + return excludes; + } + + public void setExcludes(List> excludes) { + this.excludes = excludes; + } + + QName getQName(Element e) { + String prefix = e.getAttribute("prefix"); + String namespaceUri = e.getAttribute("namespace-uri"); + String localName = e.getAttribute("local-name"); + return new QName(namespaceUri, localName, prefix); + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDefaultResult() { + return defaultResult; + } + + public void setDefaultResult(String defaultResult) { + this.defaultResult = defaultResult; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/index/SuiteEntry.java b/teamengine-core/src/main/java/com/occamlab/te/index/SuiteEntry.java index 69b65d0b2..f0d7b0b1a 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/index/SuiteEntry.java +++ b/teamengine-core/src/main/java/com/occamlab/te/index/SuiteEntry.java @@ -1,103 +1,123 @@ -package com.occamlab.te.index; - -import javax.xml.namespace.QName; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import com.occamlab.te.Test; -import com.occamlab.te.util.DomUtils; - -public class SuiteEntry extends IndexEntry { - - String defaultResult = "Pass"; - - QName startingTest; - - Document form = null; - - String title = null; - - String description = null; - - String link; - - String dataLink; - - public SuiteEntry() { - super(); - } - - SuiteEntry(Element suite) throws Exception { - super(suite); - title = DomUtils.getElementByTagName(suite, "title").getTextContent(); - description = DomUtils.getElementByTagName(suite, "description").getTextContent(); - Element e = DomUtils.getElementByTagName(suite, "starting-test"); - String prefix = e.getAttribute("prefix"); - String namespaceUri = e.getAttribute("namespace-uri"); - String localName = e.getAttribute("local-name"); - setDefaultResult(DomUtils.getElementByTagName(suite, "defaultResult").getTextContent()); - startingTest = new QName(namespaceUri, localName, prefix); - Element form_e = DomUtils.getElementByTagNameNS(suite, Test.CTL_NS, "form"); - if (form_e != null) { - form = DomUtils.createDocument(form_e); - } - } - - public QName getStartingTest() { - return startingTest; - } - - public void setStartingTest(QName startingTest) { - this.startingTest = startingTest; - } - - public Document getForm() { - return form; - } - - public void setForm(Document form) { - this.form = form; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getDataLink() { - return dataLink; - } - - public void setDataLink(String dataLink) { - this.dataLink = dataLink; - } - - public String getLink() { - return link; - } - - public void setLink(String link) { - this.link = link; - } - - public String getDefaultResult() { - return defaultResult; - } - - public void setDefaultResult(String defaultResult) { - this.defaultResult = defaultResult; - } - -} +package com.occamlab.te.index; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import javax.xml.namespace.QName; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import com.occamlab.te.Test; +import com.occamlab.te.util.DomUtils; + +public class SuiteEntry extends IndexEntry { + + String defaultResult = "Pass"; + + QName startingTest; + + Document form = null; + + String title = null; + + String description = null; + + String link; + + String dataLink; + + public SuiteEntry() { + super(); + } + + SuiteEntry(Element suite) throws Exception { + super(suite); + title = DomUtils.getElementByTagName(suite, "title").getTextContent(); + description = DomUtils.getElementByTagName(suite, "description").getTextContent(); + Element e = DomUtils.getElementByTagName(suite, "starting-test"); + String prefix = e.getAttribute("prefix"); + String namespaceUri = e.getAttribute("namespace-uri"); + String localName = e.getAttribute("local-name"); + setDefaultResult(DomUtils.getElementByTagName(suite, "defaultResult").getTextContent()); + startingTest = new QName(namespaceUri, localName, prefix); + Element form_e = DomUtils.getElementByTagNameNS(suite, Test.CTL_NS, "form"); + if (form_e != null) { + form = DomUtils.createDocument(form_e); + } + } + + public QName getStartingTest() { + return startingTest; + } + + public void setStartingTest(QName startingTest) { + this.startingTest = startingTest; + } + + public Document getForm() { + return form; + } + + public void setForm(Document form) { + this.form = form; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDataLink() { + return dataLink; + } + + public void setDataLink(String dataLink) { + this.dataLink = dataLink; + } + + public String getLink() { + return link; + } + + public void setLink(String link) { + this.link = link; + } + + public String getDefaultResult() { + return defaultResult; + } + + public void setDefaultResult(String defaultResult) { + this.defaultResult = defaultResult; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/index/TemplateEntry.java b/teamengine-core/src/main/java/com/occamlab/te/index/TemplateEntry.java index 9978b4a59..4b8e5427a 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/index/TemplateEntry.java +++ b/teamengine-core/src/main/java/com/occamlab/te/index/TemplateEntry.java @@ -1,132 +1,152 @@ -package com.occamlab.te.index; - -import java.io.File; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.List; - -import javax.xml.namespace.QName; - -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -public class TemplateEntry extends IndexEntry { - - File templateFile = null; - - boolean usesContext; - - List params = null; - - TemplateEntry() { - super(); - } - - TemplateEntry(Element template) { - super(template); - try { - String file = template.getAttribute("file"); - if (file != null && file.length() > 0) { - setTemplateFile(new File(new URI(template.getAttribute("file")))); - } - NodeList nl = template.getElementsByTagName("param"); - params = new ArrayList<>(); - for (int i = 0; i < nl.getLength(); i++) { - Element el = (Element) nl.item(i); - String prefix = el.getAttribute("prefix"); - String namespaceUri = el.getAttribute("namespace-uri"); - String localName = el.getAttribute("local-name"); - params.add(new QName(namespaceUri, localName, prefix)); - } - setUsesContext(Boolean.parseBoolean(template.getAttribute("uses-context"))); - } - catch (URISyntaxException e) { - throw new RuntimeException(e); - } - } - - // public void persistAttributes(PrintWriter out) { - // super.persistAttributes(out); - // try { - // out.print(" file=\"" + templateFile.toURI().toURL().toString() + "\"" - // + " uses-context=\"" + Boolean.toString(usesContext) + "\""); - // } catch (MalformedURLException e) { - // throw new RuntimeException(e); - // } - // } - // - // public void persistTags(PrintWriter out) { - // super.persistTags(out); - // for (QName qname : params) { - // out.println(""); - // } - // } - - public File getTemplateFile() { - return templateFile; - } - - public void setTemplateFile(File templateFile) { - this.templateFile = templateFile; - } - - public List getParams() { - return params; - } - - public void setParams(List params) { - this.params = params; - } - - public boolean usesContext() { - return usesContext; - } - - public void setUsesContext(boolean usesContext) { - this.usesContext = usesContext; - } - - // static boolean freeExecutable() { - // Set keys = Globals.loadedExecutables.keySet(); - // synchronized(Globals.loadedExecutables) { - // Iterator it = keys.iterator(); - // if (it.hasNext()) { - // Globals.loadedExecutables.remove(it.next()); - // return true; - // } - // } - // return false; - // } - // - // public XsltExecutable loadExecutable() throws SaxonApiException { - // String key = getId(); - // XsltExecutable executable = Globals.loadedExecutables.get(key); - // while (executable == null) { - // try { - // // System.out.println(template.getTemplateFile().getAbsolutePath()); - // Source source = new StreamSource(getTemplateFile()); - // executable = Globals.compiler.compile(source); - // Globals.loadedExecutables.put(key, executable); - // } catch (OutOfMemoryError e) { - // boolean freed = freeExecutable(); - // if (!freed) { - // throw e; - // } - // } - // } - // - // Runtime rt = Runtime.getRuntime(); - // while (rt.totalMemory() - rt.freeMemory() > Globals.memThreshhold) { - // boolean freed = freeExecutable(); - // if (!freed) { - // break; - // } - // } - // - // return executable; - // } - -} +package com.occamlab.te.index; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +public class TemplateEntry extends IndexEntry { + + File templateFile = null; + + boolean usesContext; + + List params = null; + + TemplateEntry() { + super(); + } + + TemplateEntry(Element template) { + super(template); + try { + String file = template.getAttribute("file"); + if (file != null && file.length() > 0) { + setTemplateFile(new File(new URI(template.getAttribute("file")))); + } + NodeList nl = template.getElementsByTagName("param"); + params = new ArrayList<>(); + for (int i = 0; i < nl.getLength(); i++) { + Element el = (Element) nl.item(i); + String prefix = el.getAttribute("prefix"); + String namespaceUri = el.getAttribute("namespace-uri"); + String localName = el.getAttribute("local-name"); + params.add(new QName(namespaceUri, localName, prefix)); + } + setUsesContext(Boolean.parseBoolean(template.getAttribute("uses-context"))); + } + catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + // public void persistAttributes(PrintWriter out) { + // super.persistAttributes(out); + // try { + // out.print(" file=\"" + templateFile.toURI().toURL().toString() + "\"" + // + " uses-context=\"" + Boolean.toString(usesContext) + "\""); + // } catch (MalformedURLException e) { + // throw new RuntimeException(e); + // } + // } + // + // public void persistTags(PrintWriter out) { + // super.persistTags(out); + // for (QName qname : params) { + // out.println(""); + // } + // } + + public File getTemplateFile() { + return templateFile; + } + + public void setTemplateFile(File templateFile) { + this.templateFile = templateFile; + } + + public List getParams() { + return params; + } + + public void setParams(List params) { + this.params = params; + } + + public boolean usesContext() { + return usesContext; + } + + public void setUsesContext(boolean usesContext) { + this.usesContext = usesContext; + } + + // static boolean freeExecutable() { + // Set keys = Globals.loadedExecutables.keySet(); + // synchronized(Globals.loadedExecutables) { + // Iterator it = keys.iterator(); + // if (it.hasNext()) { + // Globals.loadedExecutables.remove(it.next()); + // return true; + // } + // } + // return false; + // } + // + // public XsltExecutable loadExecutable() throws SaxonApiException { + // String key = getId(); + // XsltExecutable executable = Globals.loadedExecutables.get(key); + // while (executable == null) { + // try { + // // System.out.println(template.getTemplateFile().getAbsolutePath()); + // Source source = new StreamSource(getTemplateFile()); + // executable = Globals.compiler.compile(source); + // Globals.loadedExecutables.put(key, executable); + // } catch (OutOfMemoryError e) { + // boolean freed = freeExecutable(); + // if (!freed) { + // throw e; + // } + // } + // } + // + // Runtime rt = Runtime.getRuntime(); + // while (rt.totalMemory() - rt.freeMemory() > Globals.memThreshhold) { + // boolean freed = freeExecutable(); + // if (!freed) { + // break; + // } + // } + // + // return executable; + // } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/index/TemplateEntryInterface.java b/teamengine-core/src/main/java/com/occamlab/te/index/TemplateEntryInterface.java index d2eae62a2..06d1cb463 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/index/TemplateEntryInterface.java +++ b/teamengine-core/src/main/java/com/occamlab/te/index/TemplateEntryInterface.java @@ -1,22 +1,42 @@ -package com.occamlab.te.index; - -import java.io.File; -import java.util.List; - -import javax.xml.namespace.QName; - -public interface TemplateEntryInterface extends NamedEntry { - - File getTemplateFile(); - - void setTemplateFile(File templateFile); - - List getParams(); - - void setParams(List params); - - boolean usesContext(); - - void setUsesContext(boolean usesContext); - -} +package com.occamlab.te.index; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.util.List; + +import javax.xml.namespace.QName; + +public interface TemplateEntryInterface extends NamedEntry { + + File getTemplateFile(); + + void setTemplateFile(File templateFile); + + List getParams(); + + void setParams(List params); + + boolean usesContext(); + + void setUsesContext(boolean usesContext); + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/index/TestEntry.java b/teamengine-core/src/main/java/com/occamlab/te/index/TestEntry.java index 0fd0dd2cf..c73109d6a 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/index/TestEntry.java +++ b/teamengine-core/src/main/java/com/occamlab/te/index/TestEntry.java @@ -1,106 +1,126 @@ -package com.occamlab.te.index; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.w3c.dom.Element; - -import com.occamlab.te.TECore; - -/** - * Describes a test in a test suite. It corresponds to a <test> element in an index - * file. - */ -public class TestEntry extends TemplateEntry { - - private static final Logger LOGR = Logger.getLogger(TestEntry.class.getName()); - - private int defaultResult = TECore.PASS; - - private int result = TECore.PASS; - - private String context; - - private String type; - - private String assertion; - - private boolean isConformanceClass; - - private boolean isBasic; - - public TestEntry() { - super(); - } - - TestEntry(Element test) { - super(test); - if (usesContext()) { - setContext(test.getElementsByTagName("context").item(0).getTextContent()); - } - setType(test.getElementsByTagName("type").item(0).getTextContent()); - setAssertion(test.getElementsByTagName("assertion").item(0).getTextContent()); - String defaultResultName = test.getElementsByTagName("defaultResult").item(0).getTextContent(); - setDefaultResult(defaultResultName.equals("BestPractice") ? TECore.BEST_PRACTICE : TECore.PASS); - setResult(getDefaultResult()); - - this.isConformanceClass = Boolean.parseBoolean(test.getAttribute("isConformanceClass")); - this.isBasic = Boolean.parseBoolean(test.getAttribute("isBasic")); - } - - public boolean isConformanceClass() { - return isConformanceClass; - } - - public boolean isBasic() { - return isBasic; - } - - public int getDefaultResult() { - return defaultResult; - } - - public void setDefaultResult(int defaultResult) { - this.defaultResult = defaultResult; - } - - public int getResult() { - return result; - } - - public void setResult(int result) { - if (LOGR.isLoggable(Level.FINE)) { - LOGR.fine(String.format("Setting test result for %s: %d", getQName(), result)); - } - this.result = result; - } - - public String getContext() { - return context; - } - - public void setContext(String context) { - this.context = context; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getAssertion() { - return assertion; - } - - public void setAssertion(String assertion) { - this.assertion = assertion; - } - - public String toString() { - return super.toString() + "[result=" + this.result + "]"; - } - -} +package com.occamlab.te.index; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.w3c.dom.Element; + +import com.occamlab.te.TECore; + +/** + * Describes a test in a test suite. It corresponds to a <test> element in an index + * file. + */ +public class TestEntry extends TemplateEntry { + + private static final Logger LOGR = Logger.getLogger(TestEntry.class.getName()); + + private int defaultResult = TECore.PASS; + + private int result = TECore.PASS; + + private String context; + + private String type; + + private String assertion; + + private boolean isConformanceClass; + + private boolean isBasic; + + public TestEntry() { + super(); + } + + TestEntry(Element test) { + super(test); + if (usesContext()) { + setContext(test.getElementsByTagName("context").item(0).getTextContent()); + } + setType(test.getElementsByTagName("type").item(0).getTextContent()); + setAssertion(test.getElementsByTagName("assertion").item(0).getTextContent()); + String defaultResultName = test.getElementsByTagName("defaultResult").item(0).getTextContent(); + setDefaultResult(defaultResultName.equals("BestPractice") ? TECore.BEST_PRACTICE : TECore.PASS); + setResult(getDefaultResult()); + + this.isConformanceClass = Boolean.parseBoolean(test.getAttribute("isConformanceClass")); + this.isBasic = Boolean.parseBoolean(test.getAttribute("isBasic")); + } + + public boolean isConformanceClass() { + return isConformanceClass; + } + + public boolean isBasic() { + return isBasic; + } + + public int getDefaultResult() { + return defaultResult; + } + + public void setDefaultResult(int defaultResult) { + this.defaultResult = defaultResult; + } + + public int getResult() { + return result; + } + + public void setResult(int result) { + if (LOGR.isLoggable(Level.FINE)) { + LOGR.fine(String.format("Setting test result for %s: %d", getQName(), result)); + } + this.result = result; + } + + public String getContext() { + return context; + } + + public void setContext(String context) { + this.context = context; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getAssertion() { + return assertion; + } + + public void setAssertion(String assertion) { + this.assertion = assertion; + } + + public String toString() { + return super.toString() + "[result=" + this.result + "]"; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/BinaryPayloadParser.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/BinaryPayloadParser.java index 78d5c0d1d..0ea9d5811 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/BinaryPayloadParser.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/BinaryPayloadParser.java @@ -1,42 +1,62 @@ -/** - * ************************************************************************** - * - * Contributor(s): - * C. Heazel (WiSC): Added Fortify adjudication changes - * - *************************************************************************** - */ -package com.occamlab.te.parsers; - -import java.io.PrintWriter; -import java.net.URLConnection; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.XMLConstants; // Addition for Fortify modifications - -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -public class BinaryPayloadParser { - - public Document parse(URLConnection uc, Element instruction, PrintWriter logger) throws Exception { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - // Fortify Mod: prevent external entity injection - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.newDocument(); - Element root = doc.createElement("payload"); - - // Fortify Mod: prevent external entity injection - TransformerFactory tf = TransformerFactory.newInstance(); - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer t = tf.newTransformer(); - // Transformer t = TransformerFactory.newInstance().newTransformer(); - - return doc; - } - -} +/** + * ************************************************************************** + * + * Contributor(s): + * C. Heazel (WiSC): Added Fortify adjudication changes + * + *************************************************************************** + */ +package com.occamlab.te.parsers; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.PrintWriter; +import java.net.URLConnection; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.XMLConstants; // Addition for Fortify modifications + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +public class BinaryPayloadParser { + + public Document parse(URLConnection uc, Element instruction, PrintWriter logger) throws Exception { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + // Fortify Mod: prevent external entity injection + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.newDocument(); + Element root = doc.createElement("payload"); + + // Fortify Mod: prevent external entity injection + TransformerFactory tf = TransformerFactory.newInstance(); + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer t = tf.newTransformer(); + // Transformer t = TransformerFactory.newInstance().newTransformer(); + + return doc; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/CDataParser.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/CDataParser.java index 655b7b022..daacedae4 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/CDataParser.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/CDataParser.java @@ -1,52 +1,72 @@ -/**************************************************************************** - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): - C. Heazel (WiSC) Fortify modifications - - ****************************************************************************/ -package com.occamlab.te.parsers; - -import java.io.InputStream; -import java.io.PrintWriter; - -import java.net.URLConnection; - -import org.w3c.dom.Element; - -/** - * Reads a response message and produces a String representation of its content. - * - */ -public class CDataParser { - - public static String parse(URLConnection uc, Element instruction, PrintWriter logger) throws Exception { - // Fortify Mod: manage the input stream as a local variable so that it can be - // closed. - // return parse(uc.getInputStream(), instruction, logger); - InputStream is = uc.getInputStream(); - String s = parse(is, instruction, logger); - is.close(); - return s; - } - - private static String parse(InputStream is, Element instruction, PrintWriter logger) throws Exception { - byte[] buf = new byte[1024]; - int numread = is.read(buf); - String s = new String(buf, 0, numread); - while (numread >= 0) { - numread = is.read(buf); - if (numread > 0) { - s += new String(buf, 0, numread); - } - } - return s; - } - -} +/**************************************************************************** + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): + C. Heazel (WiSC) Fortify modifications + + ****************************************************************************/ +package com.occamlab.te.parsers; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.InputStream; +import java.io.PrintWriter; + +import java.net.URLConnection; + +import org.w3c.dom.Element; + +/** + * Reads a response message and produces a String representation of its content. + * + */ +public class CDataParser { + + public static String parse(URLConnection uc, Element instruction, PrintWriter logger) throws Exception { + // Fortify Mod: manage the input stream as a local variable so that it can be + // closed. + // return parse(uc.getInputStream(), instruction, logger); + InputStream is = uc.getInputStream(); + String s = parse(is, instruction, logger); + is.close(); + return s; + } + + private static String parse(InputStream is, Element instruction, PrintWriter logger) throws Exception { + byte[] buf = new byte[1024]; + int numread = is.read(buf); + String s = new String(buf, 0, numread); + while (numread >= 0) { + numread = is.read(buf); + if (numread > 0) { + s += new String(buf, 0, numread); + } + } + return s; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/HTTPParser.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/HTTPParser.java index 4a4b2e9da..e9c1781f7 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/HTTPParser.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/HTTPParser.java @@ -1,320 +1,340 @@ -/**************************************************************************** - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): - C. Heazel (WiSC): Added Fortify adjudication changes - - ****************************************************************************/ -package com.occamlab.te.parsers; - -import java.io.BufferedReader; -import java.io.File; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.io.RandomAccessFile; -import java.io.Reader; -import java.net.URLConnection; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.net.ssl.SSLProtocolException; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMResult; -import javax.xml.transform.dom.DOMSource; -import javax.xml.XMLConstants; // Addition for Fortify modifications - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import com.occamlab.te.TECore; -import com.occamlab.te.util.DomUtils; -import com.occamlab.te.util.URLConnectionUtils; - -/** - * Parses an HTTP response message and produces a DOM Document containing the message - * content. - * - * HTTPParser returns HTTP status and header information. It uses other parser(s) to parse - * the content; TECore by default if others are not specified. It supports multipart - * messages. It returns a DOM Document representation of the message status, headers, and - * content. - */ -public class HTTPParser { - - private static final Logger LOGR = Logger.getLogger(HTTPParser.class.getName()); - - public static final String PARSERS_NS = "http://www.occamlab.com/te/parsers"; - - public static final String EOS_ERR = "Error in multipart stream. End of stream reached and with no closing boundary delimiter line"; - - private static void append_headers(URLConnection uc, Element e) { - Document doc = e.getOwnerDocument(); - Element headers = doc.createElement("headers"); - e.appendChild(headers); - - for (int i = 0;; i++) { - String headerKey = uc.getHeaderFieldKey(i); - String headerValue = uc.getHeaderField(i); - if (headerKey == null) { - if (headerValue == null) - break; - } - else { - Element header = doc.createElement("header"); - headers.appendChild(header); - header.setAttribute("name", headerKey); - header.appendChild(doc.createTextNode(headerValue)); - } - } - if (LOGR.isLoggable(Level.FINER)) { - LOGR.finer(DomUtils.serializeNode(e)); - } - } - - /** - * Selects a parser for a message part based on the part number and MIME format type, - * if supplied in instructions. - * @param partnum An integer indicating the message part number. - * @param mime A MIME media type. - * @param instruction An Element representing parser instructions. - * @return A Node containing parser info, or {@code null} if no matching parser is - * found. - */ - static Node select_parser(int partnum, String mime, Element instruction) { - if (null == instruction) - return null; - NodeList instructions = instruction.getElementsByTagNameNS(PARSERS_NS, "parse"); - Node parserNode = null; - instructionsLoop: for (int i = 0; i < instructions.getLength(); i++) { - Element parse = (Element) instructions.item(i); - if (partnum != 0) { - String part_i = parse.getAttribute("part"); - if (part_i.length() > 0) { - int n = Integer.parseInt(part_i); - if (n != partnum) { - continue; - } - } - } - if (mime != null) { - String mime_i = parse.getAttribute("mime"); - if (mime_i.length() > 0) { - String[] mime_parts = mime_i.split(";\\s*"); - if (!mime.startsWith(mime_parts[0])) { - continue; - } - boolean ok = true; - for (int j = 1; j < mime_parts.length; j++) { - if (mime.indexOf(mime_parts[j]) < 0) { - ok = false; - break; - } - } - if (!ok) { - continue; - } - } - } - NodeList children = parse.getChildNodes(); - for (int j = 0; j < children.getLength(); j++) { - if (children.item(j).getNodeType() == Node.ELEMENT_NODE) { - parserNode = children.item(j); - break instructionsLoop; - } - } - } - return parserNode; - } - - private static boolean queue_equals(int[] queue, int qPos, int qLen, int[] value) { - for (int i = 0; i < qLen; i++) { - if (queue[(i + qPos) % qLen] != value[i]) { - return false; - } - } - return true; - } - - private static File create_part_file(Reader in, String boundary) throws Exception { - File temp = File.createTempFile("$te_", ".tmp"); - RandomAccessFile raf = new RandomAccessFile(temp, "rw"); - int qLen = boundary.length() + 2; - int[] boundary_queue = new int[qLen]; - boundary_queue[0] = '-'; - boundary_queue[1] = '-'; - for (int i = 0; i < boundary.length(); i++) { - boundary_queue[i + 2] = boundary.charAt(i); - } - int[] queue = new int[qLen]; - for (int i = 0; i < qLen; i++) { - queue[i] = in.read(); - if (queue[i] == -1) { - break; - } - } - int qPos = 0; - try { - while (!queue_equals(queue, qPos, qLen, boundary_queue)) { - raf.write(queue[qPos]); - queue[qPos] = in.read(); - if (queue[qPos] == -1) { - // Fortify Mod: Clean up the file first, then throw the exception. - raf.close(); - throw new Exception(EOS_ERR); - } - qPos = (qPos + 1) % qLen; - } - } - finally { - raf.close(); - } - return temp; - } - - /** - * Invocation point: Method called by TECore for request or soap-request. - * - * {@code } - */ - public static Document parse(URLConnection uc, Element instruction, PrintWriter logger, TECore core) - throws Throwable { - try { - uc.connect(); - } - catch (SSLProtocolException sslep) { - throw new SSLProtocolException( - "[SSL ERROR] Failed to connect with the requested URL due to \"Invalid server_name\" found!! :" - + uc.getURL() + ":" + sslep.getClass() + " : " + sslep.getMessage()); - } - String mime = uc.getContentType(); - boolean multipart = (mime != null && mime.startsWith("multipart")); - - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - // Fortify Mod: prevent external entity injection - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.newDocument(); - Element root = doc.createElement(multipart ? "multipart-response" : "response"); - if (uc.getHeaderFieldKey(0) == null) { - Element status = doc.createElement("status"); - String status_line = uc.getHeaderField(0); - if (status_line != null) { - String[] status_array = status_line.split("\\s"); - if (status_array.length > 0) { - status.setAttribute("protocol", status_array[0]); - } - if (status_array.length > 1) { - status.setAttribute("code", status_array[1]); - } - if (status_array.length > 2) { - StringBuilder sb = new StringBuilder(); - for (int i = 2; i < status_array.length; i++) { - sb.append(status_array[i]); - sb.append(" "); - } - status.appendChild(doc.createTextNode(sb.toString().trim())); - } - } - root.appendChild(status); - } - - append_headers(uc, root); - // Fortify Mod: prevent external entity injection - TransformerFactory tf = TransformerFactory.newInstance(); - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer t = tf.newTransformer(); - // Transformer t = TransformerFactory.newInstance().newTransformer(); - - if (multipart) { - String mime2 = mime + ";"; - int start = mime2.indexOf("boundary=") + 9; - char endchar = ';'; - if (mime2.charAt(start) == '"') { - start++; - endchar = '"'; - } - int end = mime2.indexOf(endchar, start); - String boundary = mime2.substring(start, end); - InputStream is = URLConnectionUtils.getInputStream(uc); - BufferedReader in = new BufferedReader(new InputStreamReader(is)); - File temp = create_part_file(in, boundary); - temp.delete(); - String line = in.readLine(); - int num = 1; - while (!line.endsWith("--")) { - String contentType = "text/plain"; - Element part = doc.createElement("part"); - part.setAttribute("num", Integer.toString(num)); - Element headers = doc.createElement("headers"); - line = in.readLine(); - while (line.length() > 0) { - Element header = doc.createElement("header"); - int colon = line.indexOf(":"); - String name = line.substring(0, colon); - String value = line.substring(colon + 1).trim(); - if (name.toLowerCase().equals("content-type")) { - contentType = value; - } - header.setAttribute("name", name); - header.appendChild(doc.createTextNode(value)); - headers.appendChild(header); - line = in.readLine(); - } - part.appendChild(headers); - temp = create_part_file(in, boundary); - URLConnection pc = temp.toURI().toURL().openConnection(); - pc.setRequestProperty("Content-type", mime); - Node parser = select_parser(num, contentType, instruction); - // use TECore to invoke any subsidiary (chained) parsers - Element response_e = core.parse(pc, parser); - temp.delete(); - Element parser_e = (Element) (response_e.getElementsByTagName("parser").item(0)); - if (parser_e != null) { - logger.print(parser_e.getTextContent()); - } - Element content = (Element) (response_e.getElementsByTagName("content").item(0)); - if ((null != content) && content.hasChildNodes()) { - t.transform(new DOMSource(content), new DOMResult(part)); - } - root.appendChild(part); - line = in.readLine(); - num++; - } - // Fortify Mod: Close the BufferedReader and release its resources - in.close(); - } - else { - Node parser = select_parser(0, uc.getContentType(), instruction); - // use TECore to invoke any chained (subsidiary) parsers - if (LOGR.isLoggable(Level.FINER)) { - String msg = String.format("Calling subsidiary parser for resource at %s:%n%s", uc.getURL(), - DomUtils.serializeNode(parser)); - LOGR.finer(msg); - } - Element response_e = core.parse(uc, parser); - Element parser_e = (Element) (response_e.getElementsByTagName("parser").item(0)); - if (parser_e != null) { - logger.print(parser_e.getTextContent()); - } - Element content = (Element) (response_e.getElementsByTagName("content").item(0)); - if (null != content) { - root.appendChild(doc.importNode(content, true)); - } - } - doc.appendChild(root); - return doc; - } - -} +/**************************************************************************** + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): + C. Heazel (WiSC): Added Fortify adjudication changes + + ****************************************************************************/ +package com.occamlab.te.parsers; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.RandomAccessFile; +import java.io.Reader; +import java.net.URLConnection; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.SSLProtocolException; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.XMLConstants; // Addition for Fortify modifications + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.occamlab.te.TECore; +import com.occamlab.te.util.DomUtils; +import com.occamlab.te.util.URLConnectionUtils; + +/** + * Parses an HTTP response message and produces a DOM Document containing the message + * content. + * + * HTTPParser returns HTTP status and header information. It uses other parser(s) to parse + * the content; TECore by default if others are not specified. It supports multipart + * messages. It returns a DOM Document representation of the message status, headers, and + * content. + */ +public class HTTPParser { + + private static final Logger LOGR = Logger.getLogger(HTTPParser.class.getName()); + + public static final String PARSERS_NS = "http://www.occamlab.com/te/parsers"; + + public static final String EOS_ERR = "Error in multipart stream. End of stream reached and with no closing boundary delimiter line"; + + private static void append_headers(URLConnection uc, Element e) { + Document doc = e.getOwnerDocument(); + Element headers = doc.createElement("headers"); + e.appendChild(headers); + + for (int i = 0;; i++) { + String headerKey = uc.getHeaderFieldKey(i); + String headerValue = uc.getHeaderField(i); + if (headerKey == null) { + if (headerValue == null) + break; + } + else { + Element header = doc.createElement("header"); + headers.appendChild(header); + header.setAttribute("name", headerKey); + header.appendChild(doc.createTextNode(headerValue)); + } + } + if (LOGR.isLoggable(Level.FINER)) { + LOGR.finer(DomUtils.serializeNode(e)); + } + } + + /** + * Selects a parser for a message part based on the part number and MIME format type, + * if supplied in instructions. + * @param partnum An integer indicating the message part number. + * @param mime A MIME media type. + * @param instruction An Element representing parser instructions. + * @return A Node containing parser info, or {@code null} if no matching parser is + * found. + */ + static Node select_parser(int partnum, String mime, Element instruction) { + if (null == instruction) + return null; + NodeList instructions = instruction.getElementsByTagNameNS(PARSERS_NS, "parse"); + Node parserNode = null; + instructionsLoop: for (int i = 0; i < instructions.getLength(); i++) { + Element parse = (Element) instructions.item(i); + if (partnum != 0) { + String part_i = parse.getAttribute("part"); + if (part_i.length() > 0) { + int n = Integer.parseInt(part_i); + if (n != partnum) { + continue; + } + } + } + if (mime != null) { + String mime_i = parse.getAttribute("mime"); + if (mime_i.length() > 0) { + String[] mime_parts = mime_i.split(";\\s*"); + if (!mime.startsWith(mime_parts[0])) { + continue; + } + boolean ok = true; + for (int j = 1; j < mime_parts.length; j++) { + if (mime.indexOf(mime_parts[j]) < 0) { + ok = false; + break; + } + } + if (!ok) { + continue; + } + } + } + NodeList children = parse.getChildNodes(); + for (int j = 0; j < children.getLength(); j++) { + if (children.item(j).getNodeType() == Node.ELEMENT_NODE) { + parserNode = children.item(j); + break instructionsLoop; + } + } + } + return parserNode; + } + + private static boolean queue_equals(int[] queue, int qPos, int qLen, int[] value) { + for (int i = 0; i < qLen; i++) { + if (queue[(i + qPos) % qLen] != value[i]) { + return false; + } + } + return true; + } + + private static File create_part_file(Reader in, String boundary) throws Exception { + File temp = File.createTempFile("$te_", ".tmp"); + RandomAccessFile raf = new RandomAccessFile(temp, "rw"); + int qLen = boundary.length() + 2; + int[] boundary_queue = new int[qLen]; + boundary_queue[0] = '-'; + boundary_queue[1] = '-'; + for (int i = 0; i < boundary.length(); i++) { + boundary_queue[i + 2] = boundary.charAt(i); + } + int[] queue = new int[qLen]; + for (int i = 0; i < qLen; i++) { + queue[i] = in.read(); + if (queue[i] == -1) { + break; + } + } + int qPos = 0; + try { + while (!queue_equals(queue, qPos, qLen, boundary_queue)) { + raf.write(queue[qPos]); + queue[qPos] = in.read(); + if (queue[qPos] == -1) { + // Fortify Mod: Clean up the file first, then throw the exception. + raf.close(); + throw new Exception(EOS_ERR); + } + qPos = (qPos + 1) % qLen; + } + } + finally { + raf.close(); + } + return temp; + } + + /** + * Invocation point: Method called by TECore for request or soap-request. + * + * {@code } + */ + public static Document parse(URLConnection uc, Element instruction, PrintWriter logger, TECore core) + throws Throwable { + try { + uc.connect(); + } + catch (SSLProtocolException sslep) { + throw new SSLProtocolException( + "[SSL ERROR] Failed to connect with the requested URL due to \"Invalid server_name\" found!! :" + + uc.getURL() + ":" + sslep.getClass() + " : " + sslep.getMessage()); + } + String mime = uc.getContentType(); + boolean multipart = (mime != null && mime.startsWith("multipart")); + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + // Fortify Mod: prevent external entity injection + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.newDocument(); + Element root = doc.createElement(multipart ? "multipart-response" : "response"); + if (uc.getHeaderFieldKey(0) == null) { + Element status = doc.createElement("status"); + String status_line = uc.getHeaderField(0); + if (status_line != null) { + String[] status_array = status_line.split("\\s"); + if (status_array.length > 0) { + status.setAttribute("protocol", status_array[0]); + } + if (status_array.length > 1) { + status.setAttribute("code", status_array[1]); + } + if (status_array.length > 2) { + StringBuilder sb = new StringBuilder(); + for (int i = 2; i < status_array.length; i++) { + sb.append(status_array[i]); + sb.append(" "); + } + status.appendChild(doc.createTextNode(sb.toString().trim())); + } + } + root.appendChild(status); + } + + append_headers(uc, root); + // Fortify Mod: prevent external entity injection + TransformerFactory tf = TransformerFactory.newInstance(); + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer t = tf.newTransformer(); + // Transformer t = TransformerFactory.newInstance().newTransformer(); + + if (multipart) { + String mime2 = mime + ";"; + int start = mime2.indexOf("boundary=") + 9; + char endchar = ';'; + if (mime2.charAt(start) == '"') { + start++; + endchar = '"'; + } + int end = mime2.indexOf(endchar, start); + String boundary = mime2.substring(start, end); + InputStream is = URLConnectionUtils.getInputStream(uc); + BufferedReader in = new BufferedReader(new InputStreamReader(is)); + File temp = create_part_file(in, boundary); + temp.delete(); + String line = in.readLine(); + int num = 1; + while (!line.endsWith("--")) { + String contentType = "text/plain"; + Element part = doc.createElement("part"); + part.setAttribute("num", Integer.toString(num)); + Element headers = doc.createElement("headers"); + line = in.readLine(); + while (line.length() > 0) { + Element header = doc.createElement("header"); + int colon = line.indexOf(":"); + String name = line.substring(0, colon); + String value = line.substring(colon + 1).trim(); + if (name.toLowerCase().equals("content-type")) { + contentType = value; + } + header.setAttribute("name", name); + header.appendChild(doc.createTextNode(value)); + headers.appendChild(header); + line = in.readLine(); + } + part.appendChild(headers); + temp = create_part_file(in, boundary); + URLConnection pc = temp.toURI().toURL().openConnection(); + pc.setRequestProperty("Content-type", mime); + Node parser = select_parser(num, contentType, instruction); + // use TECore to invoke any subsidiary (chained) parsers + Element response_e = core.parse(pc, parser); + temp.delete(); + Element parser_e = (Element) (response_e.getElementsByTagName("parser").item(0)); + if (parser_e != null) { + logger.print(parser_e.getTextContent()); + } + Element content = (Element) (response_e.getElementsByTagName("content").item(0)); + if ((null != content) && content.hasChildNodes()) { + t.transform(new DOMSource(content), new DOMResult(part)); + } + root.appendChild(part); + line = in.readLine(); + num++; + } + // Fortify Mod: Close the BufferedReader and release its resources + in.close(); + } + else { + Node parser = select_parser(0, uc.getContentType(), instruction); + // use TECore to invoke any chained (subsidiary) parsers + if (LOGR.isLoggable(Level.FINER)) { + String msg = String.format("Calling subsidiary parser for resource at %s:%n%s", uc.getURL(), + DomUtils.serializeNode(parser)); + LOGR.finer(msg); + } + Element response_e = core.parse(uc, parser); + Element parser_e = (Element) (response_e.getElementsByTagName("parser").item(0)); + if (parser_e != null) { + logger.print(parser_e.getTextContent()); + } + Element content = (Element) (response_e.getElementsByTagName("content").item(0)); + if (null != content) { + root.appendChild(doc.importNode(content, true)); + } + } + doc.appendChild(root); + return doc; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/ImageParser.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/ImageParser.java index c38b96680..348ce1e6c 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/ImageParser.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/ImageParser.java @@ -19,6 +19,26 @@ Paul Daisey (Image Matters LLC) ****************************************************************************/ package com.occamlab.te.parsers; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/NullParser.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/NullParser.java index 95d2a916a..d41f7ec4b 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/NullParser.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/NullParser.java @@ -1,31 +1,51 @@ -/**************************************************************************** - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): No additional contributors to date - - ****************************************************************************/ -package com.occamlab.te.parsers; - -import java.net.URLConnection; -import java.io.PrintWriter; - -import org.w3c.dom.Element; - -/** - * Ignores the request information and returns null. This request parser may - * be used to skip a request for some reason. - * - */ -public class NullParser { - - public static String parse(URLConnection uc, Element instruction, PrintWriter logger) throws Exception { - return null; - } - -} +/**************************************************************************** + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): No additional contributors to date + + ****************************************************************************/ +package com.occamlab.te.parsers; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.net.URLConnection; +import java.io.PrintWriter; + +import org.w3c.dom.Element; + +/** + * Ignores the request information and returns null. This request parser may + * be used to skip a request for some reason. + * + */ +public class NullParser { + + public static String parse(URLConnection uc, Element instruction, PrintWriter logger) throws Exception { + return null; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/SchematronValidatingParser.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/SchematronValidatingParser.java index 4f0ea52b0..aaa686a8a 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/SchematronValidatingParser.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/SchematronValidatingParser.java @@ -1,433 +1,453 @@ -/** - * ************************************************************************** - * - * Contributor(s): - * C. Heazel (WiSC): Added Fortify adjudication changes - * - *************************************************************************** - */ - -package com.occamlab.te.parsers; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.io.PrintWriter; -import java.net.URL; -import java.net.URLConnection; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import javax.xml.XMLConstants; // Addition for Fortify modifications - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.ErrorHandler; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -import com.occamlab.te.ErrorHandlerImpl; -import com.thaiopensource.util.PropertyMap; -import com.thaiopensource.util.PropertyMapBuilder; -import com.thaiopensource.validate.SchemaReader; -import com.thaiopensource.validate.SchemaReaderLoader; -import com.thaiopensource.validate.ValidateProperty; -import com.thaiopensource.validate.ValidationDriver; -import com.thaiopensource.validate.prop.schematron.SchematronProperty; - -/** - * Validates the given XML resource against the rules specified in a Schematron (v1.5) - * file. Used in conjunction with standard XML Schema validator to provide more thorough - * validation coverage. - * - * Diagnostic messages will be included if any are defined. - * - */ -public class SchematronValidatingParser { - - private static final Logger LOGR = Logger.getLogger(SchematronValidatingParser.class.getName()); - - private PropertyMapBuilder configPropBuilder = null; - - private String schemaLocation = null; - - private File schemaFile = null; - - private String phase = null; - - private String type = null; - - private PrintWriter outputLogger = null; - - /** Namespace URI for the Schematron assertion language (v 1.5). */ - public static final String SCHEMATRON_NS_URI = "http://www.ascc.net/xml/schematron"; - - /** Default constructor required for init */ - public SchematronValidatingParser() { - } - - /** Overloaded constructor required for init */ - public SchematronValidatingParser(Document schema_link) throws Exception { - getFileType(schema_link.getDocumentElement()); - } - - /** - * Parses the parser element to get the schematron file location and type of resource - * (from ctl file). - * @param schema_links Gets the location of the schema (and type of resource) and - * saves to global parameter - * @return The type of resource (URL, File, Resource) - */ - public String getFileType(Element schema_links) throws Exception { - Document d = schema_links.getOwnerDocument(); - NodeList nodes = d.getElementsByTagNameNS("http://www.occamlab.com/te/parsers", "schema"); - String localType = null; - for (int i = 0; i < nodes.getLength(); i++) { - Element e = (Element) nodes.item(i); - localType = e.getAttribute("type"); - this.type = e.getAttribute("type"); - this.phase = e.getAttribute("phase"); - this.schemaLocation = e.getTextContent().trim(); - } - return localType; - } - - /** - * Converts an org.w3c.dom.Document element to an java.io.InputStream. - * @param edoc The org.w3c.dom.Document to be converted - * @return The InputStream value of the passed doument - */ - public InputStream DocumentToInputStream(org.w3c.dom.Document edoc) throws IOException { - - final org.w3c.dom.Document doc = edoc; - final PipedOutputStream pos = new PipedOutputStream(); - PipedInputStream pis = new PipedInputStream(); - pis.connect(pos); - - (new Thread(new Runnable() { - - public void run() { - // Use the Transformer.transform() method to save the Document - // to a StreamResult - try { - TransformerFactory tFactory = TransformerFactory.newInstance(); - // Fortify Mod: prevent external entity injection - tFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer transformer = tFactory.newTransformer(); - transformer.setOutputProperty("encoding", "ISO-8859-1"); - transformer.setOutputProperty("indent", "yes"); - transformer.transform(new DOMSource(doc), new StreamResult(pos)); - } - catch (Exception _ex) { - throw new RuntimeException("Failed to tranform org.w3c.dom.Document to PipedOutputStream", _ex); - } - finally { - try { - pos.close(); - } - catch (IOException e) { - - } - } - } - }, "MyClassName.convert(org.w3c.dom.Document edoc)")).start(); - - return pis; - } - - /** - * Checks the given schematron phase for the XML file and returns the validation - * status. - * @param doc The XML file to validate (Document) - * @param schemaFile The string path to the schematron file to use - * @param phase The string phase name (contained in schematron file) - * @return Whether there were validation errors or not (boolean) - */ - public boolean checkSchematronRules(Document doc, String schemaFile, String phase) throws Exception { - - boolean isValid = false; - - if (doc == null || doc.getDocumentElement() == null) - return isValid; - try { - ClassLoader loader = this.getClass().getClassLoader(); - URL url = loader.getResource(schemaFile); - this.schemaFile = new File(URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8)); - } - catch (Exception e) { - assert false : "Entity body not found. " + e.toString(); - } - this.phase = phase; - Document returnDoc = parse(doc, null, null); - if (returnDoc != null) { - isValid = true; - } - return isValid; - } - - /** - * Checks the given schematron phase for the XML file and returns the validation - * status (takes schematron file, not string location). New and ADVANCED! (team engine - * can't work with overloaded methods :P) - * @param inputDoc The XML file to validate (Document) - * @param schemaFile The file object of the schematron file to validate with - * @param phase The string phase name (contained in schematron file) - * @return Whether there were validation errors or not (boolean) - */ - public boolean checkSchematronRulesAdv(InputSource inputDoc, File schemaFile, String phase) throws Exception { - - boolean isValid = false; - if (inputDoc == null) - return isValid; - this.schemaFile = schemaFile; - this.phase = phase; - - Document returnDoc = parse(inputDoc, null, null); - if (returnDoc != null) { - isValid = true; - } - return isValid; - } - - /** - * Runs the schematron file against the input source. - */ - public boolean executeSchematronDriver(InputSource inputDoc, File schemaFile, String phase) { - - boolean isValid = false; - ValidationDriver driver = createSchematronDriver(phase); - assert null != driver : "Unable to create Schematron ValidationDriver"; - InputSource is = null; - // Fortify Mod: move fis out so it can be closed on exit - FileInputStream fis = null; - try { - // FileInputStream fis = new FileInputStream(schemaFile); - fis = new FileInputStream(schemaFile); - is = new InputSource(fis); - } - catch (Exception e) { - e.printStackTrace(); - } - try { - if (driver.loadSchema(is)) { - isValid = driver.validate(inputDoc); - fis.close(); // Fortify addition - } - else { - assert false : ("Failed to load Schematron schema: " + schemaFile - + "\nIs the schema valid? Is the phase defined?"); - } - } - catch (SAXException e) { - assert false : e.toString(); - } - catch (IOException e) { - assert false : e.toString(); - } - return isValid; - } - - /** - * Sets up the schematron reader with all the necessary parameters. Calls - * initSchematronReader() to do further setup of the validation driver. - * @param phase The string phase name (contained in schematron file) - * @return The ValidationDriver to use in validating the XML document - */ - ValidationDriver createSchematronDriver(String phase) { - SchemaReaderLoader loader = new SchemaReaderLoader(); - SchemaReader schReader = loader.createSchemaReader(SCHEMATRON_NS_URI); - this.configPropBuilder = new PropertyMapBuilder(); - SchematronProperty.DIAGNOSE.add(this.configPropBuilder); - - if (this.outputLogger == null) { - this.outputLogger = new PrintWriter(System.out); - } - if (null != phase && !phase.isEmpty()) { - this.configPropBuilder.put(SchematronProperty.PHASE, phase); - } - ErrorHandler eh = new ErrorHandlerImpl("Schematron", outputLogger); - this.configPropBuilder.put(ValidateProperty.ERROR_HANDLER, eh); - return new ValidationDriver(this.configPropBuilder.toPropertyMap(), schReader); - } - - /** - * Parses and validates a resource obtained by dereferencing a URI. - * @param uc A URLConnection to access an XML resource. - * @param instruction An element containing parser instructions. - * @param logger The PrintWriter used for logging errors. - * @return A Document node if parsing succeeds, or {@code null} if it fails. - * @throws Exception - */ - public Document parse(URLConnection uc, Element instruction, PrintWriter logger) throws Exception { - return parse(uc.getInputStream(), instruction, logger); - } - - Document parse(InputStream is, Element instruction, PrintWriter logger) throws Exception { - - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - // Fortify Mod: Disable entity expansion to foil External Entity Injections - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = null; - try { - doc = db.parse(is); - } - catch (Exception e) { - logger.println(e.getMessage()); - } - return parse(doc, instruction, logger); - } - - Document parse(InputSource is, Element instruction, PrintWriter logger) throws Exception { - - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - // Fortify Mod: Disable entity expansion to foil External Entity Injections - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = null; - try { - doc = db.parse(is); - } - catch (Exception e) { - logger.println(e.getMessage()); - } - return parse(doc, instruction, logger); - } - - /** - * Checks the given Document against a Schematron schema. A schema reference is - * conveyed by a DOM Element node as indicated below. - * - *
-	 * {@code
-	 * 
-	 *   /class/path/schema1.sch
-	 * 
-	 * }
-	 * 
- * @param doc The document to be validated. - * @param instruction An Element containing schema information. - * @param logger A Writer used for logging error messages. - * @return The valid document, or {@code null} if any errors were detected. - * @throws Exception - */ - Document parse(Document doc, Element instruction, PrintWriter logger) throws Exception { - this.outputLogger = logger; - if (instruction != null) { - getFileType(instruction); - if (type.equals("url")) { - URL schemaURL = new URL(this.schemaLocation); - this.schemaFile = new File(schemaURL.toURI()); - } - else if (type.equals("file")) { - this.schemaFile = new File(this.schemaLocation); - } - else if (type.equals("resource")) { - URL url = this.getClass().getResource(this.schemaLocation); - this.schemaFile = new File(URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8)); - } - } - boolean isValid = false; - if (doc != null) { - InputSource xmlInputSource = null; - try { - InputStream inputStream = DocumentToInputStream(doc); - xmlInputSource = new InputSource(inputStream); - } - catch (IOException e) { - e.printStackTrace(); - } - isValid = executeSchematronDriver(xmlInputSource, this.schemaFile, this.phase); - } - if (!isValid) { - return null; - } - else { - return doc; - } - } - - /** - * Checks the content of an XML entity against the applicable rules defined in a - * Schematron schema. The designated phase identifies the active patterns (rule sets); - * if not specified, the default phase is executed. - * @param xmlEntity A DOM Document representing the XML entity to validate. - * @param schemaRef A (classpath) reference to a Schematron 1.5 schema. - * @param phase The phase to execute. - * @return A NodeList containing validation errors (it may be empty). - */ - public NodeList validate(Document xmlEntity, String schemaRef, String phase) { - - if (xmlEntity == null || xmlEntity.getDocumentElement() == null) - throw new IllegalArgumentException("No XML entity supplied (null)."); - InputSource xmlInputSource = null; - try { - InputStream inputStream = DocumentToInputStream(xmlEntity); - xmlInputSource = new InputSource(inputStream); - } - catch (IOException e) { - throw new RuntimeException(e); - } - PropertyMapBuilder builder = new PropertyMapBuilder(); - SchematronProperty.DIAGNOSE.add(builder); - if (null != phase && !phase.isEmpty()) { - builder.put(SchematronProperty.PHASE, phase); - } - XmlErrorHandler errHandler = new XmlErrorHandler(); - builder.put(ValidateProperty.ERROR_HANDLER, errHandler); - ValidationDriver driver = createDriver(builder.toPropertyMap()); - InputStream schStream = this.getClass().getResourceAsStream(schemaRef.trim()); - try { - InputSource input = new InputSource(schStream); - try { - boolean loaded = driver.loadSchema(input); - if (!loaded) { - throw new Exception("Failed to load schema at " + schemaRef.trim() - + "\nIs the schema valid? Is the phase defined?"); - } - } - finally { - schStream.close(); - } - driver.validate(xmlInputSource); - } - catch (Exception e) { - throw new RuntimeException("Schematron validation failed.", e); - } - NodeList errList = errHandler.toNodeList(); - if (LOGR.isLoggable(Level.FINER)) { - LOGR.finer(String.format("Found %d Schematron rule violation(s):%n %s", errList.getLength(), - errHandler.toString())); - } - return errList; - } - - /** - * Creates and initializes a ValidationDriver to perform Schematron validation. A - * schema must be loaded before an instance can be validated. - * @param configProps A PropertyMap containing properties to configure schema - * construction and validation behavior; it typically includes - * {@code SchematronProperty} and {@code ValidationProperty} items. - * @return A ValidationDriver that is ready to load a Schematron schema. - */ - ValidationDriver createDriver(PropertyMap configProps) { - SchemaReaderLoader loader = new SchemaReaderLoader(); - SchemaReader schReader = loader.createSchemaReader(SCHEMATRON_NS_URI); - return new ValidationDriver(configProps, schReader); - } - -} +/** + * ************************************************************************** + * + * Contributor(s): + * C. Heazel (WiSC): Added Fortify adjudication changes + * + *************************************************************************** + */ + +package com.occamlab.te.parsers; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.io.PrintWriter; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.XMLConstants; // Addition for Fortify modifications + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import com.occamlab.te.ErrorHandlerImpl; +import com.thaiopensource.util.PropertyMap; +import com.thaiopensource.util.PropertyMapBuilder; +import com.thaiopensource.validate.SchemaReader; +import com.thaiopensource.validate.SchemaReaderLoader; +import com.thaiopensource.validate.ValidateProperty; +import com.thaiopensource.validate.ValidationDriver; +import com.thaiopensource.validate.prop.schematron.SchematronProperty; + +/** + * Validates the given XML resource against the rules specified in a Schematron (v1.5) + * file. Used in conjunction with standard XML Schema validator to provide more thorough + * validation coverage. + * + * Diagnostic messages will be included if any are defined. + * + */ +public class SchematronValidatingParser { + + private static final Logger LOGR = Logger.getLogger(SchematronValidatingParser.class.getName()); + + private PropertyMapBuilder configPropBuilder = null; + + private String schemaLocation = null; + + private File schemaFile = null; + + private String phase = null; + + private String type = null; + + private PrintWriter outputLogger = null; + + /** Namespace URI for the Schematron assertion language (v 1.5). */ + public static final String SCHEMATRON_NS_URI = "http://www.ascc.net/xml/schematron"; + + /** Default constructor required for init */ + public SchematronValidatingParser() { + } + + /** Overloaded constructor required for init */ + public SchematronValidatingParser(Document schema_link) throws Exception { + getFileType(schema_link.getDocumentElement()); + } + + /** + * Parses the parser element to get the schematron file location and type of resource + * (from ctl file). + * @param schema_links Gets the location of the schema (and type of resource) and + * saves to global parameter + * @return The type of resource (URL, File, Resource) + */ + public String getFileType(Element schema_links) throws Exception { + Document d = schema_links.getOwnerDocument(); + NodeList nodes = d.getElementsByTagNameNS("http://www.occamlab.com/te/parsers", "schema"); + String localType = null; + for (int i = 0; i < nodes.getLength(); i++) { + Element e = (Element) nodes.item(i); + localType = e.getAttribute("type"); + this.type = e.getAttribute("type"); + this.phase = e.getAttribute("phase"); + this.schemaLocation = e.getTextContent().trim(); + } + return localType; + } + + /** + * Converts an org.w3c.dom.Document element to an java.io.InputStream. + * @param edoc The org.w3c.dom.Document to be converted + * @return The InputStream value of the passed doument + */ + public InputStream DocumentToInputStream(org.w3c.dom.Document edoc) throws IOException { + + final org.w3c.dom.Document doc = edoc; + final PipedOutputStream pos = new PipedOutputStream(); + PipedInputStream pis = new PipedInputStream(); + pis.connect(pos); + + (new Thread(new Runnable() { + + public void run() { + // Use the Transformer.transform() method to save the Document + // to a StreamResult + try { + TransformerFactory tFactory = TransformerFactory.newInstance(); + // Fortify Mod: prevent external entity injection + tFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer transformer = tFactory.newTransformer(); + transformer.setOutputProperty("encoding", "ISO-8859-1"); + transformer.setOutputProperty("indent", "yes"); + transformer.transform(new DOMSource(doc), new StreamResult(pos)); + } + catch (Exception _ex) { + throw new RuntimeException("Failed to tranform org.w3c.dom.Document to PipedOutputStream", _ex); + } + finally { + try { + pos.close(); + } + catch (IOException e) { + + } + } + } + }, "MyClassName.convert(org.w3c.dom.Document edoc)")).start(); + + return pis; + } + + /** + * Checks the given schematron phase for the XML file and returns the validation + * status. + * @param doc The XML file to validate (Document) + * @param schemaFile The string path to the schematron file to use + * @param phase The string phase name (contained in schematron file) + * @return Whether there were validation errors or not (boolean) + */ + public boolean checkSchematronRules(Document doc, String schemaFile, String phase) throws Exception { + + boolean isValid = false; + + if (doc == null || doc.getDocumentElement() == null) + return isValid; + try { + ClassLoader loader = this.getClass().getClassLoader(); + URL url = loader.getResource(schemaFile); + this.schemaFile = new File(URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8)); + } + catch (Exception e) { + assert false : "Entity body not found. " + e.toString(); + } + this.phase = phase; + Document returnDoc = parse(doc, null, null); + if (returnDoc != null) { + isValid = true; + } + return isValid; + } + + /** + * Checks the given schematron phase for the XML file and returns the validation + * status (takes schematron file, not string location). New and ADVANCED! (team engine + * can't work with overloaded methods :P) + * @param inputDoc The XML file to validate (Document) + * @param schemaFile The file object of the schematron file to validate with + * @param phase The string phase name (contained in schematron file) + * @return Whether there were validation errors or not (boolean) + */ + public boolean checkSchematronRulesAdv(InputSource inputDoc, File schemaFile, String phase) throws Exception { + + boolean isValid = false; + if (inputDoc == null) + return isValid; + this.schemaFile = schemaFile; + this.phase = phase; + + Document returnDoc = parse(inputDoc, null, null); + if (returnDoc != null) { + isValid = true; + } + return isValid; + } + + /** + * Runs the schematron file against the input source. + */ + public boolean executeSchematronDriver(InputSource inputDoc, File schemaFile, String phase) { + + boolean isValid = false; + ValidationDriver driver = createSchematronDriver(phase); + assert null != driver : "Unable to create Schematron ValidationDriver"; + InputSource is = null; + // Fortify Mod: move fis out so it can be closed on exit + FileInputStream fis = null; + try { + // FileInputStream fis = new FileInputStream(schemaFile); + fis = new FileInputStream(schemaFile); + is = new InputSource(fis); + } + catch (Exception e) { + e.printStackTrace(); + } + try { + if (driver.loadSchema(is)) { + isValid = driver.validate(inputDoc); + fis.close(); // Fortify addition + } + else { + assert false : ("Failed to load Schematron schema: " + schemaFile + + "\nIs the schema valid? Is the phase defined?"); + } + } + catch (SAXException e) { + assert false : e.toString(); + } + catch (IOException e) { + assert false : e.toString(); + } + return isValid; + } + + /** + * Sets up the schematron reader with all the necessary parameters. Calls + * initSchematronReader() to do further setup of the validation driver. + * @param phase The string phase name (contained in schematron file) + * @return The ValidationDriver to use in validating the XML document + */ + ValidationDriver createSchematronDriver(String phase) { + SchemaReaderLoader loader = new SchemaReaderLoader(); + SchemaReader schReader = loader.createSchemaReader(SCHEMATRON_NS_URI); + this.configPropBuilder = new PropertyMapBuilder(); + SchematronProperty.DIAGNOSE.add(this.configPropBuilder); + + if (this.outputLogger == null) { + this.outputLogger = new PrintWriter(System.out); + } + if (null != phase && !phase.isEmpty()) { + this.configPropBuilder.put(SchematronProperty.PHASE, phase); + } + ErrorHandler eh = new ErrorHandlerImpl("Schematron", outputLogger); + this.configPropBuilder.put(ValidateProperty.ERROR_HANDLER, eh); + return new ValidationDriver(this.configPropBuilder.toPropertyMap(), schReader); + } + + /** + * Parses and validates a resource obtained by dereferencing a URI. + * @param uc A URLConnection to access an XML resource. + * @param instruction An element containing parser instructions. + * @param logger The PrintWriter used for logging errors. + * @return A Document node if parsing succeeds, or {@code null} if it fails. + * @throws Exception + */ + public Document parse(URLConnection uc, Element instruction, PrintWriter logger) throws Exception { + return parse(uc.getInputStream(), instruction, logger); + } + + Document parse(InputStream is, Element instruction, PrintWriter logger) throws Exception { + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + // Fortify Mod: Disable entity expansion to foil External Entity Injections + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = null; + try { + doc = db.parse(is); + } + catch (Exception e) { + logger.println(e.getMessage()); + } + return parse(doc, instruction, logger); + } + + Document parse(InputSource is, Element instruction, PrintWriter logger) throws Exception { + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + // Fortify Mod: Disable entity expansion to foil External Entity Injections + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = null; + try { + doc = db.parse(is); + } + catch (Exception e) { + logger.println(e.getMessage()); + } + return parse(doc, instruction, logger); + } + + /** + * Checks the given Document against a Schematron schema. A schema reference is + * conveyed by a DOM Element node as indicated below. + * + *
+	 * {@code
+	 * 
+	 *   /class/path/schema1.sch
+	 * 
+	 * }
+	 * 
+ * @param doc The document to be validated. + * @param instruction An Element containing schema information. + * @param logger A Writer used for logging error messages. + * @return The valid document, or {@code null} if any errors were detected. + * @throws Exception + */ + Document parse(Document doc, Element instruction, PrintWriter logger) throws Exception { + this.outputLogger = logger; + if (instruction != null) { + getFileType(instruction); + if (type.equals("url")) { + URL schemaURL = new URL(this.schemaLocation); + this.schemaFile = new File(schemaURL.toURI()); + } + else if (type.equals("file")) { + this.schemaFile = new File(this.schemaLocation); + } + else if (type.equals("resource")) { + URL url = this.getClass().getResource(this.schemaLocation); + this.schemaFile = new File(URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8)); + } + } + boolean isValid = false; + if (doc != null) { + InputSource xmlInputSource = null; + try { + InputStream inputStream = DocumentToInputStream(doc); + xmlInputSource = new InputSource(inputStream); + } + catch (IOException e) { + e.printStackTrace(); + } + isValid = executeSchematronDriver(xmlInputSource, this.schemaFile, this.phase); + } + if (!isValid) { + return null; + } + else { + return doc; + } + } + + /** + * Checks the content of an XML entity against the applicable rules defined in a + * Schematron schema. The designated phase identifies the active patterns (rule sets); + * if not specified, the default phase is executed. + * @param xmlEntity A DOM Document representing the XML entity to validate. + * @param schemaRef A (classpath) reference to a Schematron 1.5 schema. + * @param phase The phase to execute. + * @return A NodeList containing validation errors (it may be empty). + */ + public NodeList validate(Document xmlEntity, String schemaRef, String phase) { + + if (xmlEntity == null || xmlEntity.getDocumentElement() == null) + throw new IllegalArgumentException("No XML entity supplied (null)."); + InputSource xmlInputSource = null; + try { + InputStream inputStream = DocumentToInputStream(xmlEntity); + xmlInputSource = new InputSource(inputStream); + } + catch (IOException e) { + throw new RuntimeException(e); + } + PropertyMapBuilder builder = new PropertyMapBuilder(); + SchematronProperty.DIAGNOSE.add(builder); + if (null != phase && !phase.isEmpty()) { + builder.put(SchematronProperty.PHASE, phase); + } + XmlErrorHandler errHandler = new XmlErrorHandler(); + builder.put(ValidateProperty.ERROR_HANDLER, errHandler); + ValidationDriver driver = createDriver(builder.toPropertyMap()); + InputStream schStream = this.getClass().getResourceAsStream(schemaRef.trim()); + try { + InputSource input = new InputSource(schStream); + try { + boolean loaded = driver.loadSchema(input); + if (!loaded) { + throw new Exception("Failed to load schema at " + schemaRef.trim() + + "\nIs the schema valid? Is the phase defined?"); + } + } + finally { + schStream.close(); + } + driver.validate(xmlInputSource); + } + catch (Exception e) { + throw new RuntimeException("Schematron validation failed.", e); + } + NodeList errList = errHandler.toNodeList(); + if (LOGR.isLoggable(Level.FINER)) { + LOGR.finer(String.format("Found %d Schematron rule violation(s):%n %s", errList.getLength(), + errHandler.toString())); + } + return errList; + } + + /** + * Creates and initializes a ValidationDriver to perform Schematron validation. A + * schema must be loaded before an instance can be validated. + * @param configProps A PropertyMap containing properties to configure schema + * construction and validation behavior; it typically includes + * {@code SchematronProperty} and {@code ValidationProperty} items. + * @return A ValidationDriver that is ready to load a Schematron schema. + */ + ValidationDriver createDriver(PropertyMap configProps) { + SchemaReaderLoader loader = new SchemaReaderLoader(); + SchemaReader schReader = loader.createSchemaReader(SCHEMATRON_NS_URI); + return new ValidationDriver(configProps, schReader); + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/SoapParser.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/SoapParser.java index 7c74f5111..6eb239eb6 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/SoapParser.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/SoapParser.java @@ -11,6 +11,26 @@ Intecs SPA are Copyright (C) 2008-2009, Intecs SPA. All Rights Reserved. package com.occamlab.te.parsers; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import org.w3c.dom.Document; import org.w3c.dom.Element; import java.net.URLConnection; diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/ValidationError.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/ValidationError.java index b2d7fd2b6..e949fd93b 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/ValidationError.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/ValidationError.java @@ -1,58 +1,78 @@ -package com.occamlab.te.parsers; - -/** - * Encapsulates information pertaining to a validation error. Instances of this class are - * immutable. - * - * @author rmartell - * @version $Rev$ - */ -public class ValidationError { - - /** - * A warning (e.g., a condition that does not cause the instance to be non-conforming. - */ - public static final short WARNING = 1; - - /** An error (e.g., the instance is invalid). */ - public static final short ERROR = 2; - - /** A fatal error (e.g., the instance is not well-formed). */ - public static final short FATAL_ERROR = 3; - - /** The error message. */ - private String message; - - /** The severity level. */ - private short severity; - - /** - * Constructs an immutable error object. - * @param severity the severity level (Warning, Error, Fatal) - * @param message a descriptive message - */ - public ValidationError(short severity, String message) { - if (null == message) { - message = "No details available"; - } - this.message = message; - this.severity = severity; - } - - /** - * Returns the message describing this error. - * @return the details about this error - */ - public String getMessage() { - return message; - } - - /** - * Returns the severity code (a short value) for this error. - * @return the severity code for this error - */ - public short getSeverity() { - return severity; - } - -} +package com.occamlab.te.parsers; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +/** + * Encapsulates information pertaining to a validation error. Instances of this class are + * immutable. + * + * @author rmartell + * @version $Rev$ + */ +public class ValidationError { + + /** + * A warning (e.g., a condition that does not cause the instance to be non-conforming. + */ + public static final short WARNING = 1; + + /** An error (e.g., the instance is invalid). */ + public static final short ERROR = 2; + + /** A fatal error (e.g., the instance is not well-formed). */ + public static final short FATAL_ERROR = 3; + + /** The error message. */ + private String message; + + /** The severity level. */ + private short severity; + + /** + * Constructs an immutable error object. + * @param severity the severity level (Warning, Error, Fatal) + * @param message a descriptive message + */ + public ValidationError(short severity, String message) { + if (null == message) { + message = "No details available"; + } + this.message = message; + this.severity = severity; + } + + /** + * Returns the message describing this error. + * @return the details about this error + */ + public String getMessage() { + return message; + } + + /** + * Returns the severity code (a short value) for this error. + * @return the severity code for this error + */ + public short getSeverity() { + return severity; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/XMLValidatingParser.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/XMLValidatingParser.java index 5d6a76790..fb6d8336a 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/XMLValidatingParser.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/XMLValidatingParser.java @@ -1,444 +1,464 @@ -/** - * ************************************************************************** - * - * Contributor(s): - * C. Heazel (WiSC): Added Fortify adjudication changes - * - *************************************************************************** - */ -package com.occamlab.te.parsers; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.CharArrayWriter; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintWriter; -import java.net.URI; -import java.net.URL; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.net.ssl.SSLProtocolException; -import javax.xml.XMLConstants; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Result; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import javax.xml.validation.Schema; -import javax.xml.validation.Validator; - -import org.w3c.dom.Document; -import org.w3c.dom.DocumentType; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.ErrorHandler; -import org.xml.sax.SAXException; - -import com.google.common.collect.ImmutableList; -import com.occamlab.te.ErrorHandlerImpl; -import com.occamlab.te.parsers.xml.CachingSchemaLoader; -import com.occamlab.te.parsers.xml.InMemorySchemaSupplier; -import com.occamlab.te.parsers.xml.XsdSchemaLoader; -import com.occamlab.te.parsers.xml.SchemaSupplier; -import com.occamlab.te.util.DomUtils; -import com.occamlab.te.util.URLConnectionUtils; - -/** - * Validates an XML resource against a set of W3C XML Schema or DTD schemas. - * - */ -public class XMLValidatingParser { - - static TransformerFactory TF = null; - static DocumentBuilderFactory nonValidatingDBF = null; - static DocumentBuilderFactory schemaValidatingDBF = null; - static DocumentBuilderFactory dtdValidatingDBF = null; - - ArrayList schemaList = new ArrayList<>(); - - ArrayList dtdList = new ArrayList<>(); - - /* - * For now we create a new cache per instance of XMLValidatingParser, which means a - * new cache per test run. These schemas could be cached for a longer period than - * that, but then the question because "how long?" Until the web app shuts down? Try - * to obey the caching headers in the HTTP responses? - * - * This solution at least fixes the major performance issue. - */ - private final CachingSchemaLoader schemaLoader = new CachingSchemaLoader(new XsdSchemaLoader()); - - private static final Logger jlogger = Logger.getLogger("com.occamlab.te.parsers.XMLValidatingParser"); - - private List loadSchemaList(Document schemaLinks, String schemaType) throws Exception { - NodeList nodes = schemaLinks.getElementsByTagNameNS("http://www.occamlab.com/te/parsers", schemaType); - if (nodes.getLength() == 0) { - return Collections.emptyList(); - } - final ArrayList schemas = new ArrayList<>(); - for (int i = 0; i < nodes.getLength(); i++) { - Element e = (Element) nodes.item(i); - Object schema = null; - String type = e.getAttribute("type"); - // URL, File, or Resource - if (type.equals("url")) { - schema = new URL(e.getTextContent()); - } - else if (type.equals("file")) { - schema = new File(e.getTextContent()); - } - else if (type.equals("resource")) { - ClassLoader cl = getClass().getClassLoader(); - String resource = e.getTextContent(); - URL url = cl.getResource(resource); - if (url == null) { - String msg = "Can't find schema resource on classpath at " + resource; - jlogger.warning(msg); - throw new Exception(msg); - } - schema = url; - } - else { - throw new Exception("Unknown schema resource type " + type); - } - jlogger.finer("Adding schema reference " + schema.toString()); - schemas.add(schema); - } - return schemas; - } - - private void loadSchemaLists(Node schemaLinks, ArrayList schemas, ArrayList dtds) - throws Exception { - if (null == schemaLinks) { - return; - } - jlogger.finer("Received schemaLinks\n" + DomUtils.serializeNode(schemaLinks)); - Document configDoc; - if (schemaLinks instanceof Document) { - configDoc = (Document) schemaLinks; - } - else { - configDoc = schemaLinks.getOwnerDocument(); - } - - final ArrayList schemaSuppliers = new ArrayList<>(); - for (final Object schemaObj : loadSchemaList(configDoc, "schema")) { - schemaSuppliers.add(SchemaSupplier.makeSupplier(schemaObj)); - } - schemas.addAll(schemaSuppliers); - dtds.addAll(loadSchemaList(configDoc, "dtd")); - - // If instruction body is an embedded xsd:schema, add it to the - // ArrayList - NodeList nodes = configDoc.getElementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "schema"); - for (int i = 0; i < nodes.getLength(); i++) { - Element e = (Element) nodes.item(i); - CharArrayWriter caw = new CharArrayWriter(); - Transformer t = TF.newTransformer(); - t.transform(new DOMSource(e), new StreamResult(caw)); - schemas.add(new InMemorySchemaSupplier(caw.toCharArray())); - } - } - - public XMLValidatingParser() { - - if (nonValidatingDBF == null) { - String property_name = "javax.xml.parsers.DocumentBuilderFactory"; - String oldprop = System.getProperty(property_name); - System.setProperty(property_name, "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl"); - nonValidatingDBF = DocumentBuilderFactory.newInstance(); - // Fortify Mod: Disable entity expansion to foil External Entity Injections - nonValidatingDBF.setExpandEntityReferences(false); - nonValidatingDBF.setNamespaceAware(true); - schemaValidatingDBF = DocumentBuilderFactory.newInstance(); - schemaValidatingDBF.setNamespaceAware(true); - schemaValidatingDBF.setValidating(true); - schemaValidatingDBF.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", - "http://www.w3.org/2001/XMLSchema"); - dtdValidatingDBF = DocumentBuilderFactory.newInstance(); - dtdValidatingDBF.setNamespaceAware(true); - dtdValidatingDBF.setValidating(true); - // Fortify Mod: Disable entity expansion to foil External Entity Injections - dtdValidatingDBF.setExpandEntityReferences(false); - if (oldprop == null) { - System.clearProperty(property_name); - } - else { - System.setProperty(property_name, oldprop); - } - } - - if (TF == null) { - // Fortify Mod: prevent external entity injection - // includes try block to capture exceptions to setFeature. - TF = TransformerFactory.newInstance(); - try { - TF.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - } - catch (Exception e) { - jlogger.warning("Failed to secure Transformer"); - } - } - } - - public XMLValidatingParser(Document schema_links) throws Exception { - this(); - if (null != schema_links) { - loadSchemaLists(schema_links, this.schemaList, this.dtdList); - } - } - - /** - * Attempts to parse a resource read using the given connection to a URL. - * @param uc A connection for reading from some URL. - * @param instruction An Element node (ctlp:XMLValidatingParser) containing - * instructions, usually schema references. - * @param logger A log writer. - * @return A Document, or null if the resource could not be parsed. - * @throws SSLProtocolException - */ - public Document parse(URLConnection uc, Element instruction, PrintWriter logger) throws SSLProtocolException { - if (null == uc) { - throw new NullPointerException("Unable to parse resource: URLConnection is null."); - } - jlogger.fine("Received URLConnection object for " + uc.getURL()); - Document doc = null; - try (InputStream inStream = URLConnectionUtils.getInputStream(uc)) { - doc = parse(inStream, instruction, logger); - } - catch (SSLProtocolException sslep) { - throw new SSLProtocolException( - "[SSL ERROR] Failed to connect with the requested URL due to \"Invalid server_name\" found!! :" - + uc.getURL() + ":" + sslep.getClass() + " : " + sslep.getMessage()); - } - catch (Exception e) { - throw new RuntimeException(String.format("Failed to parse resource from %s", uc.getURL()), e); - } - return doc; - } - - /** - * Parses and validates an XML resource using the given schema references. - * @param input The XML input to parse and validate. It must be either an InputStream - * or a Document object. - * @param parserConfig An Element - * ({http://www.occamlab.com/te/parsers}XMLValidatingParser) containing configuration - * info. If it is {@code null} or empty validation will be performed by using location - * hints in the input document. - * @param logger The PrintWriter to log all results to - * @return {@code null} If any non-ignorable errors or warnings occurred; otherwise - * the resulting Document. - * - */ - Document parse(Object input, Element parserConfig, PrintWriter logger) throws Exception { - jlogger.finer("Received XML resource of type " + input.getClass().getName()); - Document resultDoc = null; - ErrorHandlerImpl errHandler = new ErrorHandlerImpl("Parsing", logger); - - if (input instanceof InputStream) { - DocumentBuilderFactory dbf = nonValidatingDBF; - DocumentBuilder db = dbf.newDocumentBuilder(); - db.setErrorHandler(errHandler); - try (InputStream xmlInput = (InputStream) input) { - resultDoc = db.parse(xmlInput); - } - catch (Exception e) { - jlogger.log(Level.INFO, "Error parsing InputStream", e); - } - } - else if (input instanceof Document) { - resultDoc = (Document) input; - } - else { - throw new IllegalArgumentException("XML input must be an InputStream or a Document object."); - } - if (null == resultDoc) { - throw new RuntimeException("Failed to parse input: " + input.getClass().getName()); - } - errHandler.setRole("Validation"); - validate(resultDoc, parserConfig, errHandler); - int error_count = errHandler.getErrorCount(); - int warning_count = errHandler.getWarningCount(); - if (error_count > 0 || warning_count > 0) { - String msg = ""; - if (error_count > 0) { - msg += error_count + " validation error" + (error_count == 1 ? "" : "s"); - if (warning_count > 0) - msg += " and "; - } - if (warning_count > 0) { - msg += warning_count + " warning" + (warning_count == 1 ? "" : "s"); - } - msg += " detected."; - logger.println(msg); - } - - if (error_count > 0) { - String s = (null != parserConfig) ? parserConfig.getAttribute("ignoreErrors") : "false"; - if (s.length() == 0 || !Boolean.parseBoolean(s)) { - resultDoc = null; - } - } - - if (warning_count > 0) { - String s = (null != parserConfig) ? parserConfig.getAttribute("ignoreWarnings") : "true"; - if (s.length() > 0 && !Boolean.parseBoolean(s)) { - resultDoc = null; - } - } - return resultDoc; - } - - /** - * A method to validate a pool of schemas outside of the request element. - * @param doc doc The file document to validate - * @param instruction instruction The xml encapsulated schema information (file - * locations) - * @return false if there were errors, true if none. - * - */ - public boolean checkXMLRules(Document doc, Document instruction) throws Exception { - - if (doc == null || doc.getDocumentElement() == null) - return false; - Element e = instruction.getDocumentElement(); - PrintWriter logger = new PrintWriter(System.out); - Document parsedDoc = parse(doc, e, logger); - return (parsedDoc != null); - } - - /** - * Validates the given document against the schema references supplied in the - * accompanying instruction document. - * @param doc The document to be validated. - * @param instruction A document containing schema references; may be null, in which - * case embedded schema references will be used instead. - * @return A list of Element nodes ({@code }) containing error messages. - * @throws Exception If any error occurs. - */ - public NodeList validate(Document doc, Document instruction) throws Exception { - return schemaValidation(doc, instruction).toNodeList(); - } - - public Element validateSingleResult(Document doc, Document instruction) throws Exception { - return schemaValidation(doc, instruction).toRootElement(); - } - - XmlErrorHandler schemaValidation(Document doc, Document instruction) throws Exception { - if (doc == null || doc.getDocumentElement() == null) { - throw new NullPointerException("Input document is null."); - } - XmlErrorHandler errHandler = new XmlErrorHandler(); - validate(doc, instruction, errHandler); - return errHandler; - } - - /** - * Validates the given XML {@link Document} per the given instructions, recording - * errors in the given error handler. - * @param doc must not be null - * @param instruction may be null to signify no special instructions - * @param errHandler errors will be recorded on this object - */ - private void validate(final Document doc, final Node instruction, final ErrorHandler errHandler) throws Exception { - ArrayList schemas = new ArrayList<>(schemaList); - ArrayList dtds = new ArrayList<>(dtdList); - loadSchemaLists(instruction, schemas, dtds); - if (null == doc.getDoctype() && dtds.isEmpty()) { - validateAgainstXMLSchemaList(doc, schemas, errHandler); - } - else { - validateAgainstDTDList(doc, dtds, errHandler); - } - } - - /** - * Validates an XML resource against a list of XML Schemas. Validation errors are - * reported to the given handler. - * @param doc The input Document node. - * @param xsdList A list of XML schema references. Must be non-null, but if empty, - * validation will be performed by using location hints found in the input document. - * @param errHandler An ErrorHandler that collects validation errors. - * @throws SAXException If a schema cannot be read for some reason. - * @throws IOException If an I/O error occurs. - */ - void validateAgainstXMLSchemaList(Document doc, List xsdList, ErrorHandler errHandler) - throws SAXException, IOException { - jlogger - .fine("Validating XML resource from " + doc.getDocumentURI() + " with these specified schemas: " + xsdList); - Schema schema; - if (!xsdList.isEmpty()) { - schema = schemaLoader.loadSchema(ImmutableList.copyOf(xsdList)); - } - else { - schema = schemaLoader.defaultSchema(); - } - Validator validator = schema.newValidator(); - validator.setErrorHandler(errHandler); - DOMSource source = new DOMSource(doc, doc.getBaseURI()); - validator.validate(source); - } - - /** - * Validates an XML resource against a list of DTD schemas or as indicated by a - * DOCTYPE declaration. Validation errors are reported to the given handler. If no DTD - * references are provided the external schema reference in the DOCTYPE declaration is - * used (Note: an internal subset is ignored). - * @param doc The input Document. - * @param dtdList A list of DTD schema references. May be empty but not null. - * @param errHandler An ErrorHandler that collects validation errors. - * @throws Exception If any errors occur while attempting to validate the document. - */ - private void validateAgainstDTDList(Document doc, ArrayList dtdList, ErrorHandler errHandler) - throws Exception { - jlogger.finer("Validating XML resource from " + doc.getDocumentURI()); - DocumentBuilder db = dtdValidatingDBF.newDocumentBuilder(); - db.setErrorHandler(errHandler); - // Fortify Mod: prevent external entity injection - // includes try block to capture exceptions to setFeature. - TransformerFactory tf = TransformerFactory.newInstance(); - try { - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - } - catch (Exception e) { - jlogger.warning("Failed to secure Transformer"); - } - // End Fortify Mod - Transformer copier = tf.newTransformer(); - ByteArrayOutputStream content = new ByteArrayOutputStream(); - Result copy = new StreamResult(content); - if (dtdList.isEmpty()) { - DocumentType doctype = doc.getDoctype(); - if (null == doctype) { - return; - } - URI systemId = URI.create(doctype.getSystemId()); - if (!systemId.isAbsolute() && null != doc.getBaseURI()) { - systemId = URI.create(doc.getBaseURI()).resolve(systemId); - } - copier.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, systemId.toString()); - copier.transform(new DOMSource(doc), copy); - db.parse(new ByteArrayInputStream(content.toByteArray())); - } - else { - for (Object dtdRef : dtdList) { - content.reset(); - copier.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, dtdRef.toString()); - copier.transform(new DOMSource(doc), copy); - db.parse(new ByteArrayInputStream(content.toByteArray())); - } - } - } - -} +/** + * ************************************************************************** + * + * Contributor(s): + * C. Heazel (WiSC): Added Fortify adjudication changes + * + *************************************************************************** + */ +package com.occamlab.te.parsers; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.CharArrayWriter; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.SSLProtocolException; +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Result; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.validation.Schema; +import javax.xml.validation.Validator; + +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; + +import com.google.common.collect.ImmutableList; +import com.occamlab.te.ErrorHandlerImpl; +import com.occamlab.te.parsers.xml.CachingSchemaLoader; +import com.occamlab.te.parsers.xml.InMemorySchemaSupplier; +import com.occamlab.te.parsers.xml.XsdSchemaLoader; +import com.occamlab.te.parsers.xml.SchemaSupplier; +import com.occamlab.te.util.DomUtils; +import com.occamlab.te.util.URLConnectionUtils; + +/** + * Validates an XML resource against a set of W3C XML Schema or DTD schemas. + * + */ +public class XMLValidatingParser { + + static TransformerFactory TF = null; + static DocumentBuilderFactory nonValidatingDBF = null; + static DocumentBuilderFactory schemaValidatingDBF = null; + static DocumentBuilderFactory dtdValidatingDBF = null; + + ArrayList schemaList = new ArrayList<>(); + + ArrayList dtdList = new ArrayList<>(); + + /* + * For now we create a new cache per instance of XMLValidatingParser, which means a + * new cache per test run. These schemas could be cached for a longer period than + * that, but then the question because "how long?" Until the web app shuts down? Try + * to obey the caching headers in the HTTP responses? + * + * This solution at least fixes the major performance issue. + */ + private final CachingSchemaLoader schemaLoader = new CachingSchemaLoader(new XsdSchemaLoader()); + + private static final Logger jlogger = Logger.getLogger("com.occamlab.te.parsers.XMLValidatingParser"); + + private List loadSchemaList(Document schemaLinks, String schemaType) throws Exception { + NodeList nodes = schemaLinks.getElementsByTagNameNS("http://www.occamlab.com/te/parsers", schemaType); + if (nodes.getLength() == 0) { + return Collections.emptyList(); + } + final ArrayList schemas = new ArrayList<>(); + for (int i = 0; i < nodes.getLength(); i++) { + Element e = (Element) nodes.item(i); + Object schema = null; + String type = e.getAttribute("type"); + // URL, File, or Resource + if (type.equals("url")) { + schema = new URL(e.getTextContent()); + } + else if (type.equals("file")) { + schema = new File(e.getTextContent()); + } + else if (type.equals("resource")) { + ClassLoader cl = getClass().getClassLoader(); + String resource = e.getTextContent(); + URL url = cl.getResource(resource); + if (url == null) { + String msg = "Can't find schema resource on classpath at " + resource; + jlogger.warning(msg); + throw new Exception(msg); + } + schema = url; + } + else { + throw new Exception("Unknown schema resource type " + type); + } + jlogger.finer("Adding schema reference " + schema.toString()); + schemas.add(schema); + } + return schemas; + } + + private void loadSchemaLists(Node schemaLinks, ArrayList schemas, ArrayList dtds) + throws Exception { + if (null == schemaLinks) { + return; + } + jlogger.finer("Received schemaLinks\n" + DomUtils.serializeNode(schemaLinks)); + Document configDoc; + if (schemaLinks instanceof Document) { + configDoc = (Document) schemaLinks; + } + else { + configDoc = schemaLinks.getOwnerDocument(); + } + + final ArrayList schemaSuppliers = new ArrayList<>(); + for (final Object schemaObj : loadSchemaList(configDoc, "schema")) { + schemaSuppliers.add(SchemaSupplier.makeSupplier(schemaObj)); + } + schemas.addAll(schemaSuppliers); + dtds.addAll(loadSchemaList(configDoc, "dtd")); + + // If instruction body is an embedded xsd:schema, add it to the + // ArrayList + NodeList nodes = configDoc.getElementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "schema"); + for (int i = 0; i < nodes.getLength(); i++) { + Element e = (Element) nodes.item(i); + CharArrayWriter caw = new CharArrayWriter(); + Transformer t = TF.newTransformer(); + t.transform(new DOMSource(e), new StreamResult(caw)); + schemas.add(new InMemorySchemaSupplier(caw.toCharArray())); + } + } + + public XMLValidatingParser() { + + if (nonValidatingDBF == null) { + String property_name = "javax.xml.parsers.DocumentBuilderFactory"; + String oldprop = System.getProperty(property_name); + System.setProperty(property_name, "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl"); + nonValidatingDBF = DocumentBuilderFactory.newInstance(); + // Fortify Mod: Disable entity expansion to foil External Entity Injections + nonValidatingDBF.setExpandEntityReferences(false); + nonValidatingDBF.setNamespaceAware(true); + schemaValidatingDBF = DocumentBuilderFactory.newInstance(); + schemaValidatingDBF.setNamespaceAware(true); + schemaValidatingDBF.setValidating(true); + schemaValidatingDBF.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", + "http://www.w3.org/2001/XMLSchema"); + dtdValidatingDBF = DocumentBuilderFactory.newInstance(); + dtdValidatingDBF.setNamespaceAware(true); + dtdValidatingDBF.setValidating(true); + // Fortify Mod: Disable entity expansion to foil External Entity Injections + dtdValidatingDBF.setExpandEntityReferences(false); + if (oldprop == null) { + System.clearProperty(property_name); + } + else { + System.setProperty(property_name, oldprop); + } + } + + if (TF == null) { + // Fortify Mod: prevent external entity injection + // includes try block to capture exceptions to setFeature. + TF = TransformerFactory.newInstance(); + try { + TF.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } + catch (Exception e) { + jlogger.warning("Failed to secure Transformer"); + } + } + } + + public XMLValidatingParser(Document schema_links) throws Exception { + this(); + if (null != schema_links) { + loadSchemaLists(schema_links, this.schemaList, this.dtdList); + } + } + + /** + * Attempts to parse a resource read using the given connection to a URL. + * @param uc A connection for reading from some URL. + * @param instruction An Element node (ctlp:XMLValidatingParser) containing + * instructions, usually schema references. + * @param logger A log writer. + * @return A Document, or null if the resource could not be parsed. + * @throws SSLProtocolException + */ + public Document parse(URLConnection uc, Element instruction, PrintWriter logger) throws SSLProtocolException { + if (null == uc) { + throw new NullPointerException("Unable to parse resource: URLConnection is null."); + } + jlogger.fine("Received URLConnection object for " + uc.getURL()); + Document doc = null; + try (InputStream inStream = URLConnectionUtils.getInputStream(uc)) { + doc = parse(inStream, instruction, logger); + } + catch (SSLProtocolException sslep) { + throw new SSLProtocolException( + "[SSL ERROR] Failed to connect with the requested URL due to \"Invalid server_name\" found!! :" + + uc.getURL() + ":" + sslep.getClass() + " : " + sslep.getMessage()); + } + catch (Exception e) { + throw new RuntimeException(String.format("Failed to parse resource from %s", uc.getURL()), e); + } + return doc; + } + + /** + * Parses and validates an XML resource using the given schema references. + * @param input The XML input to parse and validate. It must be either an InputStream + * or a Document object. + * @param parserConfig An Element + * ({http://www.occamlab.com/te/parsers}XMLValidatingParser) containing configuration + * info. If it is {@code null} or empty validation will be performed by using location + * hints in the input document. + * @param logger The PrintWriter to log all results to + * @return {@code null} If any non-ignorable errors or warnings occurred; otherwise + * the resulting Document. + * + */ + Document parse(Object input, Element parserConfig, PrintWriter logger) throws Exception { + jlogger.finer("Received XML resource of type " + input.getClass().getName()); + Document resultDoc = null; + ErrorHandlerImpl errHandler = new ErrorHandlerImpl("Parsing", logger); + + if (input instanceof InputStream) { + DocumentBuilderFactory dbf = nonValidatingDBF; + DocumentBuilder db = dbf.newDocumentBuilder(); + db.setErrorHandler(errHandler); + try (InputStream xmlInput = (InputStream) input) { + resultDoc = db.parse(xmlInput); + } + catch (Exception e) { + jlogger.log(Level.INFO, "Error parsing InputStream", e); + } + } + else if (input instanceof Document) { + resultDoc = (Document) input; + } + else { + throw new IllegalArgumentException("XML input must be an InputStream or a Document object."); + } + if (null == resultDoc) { + throw new RuntimeException("Failed to parse input: " + input.getClass().getName()); + } + errHandler.setRole("Validation"); + validate(resultDoc, parserConfig, errHandler); + int error_count = errHandler.getErrorCount(); + int warning_count = errHandler.getWarningCount(); + if (error_count > 0 || warning_count > 0) { + String msg = ""; + if (error_count > 0) { + msg += error_count + " validation error" + (error_count == 1 ? "" : "s"); + if (warning_count > 0) + msg += " and "; + } + if (warning_count > 0) { + msg += warning_count + " warning" + (warning_count == 1 ? "" : "s"); + } + msg += " detected."; + logger.println(msg); + } + + if (error_count > 0) { + String s = (null != parserConfig) ? parserConfig.getAttribute("ignoreErrors") : "false"; + if (s.length() == 0 || !Boolean.parseBoolean(s)) { + resultDoc = null; + } + } + + if (warning_count > 0) { + String s = (null != parserConfig) ? parserConfig.getAttribute("ignoreWarnings") : "true"; + if (s.length() > 0 && !Boolean.parseBoolean(s)) { + resultDoc = null; + } + } + return resultDoc; + } + + /** + * A method to validate a pool of schemas outside of the request element. + * @param doc doc The file document to validate + * @param instruction instruction The xml encapsulated schema information (file + * locations) + * @return false if there were errors, true if none. + * + */ + public boolean checkXMLRules(Document doc, Document instruction) throws Exception { + + if (doc == null || doc.getDocumentElement() == null) + return false; + Element e = instruction.getDocumentElement(); + PrintWriter logger = new PrintWriter(System.out); + Document parsedDoc = parse(doc, e, logger); + return (parsedDoc != null); + } + + /** + * Validates the given document against the schema references supplied in the + * accompanying instruction document. + * @param doc The document to be validated. + * @param instruction A document containing schema references; may be null, in which + * case embedded schema references will be used instead. + * @return A list of Element nodes ({@code }) containing error messages. + * @throws Exception If any error occurs. + */ + public NodeList validate(Document doc, Document instruction) throws Exception { + return schemaValidation(doc, instruction).toNodeList(); + } + + public Element validateSingleResult(Document doc, Document instruction) throws Exception { + return schemaValidation(doc, instruction).toRootElement(); + } + + XmlErrorHandler schemaValidation(Document doc, Document instruction) throws Exception { + if (doc == null || doc.getDocumentElement() == null) { + throw new NullPointerException("Input document is null."); + } + XmlErrorHandler errHandler = new XmlErrorHandler(); + validate(doc, instruction, errHandler); + return errHandler; + } + + /** + * Validates the given XML {@link Document} per the given instructions, recording + * errors in the given error handler. + * @param doc must not be null + * @param instruction may be null to signify no special instructions + * @param errHandler errors will be recorded on this object + */ + private void validate(final Document doc, final Node instruction, final ErrorHandler errHandler) throws Exception { + ArrayList schemas = new ArrayList<>(schemaList); + ArrayList dtds = new ArrayList<>(dtdList); + loadSchemaLists(instruction, schemas, dtds); + if (null == doc.getDoctype() && dtds.isEmpty()) { + validateAgainstXMLSchemaList(doc, schemas, errHandler); + } + else { + validateAgainstDTDList(doc, dtds, errHandler); + } + } + + /** + * Validates an XML resource against a list of XML Schemas. Validation errors are + * reported to the given handler. + * @param doc The input Document node. + * @param xsdList A list of XML schema references. Must be non-null, but if empty, + * validation will be performed by using location hints found in the input document. + * @param errHandler An ErrorHandler that collects validation errors. + * @throws SAXException If a schema cannot be read for some reason. + * @throws IOException If an I/O error occurs. + */ + void validateAgainstXMLSchemaList(Document doc, List xsdList, ErrorHandler errHandler) + throws SAXException, IOException { + jlogger + .fine("Validating XML resource from " + doc.getDocumentURI() + " with these specified schemas: " + xsdList); + Schema schema; + if (!xsdList.isEmpty()) { + schema = schemaLoader.loadSchema(ImmutableList.copyOf(xsdList)); + } + else { + schema = schemaLoader.defaultSchema(); + } + Validator validator = schema.newValidator(); + validator.setErrorHandler(errHandler); + DOMSource source = new DOMSource(doc, doc.getBaseURI()); + validator.validate(source); + } + + /** + * Validates an XML resource against a list of DTD schemas or as indicated by a + * DOCTYPE declaration. Validation errors are reported to the given handler. If no DTD + * references are provided the external schema reference in the DOCTYPE declaration is + * used (Note: an internal subset is ignored). + * @param doc The input Document. + * @param dtdList A list of DTD schema references. May be empty but not null. + * @param errHandler An ErrorHandler that collects validation errors. + * @throws Exception If any errors occur while attempting to validate the document. + */ + private void validateAgainstDTDList(Document doc, ArrayList dtdList, ErrorHandler errHandler) + throws Exception { + jlogger.finer("Validating XML resource from " + doc.getDocumentURI()); + DocumentBuilder db = dtdValidatingDBF.newDocumentBuilder(); + db.setErrorHandler(errHandler); + // Fortify Mod: prevent external entity injection + // includes try block to capture exceptions to setFeature. + TransformerFactory tf = TransformerFactory.newInstance(); + try { + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } + catch (Exception e) { + jlogger.warning("Failed to secure Transformer"); + } + // End Fortify Mod + Transformer copier = tf.newTransformer(); + ByteArrayOutputStream content = new ByteArrayOutputStream(); + Result copy = new StreamResult(content); + if (dtdList.isEmpty()) { + DocumentType doctype = doc.getDoctype(); + if (null == doctype) { + return; + } + URI systemId = URI.create(doctype.getSystemId()); + if (!systemId.isAbsolute() && null != doc.getBaseURI()) { + systemId = URI.create(doc.getBaseURI()).resolve(systemId); + } + copier.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, systemId.toString()); + copier.transform(new DOMSource(doc), copy); + db.parse(new ByteArrayInputStream(content.toByteArray())); + } + else { + for (Object dtdRef : dtdList) { + content.reset(); + copier.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, dtdRef.toString()); + copier.transform(new DOMSource(doc), copy); + db.parse(new ByteArrayInputStream(content.toByteArray())); + } + } + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/XSLTransformationErrorHandler.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/XSLTransformationErrorHandler.java index eb3d5ccc0..7f98cc0c7 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/XSLTransformationErrorHandler.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/XSLTransformationErrorHandler.java @@ -1,55 +1,75 @@ -package com.occamlab.te.parsers; - -import java.io.PrintWriter; - -import javax.xml.transform.ErrorListener; -import javax.xml.transform.TransformerException; - -public class XSLTransformationErrorHandler implements ErrorListener { - - PrintWriter logger; - - boolean ignoreErrors; - - boolean ignoreWarnings; - - int errorCount; - - int warningCount; - - public XSLTransformationErrorHandler(PrintWriter logger, boolean ignoreErrors, boolean ignoreWarnings) { - this.logger = logger; - this.ignoreErrors = ignoreErrors; - this.ignoreWarnings = ignoreWarnings; - } - - @Override - public void error(TransformerException e) throws TransformerException { - if (!ignoreErrors) { - logger.println("Error: " + e.getMessageAndLocation()); - } - errorCount++; - } - - @Override - public void fatalError(TransformerException e) throws TransformerException { - logger.println("Fatal Error: " + e.getMessageAndLocation()); - } - - @Override - public void warning(TransformerException e) throws TransformerException { - if (!ignoreWarnings) { - logger.println("Warning: " + e.getMessageAndLocation()); - } - warningCount++; - } - - public int getErrorCount() { - return errorCount; - } - - public int getWarningCount() { - return warningCount; - } - -} +package com.occamlab.te.parsers; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.PrintWriter; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.TransformerException; + +public class XSLTransformationErrorHandler implements ErrorListener { + + PrintWriter logger; + + boolean ignoreErrors; + + boolean ignoreWarnings; + + int errorCount; + + int warningCount; + + public XSLTransformationErrorHandler(PrintWriter logger, boolean ignoreErrors, boolean ignoreWarnings) { + this.logger = logger; + this.ignoreErrors = ignoreErrors; + this.ignoreWarnings = ignoreWarnings; + } + + @Override + public void error(TransformerException e) throws TransformerException { + if (!ignoreErrors) { + logger.println("Error: " + e.getMessageAndLocation()); + } + errorCount++; + } + + @Override + public void fatalError(TransformerException e) throws TransformerException { + logger.println("Fatal Error: " + e.getMessageAndLocation()); + } + + @Override + public void warning(TransformerException e) throws TransformerException { + if (!ignoreWarnings) { + logger.println("Warning: " + e.getMessageAndLocation()); + } + warningCount++; + } + + public int getErrorCount() { + return errorCount; + } + + public int getWarningCount() { + return warningCount; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/XSLTransformationParser.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/XSLTransformationParser.java index bfbb23e85..3d1a985be 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/XSLTransformationParser.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/XSLTransformationParser.java @@ -1,180 +1,200 @@ -package com.occamlab.te.parsers; - -import java.io.InputStream; -import java.io.PrintWriter; -import java.net.URL; -import java.net.URLConnection; -import java.util.HashMap; -import java.util.List; -import java.util.Map.Entry; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.Source; -import javax.xml.transform.Templates; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMResult; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamSource; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -import com.occamlab.te.Test; -import com.occamlab.te.util.DomUtils; -import com.occamlab.te.util.URLConnectionUtils; - -import static java.lang.Boolean.FALSE; -import static java.lang.Boolean.TRUE; - -public class XSLTransformationParser { - - private static final Logger LOGR = Logger.getLogger(XSLTransformationParser.class.getName()); - - DocumentBuilder db = null; - - TransformerFactory tf = null; - - Templates defaultTemplates = null; - - HashMap defaultProperties = null; - - HashMap defaultParams = null; - - Boolean defaultIgnoreErrors; - - Boolean defaultIgnoreWarnings; - - public XSLTransformationParser() throws Exception { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - db = dbf.newDocumentBuilder(); - tf = TransformerFactory.newInstance(); - defaultProperties = new HashMap<>(); - defaultParams = new HashMap<>(); - defaultIgnoreErrors = FALSE; - defaultIgnoreWarnings = TRUE; - } - - public XSLTransformationParser(Node node) throws Exception { - super(); - defaultTemplates = parseInstruction(DomUtils.getElement(node), defaultProperties, defaultParams, - defaultIgnoreErrors, defaultIgnoreWarnings); - } - - public XSLTransformationParser(String reftype, String ref) throws Exception { - super(); - defaultTemplates = tf.newTemplates(getSource(reftype, ref)); - } - - private Source getSource(String reftype, String ref) throws Exception { - if (reftype.equals("url")) { - URL url = new URL(ref); - return new StreamSource(url.openStream()); - } - else if (reftype.equals("file")) { - return new StreamSource(ref); - } - else if (reftype.equals("resource")) { - ClassLoader cl = getClass().getClassLoader(); - return new StreamSource(cl.getResourceAsStream(ref)); - } - return null; - } - - private Templates parseInstruction(Element instruction, HashMap properties, - HashMap params, Boolean ignoreErrors, Boolean ignoreWarnings) throws Exception { - Templates templates = null; - final String[] atts = { "url", "file", "resource" }; - for (String att : atts) { - String val = instruction.getAttribute(att); - if (val.length() > 0) { - templates = tf.newTemplates(getSource(att, val)); - break; - } - } - Element stylesheet = DomUtils.getElementByTagNameNS(instruction, Test.XSL_NS, "stylesheet"); - if (stylesheet == null) { - stylesheet = DomUtils.getElementByTagNameNS(instruction, Test.XSL_NS, "transform"); - } - if (stylesheet != null) { - templates = tf.newTemplates(new DOMSource(stylesheet)); - } - List children = DomUtils.getChildElements(instruction); - for (Element e : children) { - if (e.getLocalName().equals("property") && e.getNamespaceURI().equals(Test.CTLP_NS)) { - properties.put(e.getAttribute("name"), e.getTextContent()); - } - if (e.getLocalName().equals("with-param") && e.getNamespaceURI().equals(Test.CTLP_NS)) { - params.put(e.getAttribute("name"), e.getTextContent()); - } - } - String ignoreErrorsAtt = instruction.getAttribute("ignoreErrors"); - if (ignoreErrorsAtt != null) { - ignoreErrors = Boolean.parseBoolean(ignoreErrorsAtt); - } - String ignoreWarningsAtt = instruction.getAttribute("ignoreWarnings"); - if (ignoreWarningsAtt != null) { - ignoreWarnings = Boolean.parseBoolean(ignoreWarningsAtt); - } - return templates; - } - - public Document parse(URLConnection uc, Element instruction, PrintWriter logger) throws Exception { - HashMap properties = new HashMap<>(defaultProperties); - HashMap params = new HashMap<>(defaultParams); - Boolean ignoreErrors = defaultIgnoreErrors; - Boolean ignoreWarnings = defaultIgnoreWarnings; - Templates templates = parseInstruction(instruction, properties, params, ignoreErrors, ignoreWarnings); - Transformer t = null; - if (templates != null) { - t = templates.newTransformer(); - } - else if (defaultTemplates != null) { - t = defaultTemplates.newTransformer(); - } - else { - t = tf.newTransformer(); - } - for (Entry prop : properties.entrySet()) { - t.setOutputProperty(prop.getKey(), prop.getValue()); - } - for (Entry param : params.entrySet()) { - t.setParameter(param.getKey(), param.getValue()); - } - XSLTransformationErrorHandler el = new XSLTransformationErrorHandler(logger, ignoreErrors, ignoreWarnings); - t.setErrorListener(el); - Document doc = db.newDocument(); - InputStream is = null; - try { - if (LOGR.isLoggable(Level.FINER)) { - String msg = String.format("Attempting to transform source from %s using instruction set:%n %s", - uc.getURL(), DomUtils.serializeNode(instruction)); - LOGR.finer(msg); - } - // may return error stream - is = URLConnectionUtils.getInputStream(uc); - t.transform(new StreamSource(is), new DOMResult(doc)); - } - catch (TransformerException e) { - el.error(e); - } - finally { - if (null != is) - is.close(); - } - if (el.getErrorCount() > 0 && !ignoreErrors) { - return null; - } - if (el.getWarningCount() > 0 && !ignoreWarnings) { - return null; - } - return doc; - } - -} +package com.occamlab.te.parsers; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.InputStream; +import java.io.PrintWriter; +import java.net.URL; +import java.net.URLConnection; +import java.util.HashMap; +import java.util.List; +import java.util.Map.Entry; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Source; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamSource; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import com.occamlab.te.Test; +import com.occamlab.te.util.DomUtils; +import com.occamlab.te.util.URLConnectionUtils; + +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; + +public class XSLTransformationParser { + + private static final Logger LOGR = Logger.getLogger(XSLTransformationParser.class.getName()); + + DocumentBuilder db = null; + + TransformerFactory tf = null; + + Templates defaultTemplates = null; + + HashMap defaultProperties = null; + + HashMap defaultParams = null; + + Boolean defaultIgnoreErrors; + + Boolean defaultIgnoreWarnings; + + public XSLTransformationParser() throws Exception { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + db = dbf.newDocumentBuilder(); + tf = TransformerFactory.newInstance(); + defaultProperties = new HashMap<>(); + defaultParams = new HashMap<>(); + defaultIgnoreErrors = FALSE; + defaultIgnoreWarnings = TRUE; + } + + public XSLTransformationParser(Node node) throws Exception { + super(); + defaultTemplates = parseInstruction(DomUtils.getElement(node), defaultProperties, defaultParams, + defaultIgnoreErrors, defaultIgnoreWarnings); + } + + public XSLTransformationParser(String reftype, String ref) throws Exception { + super(); + defaultTemplates = tf.newTemplates(getSource(reftype, ref)); + } + + private Source getSource(String reftype, String ref) throws Exception { + if (reftype.equals("url")) { + URL url = new URL(ref); + return new StreamSource(url.openStream()); + } + else if (reftype.equals("file")) { + return new StreamSource(ref); + } + else if (reftype.equals("resource")) { + ClassLoader cl = getClass().getClassLoader(); + return new StreamSource(cl.getResourceAsStream(ref)); + } + return null; + } + + private Templates parseInstruction(Element instruction, HashMap properties, + HashMap params, Boolean ignoreErrors, Boolean ignoreWarnings) throws Exception { + Templates templates = null; + final String[] atts = { "url", "file", "resource" }; + for (String att : atts) { + String val = instruction.getAttribute(att); + if (val.length() > 0) { + templates = tf.newTemplates(getSource(att, val)); + break; + } + } + Element stylesheet = DomUtils.getElementByTagNameNS(instruction, Test.XSL_NS, "stylesheet"); + if (stylesheet == null) { + stylesheet = DomUtils.getElementByTagNameNS(instruction, Test.XSL_NS, "transform"); + } + if (stylesheet != null) { + templates = tf.newTemplates(new DOMSource(stylesheet)); + } + List children = DomUtils.getChildElements(instruction); + for (Element e : children) { + if (e.getLocalName().equals("property") && e.getNamespaceURI().equals(Test.CTLP_NS)) { + properties.put(e.getAttribute("name"), e.getTextContent()); + } + if (e.getLocalName().equals("with-param") && e.getNamespaceURI().equals(Test.CTLP_NS)) { + params.put(e.getAttribute("name"), e.getTextContent()); + } + } + String ignoreErrorsAtt = instruction.getAttribute("ignoreErrors"); + if (ignoreErrorsAtt != null) { + ignoreErrors = Boolean.parseBoolean(ignoreErrorsAtt); + } + String ignoreWarningsAtt = instruction.getAttribute("ignoreWarnings"); + if (ignoreWarningsAtt != null) { + ignoreWarnings = Boolean.parseBoolean(ignoreWarningsAtt); + } + return templates; + } + + public Document parse(URLConnection uc, Element instruction, PrintWriter logger) throws Exception { + HashMap properties = new HashMap<>(defaultProperties); + HashMap params = new HashMap<>(defaultParams); + Boolean ignoreErrors = defaultIgnoreErrors; + Boolean ignoreWarnings = defaultIgnoreWarnings; + Templates templates = parseInstruction(instruction, properties, params, ignoreErrors, ignoreWarnings); + Transformer t = null; + if (templates != null) { + t = templates.newTransformer(); + } + else if (defaultTemplates != null) { + t = defaultTemplates.newTransformer(); + } + else { + t = tf.newTransformer(); + } + for (Entry prop : properties.entrySet()) { + t.setOutputProperty(prop.getKey(), prop.getValue()); + } + for (Entry param : params.entrySet()) { + t.setParameter(param.getKey(), param.getValue()); + } + XSLTransformationErrorHandler el = new XSLTransformationErrorHandler(logger, ignoreErrors, ignoreWarnings); + t.setErrorListener(el); + Document doc = db.newDocument(); + InputStream is = null; + try { + if (LOGR.isLoggable(Level.FINER)) { + String msg = String.format("Attempting to transform source from %s using instruction set:%n %s", + uc.getURL(), DomUtils.serializeNode(instruction)); + LOGR.finer(msg); + } + // may return error stream + is = URLConnectionUtils.getInputStream(uc); + t.transform(new StreamSource(is), new DOMResult(doc)); + } + catch (TransformerException e) { + el.error(e); + } + finally { + if (null != is) + is.close(); + } + if (el.getErrorCount() > 0 && !ignoreErrors) { + return null; + } + if (el.getWarningCount() > 0 && !ignoreWarnings) { + return null; + } + return doc; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/XmlErrorHandler.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/XmlErrorHandler.java index f285d2e06..f0610d39b 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/XmlErrorHandler.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/XmlErrorHandler.java @@ -1,241 +1,261 @@ -/** - * ******************************************************************************** - * - * Version Date: January 8, 2018 - * - * Contributor(s): - * C. Heazel (WiSC): Applied mofications to address Fortify issues - * - * ******************************************************************************** - */ - -package com.occamlab.te.parsers; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.ErrorHandler; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; - -/** - * A SAX error handler that collects validation errors raised while verifying the - * structure and content of XML entities. - * - */ -public class XmlErrorHandler implements ErrorHandler { - - /** Storage for error messages. */ - private StringBuffer buf = new StringBuffer(); - - /** Collection of reported validation errors. */ - private List errors = new ArrayList<>(); - - private static Logger jlogger = Logger.getLogger("com.occamlab.te.parsers.XmlErrorHandler"); - - /** - * Indicates whether any validation errors have been reported. - * @return true if any validation errors have been received. - */ - public boolean isEmpty() { - return errors.isEmpty(); - } - - /** - * Receive notification of a warning. - * @param spex a non-error condition reported by the parser - * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException) - */ - public void warning(SAXParseException spex) { - addError(ValidationError.WARNING, spex); - } - - /** - * Receive notification of a recoverable error. Typically this indicates that a - * validation constraint has been violated. - * @param spex a non-fatal error condition reported by the parser - * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException) - */ - public void error(SAXParseException spex) { - addError(ValidationError.ERROR, spex); - } - - /** - * Prints the error to STDOUT, used to be consistent with TEAM Engine error handler. - * - */ - void printError(String type, SAXParseException e) { - PrintWriter logger = new PrintWriter(System.out); - logger.print(type); - if (e.getLineNumber() >= 0) { - logger.print(" at line " + e.getLineNumber()); - if (e.getColumnNumber() >= 0) { - logger.print(", column " + e.getColumnNumber()); - } - if (e.getSystemId() != null) { - logger.print(" of " + e.getSystemId()); - } - } - else { - if (e.getSystemId() != null) { - logger.print(" in " + e.getSystemId()); - } - } - logger.println(":"); - logger.println(" " + e.getMessage()); - logger.flush(); - } - - /** - * Receive notification of a non-recoverable error, such as a violation of the - * well-formedness constraint. - * @param spex a fatal error condition reported by the parser - * @throws SAXException if a fatal error (e.g., non-XML input, or ill-formed XML) - * occurs while parsing the input - * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException) - */ - public void fatalError(SAXParseException spex) throws SAXException { - - addError(ValidationError.FATAL_ERROR, spex); - throw new SAXException("Fatal error while parsing input."); - } - - /** - * Adds a validation error based on a SAXParseException. - * @param severity the severity of the error - * @param spex the SAXParseException raised while validating the XML - * source - */ - private void addError(short severity, SAXParseException spex) { - if (spex.getLineNumber() > 0) { - buf.append("Line " + spex.getLineNumber() + " - "); - } - buf.append(spex.getMessage() + "\n"); - ValidationError error = new ValidationError(severity, buf.toString()); - errors.add(error); - buf.setLength(0); - } - - /** - * Returns a concatenation of all received error messages. - * @return a consolidated error message - */ - public String toString() { - buf.setLength(0); - ErrorIterator errIterator = iterator(); - while (errIterator.hasNext()) { - ValidationError err = errIterator.next(); - buf.append(err.getMessage()); - } - return buf.toString(); - } - - /** - * Returns a list of errors as strings. - * @return a list of error strings. - */ - public List toList() { - - List errorStrings = new ArrayList<>(); - ErrorIterator errIterator = iterator(); - while (errIterator.hasNext()) { - ValidationError err = errIterator.next(); - errorStrings.add(err.getMessage()); - } - return errorStrings; - } - - /** - * Returns validation errors in a root container node. The root container - * ({@code }) contains a list of {@code } elements containing error - * messages as text content. - * @return Root element containing list of errors - */ - public Element toRootElement() { - Document doc = null; - try { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - DocumentBuilder db = dbf.newDocumentBuilder(); - doc = db.newDocument(); - } - catch (Exception e) { - jlogger.log(Level.SEVERE, "validate", e); - e.printStackTrace(); - // Fortify Mod: if we get here then there is no point in going further - return null; - } - Element root = doc.createElement("errors"); - doc.appendChild(root); - ErrorIterator errIterator = iterator(); - while (errIterator.hasNext()) { - ValidationError err = errIterator.next(); - Element elem = doc.createElement("error"); - elem.setTextContent(err.getMessage()); - root.appendChild(elem); - } - return root; - } - - /** - * Returns validation errors in a NodeList (needed for CTL processing). Each item in - * the list is an {@code } element containing an error message as text content. - * @return a list of errors in a NodeList. - */ - public NodeList toNodeList() { - return toRootElement().getElementsByTagName("error"); - } - - /** - * Returns an iterator over the validation errors collected by this handler. - * @return a read-only ErrorIterator for this handler - */ - public ErrorIterator iterator() { - return new ErrorIterator(); - } - - /** - * Clears all errors and messages. - */ - public void reset() { - buf.setLength(0); - errors.clear(); - } - - /** - * Helper class that provides a read-only iterator over validation errors. - */ - public class ErrorIterator { - - /** The underlying errors for this iterator. */ - Iterator underlying = errors.iterator(); - - /** - * Indicates if more errors remain in the iteration. - * @return true if more errors remain. - */ - public boolean hasNext() { - return underlying.hasNext(); - } - - /** - * Returns the next validation error in the iteration. - * @return the next error - */ - public ValidationError next() { - return (ValidationError) underlying.next(); - } - - } - -} +/** + * ******************************************************************************** + * + * Version Date: January 8, 2018 + * + * Contributor(s): + * C. Heazel (WiSC): Applied mofications to address Fortify issues + * + * ******************************************************************************** + */ + +package com.occamlab.te.parsers; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +/** + * A SAX error handler that collects validation errors raised while verifying the + * structure and content of XML entities. + * + */ +public class XmlErrorHandler implements ErrorHandler { + + /** Storage for error messages. */ + private StringBuffer buf = new StringBuffer(); + + /** Collection of reported validation errors. */ + private List errors = new ArrayList<>(); + + private static Logger jlogger = Logger.getLogger("com.occamlab.te.parsers.XmlErrorHandler"); + + /** + * Indicates whether any validation errors have been reported. + * @return true if any validation errors have been received. + */ + public boolean isEmpty() { + return errors.isEmpty(); + } + + /** + * Receive notification of a warning. + * @param spex a non-error condition reported by the parser + * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException) + */ + public void warning(SAXParseException spex) { + addError(ValidationError.WARNING, spex); + } + + /** + * Receive notification of a recoverable error. Typically this indicates that a + * validation constraint has been violated. + * @param spex a non-fatal error condition reported by the parser + * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException) + */ + public void error(SAXParseException spex) { + addError(ValidationError.ERROR, spex); + } + + /** + * Prints the error to STDOUT, used to be consistent with TEAM Engine error handler. + * + */ + void printError(String type, SAXParseException e) { + PrintWriter logger = new PrintWriter(System.out); + logger.print(type); + if (e.getLineNumber() >= 0) { + logger.print(" at line " + e.getLineNumber()); + if (e.getColumnNumber() >= 0) { + logger.print(", column " + e.getColumnNumber()); + } + if (e.getSystemId() != null) { + logger.print(" of " + e.getSystemId()); + } + } + else { + if (e.getSystemId() != null) { + logger.print(" in " + e.getSystemId()); + } + } + logger.println(":"); + logger.println(" " + e.getMessage()); + logger.flush(); + } + + /** + * Receive notification of a non-recoverable error, such as a violation of the + * well-formedness constraint. + * @param spex a fatal error condition reported by the parser + * @throws SAXException if a fatal error (e.g., non-XML input, or ill-formed XML) + * occurs while parsing the input + * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException) + */ + public void fatalError(SAXParseException spex) throws SAXException { + + addError(ValidationError.FATAL_ERROR, spex); + throw new SAXException("Fatal error while parsing input."); + } + + /** + * Adds a validation error based on a SAXParseException. + * @param severity the severity of the error + * @param spex the SAXParseException raised while validating the XML + * source + */ + private void addError(short severity, SAXParseException spex) { + if (spex.getLineNumber() > 0) { + buf.append("Line " + spex.getLineNumber() + " - "); + } + buf.append(spex.getMessage() + "\n"); + ValidationError error = new ValidationError(severity, buf.toString()); + errors.add(error); + buf.setLength(0); + } + + /** + * Returns a concatenation of all received error messages. + * @return a consolidated error message + */ + public String toString() { + buf.setLength(0); + ErrorIterator errIterator = iterator(); + while (errIterator.hasNext()) { + ValidationError err = errIterator.next(); + buf.append(err.getMessage()); + } + return buf.toString(); + } + + /** + * Returns a list of errors as strings. + * @return a list of error strings. + */ + public List toList() { + + List errorStrings = new ArrayList<>(); + ErrorIterator errIterator = iterator(); + while (errIterator.hasNext()) { + ValidationError err = errIterator.next(); + errorStrings.add(err.getMessage()); + } + return errorStrings; + } + + /** + * Returns validation errors in a root container node. The root container + * ({@code }) contains a list of {@code } elements containing error + * messages as text content. + * @return Root element containing list of errors + */ + public Element toRootElement() { + Document doc = null; + try { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + DocumentBuilder db = dbf.newDocumentBuilder(); + doc = db.newDocument(); + } + catch (Exception e) { + jlogger.log(Level.SEVERE, "validate", e); + e.printStackTrace(); + // Fortify Mod: if we get here then there is no point in going further + return null; + } + Element root = doc.createElement("errors"); + doc.appendChild(root); + ErrorIterator errIterator = iterator(); + while (errIterator.hasNext()) { + ValidationError err = errIterator.next(); + Element elem = doc.createElement("error"); + elem.setTextContent(err.getMessage()); + root.appendChild(elem); + } + return root; + } + + /** + * Returns validation errors in a NodeList (needed for CTL processing). Each item in + * the list is an {@code } element containing an error message as text content. + * @return a list of errors in a NodeList. + */ + public NodeList toNodeList() { + return toRootElement().getElementsByTagName("error"); + } + + /** + * Returns an iterator over the validation errors collected by this handler. + * @return a read-only ErrorIterator for this handler + */ + public ErrorIterator iterator() { + return new ErrorIterator(); + } + + /** + * Clears all errors and messages. + */ + public void reset() { + buf.setLength(0); + errors.clear(); + } + + /** + * Helper class that provides a read-only iterator over validation errors. + */ + public class ErrorIterator { + + /** The underlying errors for this iterator. */ + Iterator underlying = errors.iterator(); + + /** + * Indicates if more errors remain in the iteration. + * @return true if more errors remain. + */ + public boolean hasNext() { + return underlying.hasNext(); + } + + /** + * Returns the next validation error in the iteration. + * @return the next error + */ + public ValidationError next() { + return (ValidationError) underlying.next(); + } + + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/ZipParser.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/ZipParser.java index b84f63f24..12844d2a6 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/ZipParser.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/ZipParser.java @@ -1,266 +1,286 @@ -/** - * ******************************************************************** - * - * Version Date: January 5, 2018 - * - * Contributor(s): - * C. Heazel (WiSC) Modifications to address Fortify issues - - * Chuck Heazel (WiSC): Modifications to address Fortify issues - * Made parse() and saveZipFile() private to discourage their use. - */ -package com.occamlab.te.parsers; - -import java.io.*; -import java.net.URLConnection; - -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import java.util.Random; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.occamlab.te.util.Utils; - -/** - * Parses a zip file input by extracting the contents into the directory specified by the - * value of the <code>java.io.tmpdir</code> system property. The resulting - * manifest is structured as follows: - * - * <ctl:manifest xmlns:ctl="http://www.occamlab.com/ctl"> <ctl:file-entry - * full-path="${java.io.tmpdir}/dir/doc.kml" size="2048" /> </ctl:manifest> - * - * @author jparrpearson - */ -public class ZipParser { - - public static final String PARSERS_NS = "http://www.occamlab.com/te/parsers"; - - public static final String CTL_NS = "http://www.occamlab.com/ctl"; - - // Add more mime types as necessary, if mime type not listed a default will - // be given - public static String[][] ApplicationMediaTypeMappings = { { "kml", "vnd.google-earth.kml+xml" }, - { "kmz", "vnd.google-earth.kmz" }, { "xml", "application/xml" }, { "txt", "text/plain" }, - { "jpg", "image/jpeg" }, { "jpeg", "image/jpeg" }, { "gif", "image/gif" }, { "png", "image/png" } }; - - private static Logger jlogger = Logger.getLogger("com.occamlab.te.parsers.ZipParser"); - - /** - * Returns the mime media type value for the given extension - * @param ext the filename extension to lookup - * @return String the mime type for the given extension - */ - public static String getMediaType(String ext) { - String mediaType = ""; - - // Find the media type value in the lookup table - for (int i = 0; i < ApplicationMediaTypeMappings.length; i++) { - if (ApplicationMediaTypeMappings[i][0].equals(ext.toLowerCase())) { - mediaType = ApplicationMediaTypeMappings[i][1]; - } - } - - // Give the media type default of "application/octet-stream" - if (mediaType.isEmpty()) { - mediaType = "application/octet-stream"; - } - - return mediaType; - } - - /** - * Parses the entity (a ZIP archive) obtained in response to submitting a request to - * some URL. The resulting manifest is an XML document with <ctl:manifest> as - * the document element. - * @param resp the response to parse - * @param instruction a DOM Element representation of configuration information for - * this parser - * @param logger the test logger - * @return a DOM Document representing the manifest of items in the archive. - * @throws Throwable - */ - // Fortify Mod: made private - private static Document parse(URLConnection uc, Element instruction, PrintWriter logger) throws Throwable { - return parse(uc.getInputStream(), instruction, logger); - } - - private static Document parse(InputStream is, Element instruction, PrintWriter logger) throws Throwable { - - // Create the response element, - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.newDocument(); - Element root = doc.createElementNS(CTL_NS, "manifest"); - - // Open the connection to the zip file - ZipInputStream zis = new ZipInputStream(is); - - // Create the full directory path to store the zip entities - Document d = instruction.getOwnerDocument(); - NodeList nodes = d.getElementsByTagNameNS(CTL_NS, "SessionDir"); - // Either use the given session directory, or make one in the java temp - // directory - String path = ""; - if (nodes.getLength() > 0) { - Element e = (Element) nodes.item(0); - path = e.getTextContent(); - } - else { - path = System.getProperty("java.io.tmpdir") + "/zipparser.temp"; - } - String randomStr = Utils.randomString(16, new Random()); - path = path + "/work/" + randomStr; - new File(path).mkdirs(); - - // Unzip the file to a temporary location (java temp) - ZipEntry entry = null; - while ((entry = zis.getNextEntry()) != null) { - // Open the output file and get info from it - String filename = entry.getName(); - long size = entry.getSize(); - String ext = filename.substring(filename.lastIndexOf(".") + 1); - String mediaType = getMediaType(ext); - // Make the temp directory and subdirectories if needed - String subdir = ""; - if (filename.lastIndexOf("/") != -1) - subdir = filename.substring(0, filename.lastIndexOf("/")); - else if (filename.lastIndexOf("\\") != -1) - subdir = filename.substring(0, filename.lastIndexOf("\\")); - new File(path, subdir).mkdirs(); - File outFile = new File(path, filename); - if (!outFile.toPath().normalize().startsWith(path)) { - throw new IOException("Bad zip entry"); - } - if (outFile.isDirectory()) - continue; - OutputStream out = new FileOutputStream(outFile); - - // Transfer bytes from the ZIP file to the output file - byte[] buf = new byte[1024]; - int len; - while ((len = zis.read(buf)) > 0) { - out.write(buf, 0, len); - } - // Fortify Mod: Close the OutputStream and release its resources - out.close(); - - // Add the file information to the document - Element fileEntry = doc.createElementNS(CTL_NS, "file-entry"); - fileEntry.setAttribute("full-path", outFile.getPath().replace('\\', '/')); - fileEntry.setAttribute("media-type", mediaType); - fileEntry.setAttribute("size", String.valueOf(size)); - root.appendChild(fileEntry); - } - - doc.appendChild(root); - - // Return the document - return doc; - } - - /** - * Extracts the local Zip file and saves to the working directory. The resulting - * manifest is an XML document with <ctl:manifest> as the document element. - * @param path the full path to the local Zip file - * @param instruction a DOM Element representation of configuration information for - * this parser - * @return a DOM Document representing the manifest of items in the archive. - */ - - // Fortify Mod - made private - private Document saveZipFile(String filepath, Document instruction) throws Exception { - - // Get a connection to the Zip file - FileInputStream is = null; - ZipInputStream zis = null; - try { - is = new FileInputStream(filepath); - zis = new ZipInputStream(is); - } - catch (Exception e) { - jlogger.log(Level.SEVERE, "saveZipFile", e); - - System.out.println("ERROR: " + e.getMessage()); - return null; - } - - // Create the response element, - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.newDocument(); - Element root = doc.createElementNS(CTL_NS, "manifest"); - - // Create the full directory path to store the zip entities - Document d = instruction.getOwnerDocument(); - NodeList nodes = d.getElementsByTagNameNS(CTL_NS, "SessionDir"); - // Either use the given session directory, or make one in the java temp - // directory - String path = ""; - if (nodes.getLength() > 0) { - Element e = (Element) nodes.item(0); - path = e.getTextContent(); - } - else { - path = System.getProperty("java.io.tmpdir") + "/zipparser.temp"; - } - String randomStr = Utils.randomString(16, new Random()); - path = path + "/work/" + randomStr; - new File(path).mkdirs(); - - // Unzip the file to a temporary location (java temp) - ZipEntry entry = null; - while ((entry = zis.getNextEntry()) != null) { - System.out.println("File: " + entry.getName()); - // Open the output file and get info from it - String filename = entry.getName(); - long size = entry.getSize(); - String ext = filename.substring(filename.lastIndexOf(".") + 1); - String mediaType = getMediaType(ext); - // Make the temp directory and subdirectories if needed - String subdir = ""; - if (filename.lastIndexOf("/") != -1) - subdir = filename.substring(0, filename.lastIndexOf("/")); - else if (filename.lastIndexOf("\\") != -1) - subdir = filename.substring(0, filename.lastIndexOf("\\")); - new File(path, subdir).mkdirs(); - File outFile = new File(path, filename); - if (!outFile.toPath().normalize().startsWith(path)) { - throw new IOException("Bad zip entry"); - } - if (outFile.isDirectory()) - continue; - OutputStream out = new FileOutputStream(outFile); - - // Transfer bytes from the ZIP file to the output file - byte[] buf = new byte[1024]; - int len; - while ((len = zis.read(buf)) > 0) { - out.write(buf, 0, len); - } - // Fortify Mod: close the OutputStream and release its resources - out.close(); - - // Add the file information to the document - Element fileEntry = doc.createElementNS(CTL_NS, "file-entry"); - fileEntry.setAttribute("full-path", outFile.getPath().replace('\\', '/')); - fileEntry.setAttribute("media-type", mediaType); - fileEntry.setAttribute("size", String.valueOf(size)); - root.appendChild(fileEntry); - } - // Fortify Mod: Close the ZipInputStream and release resources - zis.close(); - - doc.appendChild(root); - - // Return the document - return doc; - } - -} +/** + * ******************************************************************** + * + * Version Date: January 5, 2018 + * + * Contributor(s): + * C. Heazel (WiSC) Modifications to address Fortify issues + + * Chuck Heazel (WiSC): Modifications to address Fortify issues + * Made parse() and saveZipFile() private to discourage their use. + */ +package com.occamlab.te.parsers; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.*; +import java.net.URLConnection; + +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.Random; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.occamlab.te.util.Utils; + +/** + * Parses a zip file input by extracting the contents into the directory specified by the + * value of the <code>java.io.tmpdir</code> system property. The resulting + * manifest is structured as follows: + * + * <ctl:manifest xmlns:ctl="http://www.occamlab.com/ctl"> <ctl:file-entry + * full-path="${java.io.tmpdir}/dir/doc.kml" size="2048" /> </ctl:manifest> + * + * @author jparrpearson + */ +public class ZipParser { + + public static final String PARSERS_NS = "http://www.occamlab.com/te/parsers"; + + public static final String CTL_NS = "http://www.occamlab.com/ctl"; + + // Add more mime types as necessary, if mime type not listed a default will + // be given + public static String[][] ApplicationMediaTypeMappings = { { "kml", "vnd.google-earth.kml+xml" }, + { "kmz", "vnd.google-earth.kmz" }, { "xml", "application/xml" }, { "txt", "text/plain" }, + { "jpg", "image/jpeg" }, { "jpeg", "image/jpeg" }, { "gif", "image/gif" }, { "png", "image/png" } }; + + private static Logger jlogger = Logger.getLogger("com.occamlab.te.parsers.ZipParser"); + + /** + * Returns the mime media type value for the given extension + * @param ext the filename extension to lookup + * @return String the mime type for the given extension + */ + public static String getMediaType(String ext) { + String mediaType = ""; + + // Find the media type value in the lookup table + for (int i = 0; i < ApplicationMediaTypeMappings.length; i++) { + if (ApplicationMediaTypeMappings[i][0].equals(ext.toLowerCase())) { + mediaType = ApplicationMediaTypeMappings[i][1]; + } + } + + // Give the media type default of "application/octet-stream" + if (mediaType.isEmpty()) { + mediaType = "application/octet-stream"; + } + + return mediaType; + } + + /** + * Parses the entity (a ZIP archive) obtained in response to submitting a request to + * some URL. The resulting manifest is an XML document with <ctl:manifest> as + * the document element. + * @param resp the response to parse + * @param instruction a DOM Element representation of configuration information for + * this parser + * @param logger the test logger + * @return a DOM Document representing the manifest of items in the archive. + * @throws Throwable + */ + // Fortify Mod: made private + private static Document parse(URLConnection uc, Element instruction, PrintWriter logger) throws Throwable { + return parse(uc.getInputStream(), instruction, logger); + } + + private static Document parse(InputStream is, Element instruction, PrintWriter logger) throws Throwable { + + // Create the response element, + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.newDocument(); + Element root = doc.createElementNS(CTL_NS, "manifest"); + + // Open the connection to the zip file + ZipInputStream zis = new ZipInputStream(is); + + // Create the full directory path to store the zip entities + Document d = instruction.getOwnerDocument(); + NodeList nodes = d.getElementsByTagNameNS(CTL_NS, "SessionDir"); + // Either use the given session directory, or make one in the java temp + // directory + String path = ""; + if (nodes.getLength() > 0) { + Element e = (Element) nodes.item(0); + path = e.getTextContent(); + } + else { + path = System.getProperty("java.io.tmpdir") + "/zipparser.temp"; + } + String randomStr = Utils.randomString(16, new Random()); + path = path + "/work/" + randomStr; + new File(path).mkdirs(); + + // Unzip the file to a temporary location (java temp) + ZipEntry entry = null; + while ((entry = zis.getNextEntry()) != null) { + // Open the output file and get info from it + String filename = entry.getName(); + long size = entry.getSize(); + String ext = filename.substring(filename.lastIndexOf(".") + 1); + String mediaType = getMediaType(ext); + // Make the temp directory and subdirectories if needed + String subdir = ""; + if (filename.lastIndexOf("/") != -1) + subdir = filename.substring(0, filename.lastIndexOf("/")); + else if (filename.lastIndexOf("\\") != -1) + subdir = filename.substring(0, filename.lastIndexOf("\\")); + new File(path, subdir).mkdirs(); + File outFile = new File(path, filename); + if (!outFile.toPath().normalize().startsWith(path)) { + throw new IOException("Bad zip entry"); + } + if (outFile.isDirectory()) + continue; + OutputStream out = new FileOutputStream(outFile); + + // Transfer bytes from the ZIP file to the output file + byte[] buf = new byte[1024]; + int len; + while ((len = zis.read(buf)) > 0) { + out.write(buf, 0, len); + } + // Fortify Mod: Close the OutputStream and release its resources + out.close(); + + // Add the file information to the document + Element fileEntry = doc.createElementNS(CTL_NS, "file-entry"); + fileEntry.setAttribute("full-path", outFile.getPath().replace('\\', '/')); + fileEntry.setAttribute("media-type", mediaType); + fileEntry.setAttribute("size", String.valueOf(size)); + root.appendChild(fileEntry); + } + + doc.appendChild(root); + + // Return the document + return doc; + } + + /** + * Extracts the local Zip file and saves to the working directory. The resulting + * manifest is an XML document with <ctl:manifest> as the document element. + * @param path the full path to the local Zip file + * @param instruction a DOM Element representation of configuration information for + * this parser + * @return a DOM Document representing the manifest of items in the archive. + */ + + // Fortify Mod - made private + private Document saveZipFile(String filepath, Document instruction) throws Exception { + + // Get a connection to the Zip file + FileInputStream is = null; + ZipInputStream zis = null; + try { + is = new FileInputStream(filepath); + zis = new ZipInputStream(is); + } + catch (Exception e) { + jlogger.log(Level.SEVERE, "saveZipFile", e); + + System.out.println("ERROR: " + e.getMessage()); + return null; + } + + // Create the response element, + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.newDocument(); + Element root = doc.createElementNS(CTL_NS, "manifest"); + + // Create the full directory path to store the zip entities + Document d = instruction.getOwnerDocument(); + NodeList nodes = d.getElementsByTagNameNS(CTL_NS, "SessionDir"); + // Either use the given session directory, or make one in the java temp + // directory + String path = ""; + if (nodes.getLength() > 0) { + Element e = (Element) nodes.item(0); + path = e.getTextContent(); + } + else { + path = System.getProperty("java.io.tmpdir") + "/zipparser.temp"; + } + String randomStr = Utils.randomString(16, new Random()); + path = path + "/work/" + randomStr; + new File(path).mkdirs(); + + // Unzip the file to a temporary location (java temp) + ZipEntry entry = null; + while ((entry = zis.getNextEntry()) != null) { + System.out.println("File: " + entry.getName()); + // Open the output file and get info from it + String filename = entry.getName(); + long size = entry.getSize(); + String ext = filename.substring(filename.lastIndexOf(".") + 1); + String mediaType = getMediaType(ext); + // Make the temp directory and subdirectories if needed + String subdir = ""; + if (filename.lastIndexOf("/") != -1) + subdir = filename.substring(0, filename.lastIndexOf("/")); + else if (filename.lastIndexOf("\\") != -1) + subdir = filename.substring(0, filename.lastIndexOf("\\")); + new File(path, subdir).mkdirs(); + File outFile = new File(path, filename); + if (!outFile.toPath().normalize().startsWith(path)) { + throw new IOException("Bad zip entry"); + } + if (outFile.isDirectory()) + continue; + OutputStream out = new FileOutputStream(outFile); + + // Transfer bytes from the ZIP file to the output file + byte[] buf = new byte[1024]; + int len; + while ((len = zis.read(buf)) > 0) { + out.write(buf, 0, len); + } + // Fortify Mod: close the OutputStream and release its resources + out.close(); + + // Add the file information to the document + Element fileEntry = doc.createElementNS(CTL_NS, "file-entry"); + fileEntry.setAttribute("full-path", outFile.getPath().replace('\\', '/')); + fileEntry.setAttribute("media-type", mediaType); + fileEntry.setAttribute("size", String.valueOf(size)); + root.appendChild(fileEntry); + } + // Fortify Mod: Close the ZipInputStream and release resources + zis.close(); + + doc.appendChild(root); + + // Return the document + return doc; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/CachingSchemaLoader.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/CachingSchemaLoader.java index 0319af70f..db529264a 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/CachingSchemaLoader.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/CachingSchemaLoader.java @@ -1,5 +1,25 @@ package com.occamlab.te.parsers.xml; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.util.Objects; import java.util.concurrent.ExecutionException; diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/FileSchemaSupplier.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/FileSchemaSupplier.java index 76db345e0..03c818196 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/FileSchemaSupplier.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/FileSchemaSupplier.java @@ -1,5 +1,25 @@ package com.occamlab.te.parsers.xml; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.File; import java.util.Objects; diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/InMemorySchemaSupplier.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/InMemorySchemaSupplier.java index c465ff6fb..cfa029799 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/InMemorySchemaSupplier.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/InMemorySchemaSupplier.java @@ -1,5 +1,25 @@ package com.occamlab.te.parsers.xml; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.CharArrayReader; import java.util.Arrays; import java.util.Objects; diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/SchemaLoader.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/SchemaLoader.java index fdee81b27..51ecbd70e 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/SchemaLoader.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/SchemaLoader.java @@ -1,5 +1,25 @@ package com.occamlab.te.parsers.xml; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import javax.xml.validation.Schema; import org.xml.sax.SAXException; @@ -29,4 +49,4 @@ public interface SchemaLoader { */ Schema defaultSchema() throws SAXException; -} \ No newline at end of file +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/SchemaSupplier.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/SchemaSupplier.java index 9e728ef4c..a2885f413 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/SchemaSupplier.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/SchemaSupplier.java @@ -1,5 +1,25 @@ package com.occamlab.te.parsers.xml; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.File; import java.net.URL; diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/UrlSchemaSupplier.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/UrlSchemaSupplier.java index 5e9c3d486..79ed8c6cb 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/UrlSchemaSupplier.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/UrlSchemaSupplier.java @@ -1,5 +1,25 @@ package com.occamlab.te.parsers.xml; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.net.URL; import java.util.Objects; diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/XsdSchemaLoader.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/XsdSchemaLoader.java index 2fbf08aa3..36bdb3cff 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/XsdSchemaLoader.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/XsdSchemaLoader.java @@ -1,5 +1,25 @@ package com.occamlab.te.parsers.xml; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.util.logging.Logger; import javax.xml.XMLConstants; diff --git a/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/package-info.java b/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/package-info.java index 46284860a..d594b739b 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/package-info.java +++ b/teamengine-core/src/main/java/com/occamlab/te/parsers/xml/package-info.java @@ -1,4 +1,23 @@ /** * Classes providing XML-related functionality for parsers. */ -package com.occamlab.te.parsers.xml; \ No newline at end of file +package com.occamlab.te.parsers.xml; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ diff --git a/teamengine-core/src/main/java/com/occamlab/te/saxon/GetTypeFunctionCall.java b/teamengine-core/src/main/java/com/occamlab/te/saxon/GetTypeFunctionCall.java index 61b5e3beb..7050328b5 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/saxon/GetTypeFunctionCall.java +++ b/teamengine-core/src/main/java/com/occamlab/te/saxon/GetTypeFunctionCall.java @@ -1,49 +1,69 @@ -package com.occamlab.te.saxon; - -import java.util.List; - -import javax.xml.namespace.QName; - -import net.sf.saxon.expr.Expression; -import net.sf.saxon.expr.ExpressionTool; -import net.sf.saxon.expr.StaticContext; -import net.sf.saxon.expr.XPathContext; -import net.sf.saxon.om.SequenceIterator; -import net.sf.saxon.om.StructuredQName; -import net.sf.saxon.om.ValueRepresentation; -import net.sf.saxon.trans.XPathException; -import net.sf.saxon.type.ItemType; -import net.sf.saxon.type.SchemaType; -import net.sf.saxon.type.TypeHierarchy; -import net.sf.saxon.value.SequenceType; -import net.sf.saxon.value.Value; - -public class GetTypeFunctionCall extends TEFunctionCall { - - List params = null; - - boolean usesContext = false; - - TypeHierarchy th; - - public GetTypeFunctionCall(StructuredQName functionName, Expression[] staticArgs, StaticContext env) { - super(functionName, staticArgs, env); - } - - public static String getTypeName(ItemType it) throws XPathException { - if (it instanceof SchemaType) { - return "xs:" + ((SchemaType) it).getName(); - } - return it.toString(); - } - - public SequenceIterator iterate(XPathContext context) throws XPathException { - Expression[] argExpressions = getArguments(); - ValueRepresentation vr = ExpressionTool.lazyEvaluate(argExpressions[0], context, 1); - ItemType it = Value.asValue(vr).getItemType(context.getConfiguration().getTypeHierarchy()); - String type = getTypeName(it); - Value v = Value.convertJavaObjectToXPath(type, SequenceType.SINGLE_STRING, context); - return v.iterate(); - } - -} +package com.occamlab.te.saxon; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.List; + +import javax.xml.namespace.QName; + +import net.sf.saxon.expr.Expression; +import net.sf.saxon.expr.ExpressionTool; +import net.sf.saxon.expr.StaticContext; +import net.sf.saxon.expr.XPathContext; +import net.sf.saxon.om.SequenceIterator; +import net.sf.saxon.om.StructuredQName; +import net.sf.saxon.om.ValueRepresentation; +import net.sf.saxon.trans.XPathException; +import net.sf.saxon.type.ItemType; +import net.sf.saxon.type.SchemaType; +import net.sf.saxon.type.TypeHierarchy; +import net.sf.saxon.value.SequenceType; +import net.sf.saxon.value.Value; + +public class GetTypeFunctionCall extends TEFunctionCall { + + List params = null; + + boolean usesContext = false; + + TypeHierarchy th; + + public GetTypeFunctionCall(StructuredQName functionName, Expression[] staticArgs, StaticContext env) { + super(functionName, staticArgs, env); + } + + public static String getTypeName(ItemType it) throws XPathException { + if (it instanceof SchemaType) { + return "xs:" + ((SchemaType) it).getName(); + } + return it.toString(); + } + + public SequenceIterator iterate(XPathContext context) throws XPathException { + Expression[] argExpressions = getArguments(); + ValueRepresentation vr = ExpressionTool.lazyEvaluate(argExpressions[0], context, 1); + ItemType it = Value.asValue(vr).getItemType(context.getConfiguration().getTypeHierarchy()); + String type = getTypeName(it); + Value v = Value.convertJavaObjectToXPath(type, SequenceType.SINGLE_STRING, context); + return v.iterate(); + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/saxon/ObjValue.java b/teamengine-core/src/main/java/com/occamlab/te/saxon/ObjValue.java index 3240a70a7..71ff4d213 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/saxon/ObjValue.java +++ b/teamengine-core/src/main/java/com/occamlab/te/saxon/ObjValue.java @@ -1,12 +1,32 @@ -package com.occamlab.te.saxon; - -import net.sf.saxon.s9api.XdmValue; -import net.sf.saxon.value.ObjectValue; - -public class ObjValue extends XdmValue { - - public ObjValue(Object o) { - super(new ObjectValue(o)); - } - -} +package com.occamlab.te.saxon; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import net.sf.saxon.s9api.XdmValue; +import net.sf.saxon.value.ObjectValue; + +public class ObjValue extends XdmValue { + + public ObjValue(Object o) { + super(new ObjectValue(o)); + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/saxon/TEFunctionCall.java b/teamengine-core/src/main/java/com/occamlab/te/saxon/TEFunctionCall.java index ffce4144a..949c0ed01 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/saxon/TEFunctionCall.java +++ b/teamengine-core/src/main/java/com/occamlab/te/saxon/TEFunctionCall.java @@ -1,46 +1,66 @@ -package com.occamlab.te.saxon; - -import net.sf.saxon.expr.Expression; -import net.sf.saxon.expr.ExpressionVisitor; -import net.sf.saxon.expr.FunctionCall; -import net.sf.saxon.expr.StaticContext; -import net.sf.saxon.expr.StaticProperty; -import net.sf.saxon.om.StructuredQName; -import net.sf.saxon.trans.XPathException; -import net.sf.saxon.type.AnyItemType; -import net.sf.saxon.type.ItemType; -import net.sf.saxon.type.TypeHierarchy; - -public class TEFunctionCall extends FunctionCall { - - public TEFunctionCall(StructuredQName functionName, Expression[] staticArgs, StaticContext env) { - super(); - this.setFunctionName(functionName); - this.setArguments(staticArgs); - } - - public Expression preEvaluate(ExpressionVisitor visitor) { - return this; - } - - public int getImplementationMethod() { - return ITERATE_METHOD; - } - - protected void checkArguments(ExpressionVisitor visitor) throws XPathException { - // Assume arguments are OK - } - - protected int computeCardinality() { - return StaticProperty.ALLOWS_ZERO_OR_MORE; - } - - public Expression copy() { - throw new UnsupportedOperationException(); - } - - public ItemType getItemType(TypeHierarchy th) { - return AnyItemType.getInstance(); - } - -} +package com.occamlab.te.saxon; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import net.sf.saxon.expr.Expression; +import net.sf.saxon.expr.ExpressionVisitor; +import net.sf.saxon.expr.FunctionCall; +import net.sf.saxon.expr.StaticContext; +import net.sf.saxon.expr.StaticProperty; +import net.sf.saxon.om.StructuredQName; +import net.sf.saxon.trans.XPathException; +import net.sf.saxon.type.AnyItemType; +import net.sf.saxon.type.ItemType; +import net.sf.saxon.type.TypeHierarchy; + +public class TEFunctionCall extends FunctionCall { + + public TEFunctionCall(StructuredQName functionName, Expression[] staticArgs, StaticContext env) { + super(); + this.setFunctionName(functionName); + this.setArguments(staticArgs); + } + + public Expression preEvaluate(ExpressionVisitor visitor) { + return this; + } + + public int getImplementationMethod() { + return ITERATE_METHOD; + } + + protected void checkArguments(ExpressionVisitor visitor) throws XPathException { + // Assume arguments are OK + } + + protected int computeCardinality() { + return StaticProperty.ALLOWS_ZERO_OR_MORE; + } + + public Expression copy() { + throw new UnsupportedOperationException(); + } + + public ItemType getItemType(TypeHierarchy th) { + return AnyItemType.getInstance(); + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/saxon/TEFunctionLibrary.java b/teamengine-core/src/main/java/com/occamlab/te/saxon/TEFunctionLibrary.java index 56c2a00e9..78df36cba 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/saxon/TEFunctionLibrary.java +++ b/teamengine-core/src/main/java/com/occamlab/te/saxon/TEFunctionLibrary.java @@ -1,75 +1,95 @@ -package com.occamlab.te.saxon; - -import java.util.List; - -import net.sf.saxon.Configuration; -import net.sf.saxon.expr.Expression; -import net.sf.saxon.expr.StaticContext; -import net.sf.saxon.functions.FunctionLibrary; -import net.sf.saxon.om.StructuredQName; -import net.sf.saxon.trans.XPathException; - -import com.occamlab.te.Test; -import com.occamlab.te.index.FunctionEntry; -import com.occamlab.te.index.Index; - -public class TEFunctionLibrary implements FunctionLibrary { - - Configuration config = null; - - Index index = null; - - public TEFunctionLibrary(Configuration config, Index index) { - this.config = config; - this.index = index; - } - - public Expression bind(StructuredQName functionName, Expression[] staticArgs, StaticContext env) - throws XPathException { - if (functionName.getNamespaceURI().equals(Test.TE_NS) && functionName.getLocalName().equals("get-type")) { - return new GetTypeFunctionCall(functionName, staticArgs, env); - } - - String key = functionName.getClarkName(); - List functions = index.getFunctions(key); - int argCount = staticArgs.length; - - if (functions != null) { - for (FunctionEntry fe : functions) { - if (argCount >= fe.getMinArgs() && argCount <= fe.getMaxArgs()) { - if (fe.isJava()) { - return new TEJavaFunctionCall(fe, functionName, staticArgs, env); - } - else { - return new TEXSLFunctionCall(fe, functionName, staticArgs, env); - } - } - } - } - - // Just return null rather than throw an exception, because there may be - // another function library that supports this function - return null; - } - - public FunctionLibrary copy() { - return new TEFunctionLibrary(config, index); - } - - public boolean isAvailable(StructuredQName functionName, int arity) { - String key = functionName.getClarkName(); - List functions = index.getFunctions(key); - if (functions != null) { - for (FunctionEntry fe : functions) { - if (arity == -1) { - return true; - } - if (arity >= fe.getMinArgs() && arity <= fe.getMaxArgs()) { - return true; - } - } - } - return false; - } - -} +package com.occamlab.te.saxon; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.List; + +import net.sf.saxon.Configuration; +import net.sf.saxon.expr.Expression; +import net.sf.saxon.expr.StaticContext; +import net.sf.saxon.functions.FunctionLibrary; +import net.sf.saxon.om.StructuredQName; +import net.sf.saxon.trans.XPathException; + +import com.occamlab.te.Test; +import com.occamlab.te.index.FunctionEntry; +import com.occamlab.te.index.Index; + +public class TEFunctionLibrary implements FunctionLibrary { + + Configuration config = null; + + Index index = null; + + public TEFunctionLibrary(Configuration config, Index index) { + this.config = config; + this.index = index; + } + + public Expression bind(StructuredQName functionName, Expression[] staticArgs, StaticContext env) + throws XPathException { + if (functionName.getNamespaceURI().equals(Test.TE_NS) && functionName.getLocalName().equals("get-type")) { + return new GetTypeFunctionCall(functionName, staticArgs, env); + } + + String key = functionName.getClarkName(); + List functions = index.getFunctions(key); + int argCount = staticArgs.length; + + if (functions != null) { + for (FunctionEntry fe : functions) { + if (argCount >= fe.getMinArgs() && argCount <= fe.getMaxArgs()) { + if (fe.isJava()) { + return new TEJavaFunctionCall(fe, functionName, staticArgs, env); + } + else { + return new TEXSLFunctionCall(fe, functionName, staticArgs, env); + } + } + } + } + + // Just return null rather than throw an exception, because there may be + // another function library that supports this function + return null; + } + + public FunctionLibrary copy() { + return new TEFunctionLibrary(config, index); + } + + public boolean isAvailable(StructuredQName functionName, int arity) { + String key = functionName.getClarkName(); + List functions = index.getFunctions(key); + if (functions != null) { + for (FunctionEntry fe : functions) { + if (arity == -1) { + return true; + } + if (arity >= fe.getMinArgs() && arity <= fe.getMaxArgs()) { + return true; + } + } + } + return false; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/saxon/TEJavaFunctionCall.java b/teamengine-core/src/main/java/com/occamlab/te/saxon/TEJavaFunctionCall.java index 6371c8b9f..0f246ef1e 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/saxon/TEJavaFunctionCall.java +++ b/teamengine-core/src/main/java/com/occamlab/te/saxon/TEJavaFunctionCall.java @@ -1,115 +1,135 @@ -package com.occamlab.te.saxon; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import net.sf.saxon.Controller; -import net.sf.saxon.expr.Expression; -import net.sf.saxon.expr.ExpressionTool; -import net.sf.saxon.expr.StaticContext; -import net.sf.saxon.expr.XPathContext; -import net.sf.saxon.om.EmptyIterator; -import net.sf.saxon.om.SequenceIterator; -import net.sf.saxon.om.StructuredQName; -import net.sf.saxon.om.ValueRepresentation; -import net.sf.saxon.trans.XPathException; -import net.sf.saxon.value.ObjectValue; -import net.sf.saxon.value.SequenceType; -import net.sf.saxon.value.Value; - -import com.occamlab.te.TEClassLoader; -import com.occamlab.te.TECore; -import com.occamlab.te.Test; -import com.occamlab.te.index.FunctionEntry; -import com.occamlab.te.util.Misc; - -public class TEJavaFunctionCall extends TEFunctionCall { - - FunctionEntry fe; - - Method[] methods = null; - - public TEJavaFunctionCall(FunctionEntry fe, StructuredQName functionName, Expression[] staticArgs, - StaticContext env) throws XPathException { - super(functionName, staticArgs, env); - this.fe = fe; - } - - public SequenceIterator iterate(XPathContext context) throws XPathException { - Controller controller = context.getController(); - ObjectValue ov = (ObjectValue) controller.getParameter("{" + Test.TE_NS + "}core"); - TECore core = (TECore) ov.getObject(); - TEClassLoader cl = core.getEngine().getClassLoader(core.getOpts().getSourcesName()); - - if (methods == null) { - methods = new Method[fe.getMaxArgs() + 1]; - for (int i = fe.getMinArgs(); i <= fe.getMaxArgs(); i++) { - try { - methods[i] = Misc.getMethod(fe.getClassName(), fe.getMethod(), cl, i); - } - catch (Exception e) { - throw new XPathException("Error: Unable to bind function " + fe.getName(), e); - } - } - } - - Object instance = null; - if (fe.isInitialized()) { - instance = core.getFunctionInstance(fe.hashCode()); - if (instance == null) { - try { - instance = Misc.makeInstance(fe.getClassName(), fe.getClassParams(), cl); - core.putFunctionInstance(fe.hashCode(), instance); - } - catch (Exception e) { - throw new XPathException(e); - } - } - } - Expression[] argExpressions = getArguments(); - Object[] javaArgs = new Object[argExpressions.length]; - Method m; - Class[] types; - int argsIndex; - if (fe.usesContext()) { - m = methods[argExpressions.length + 1]; - types = m.getParameterTypes(); - ValueRepresentation vr = context.getContextItem(); - javaArgs[0] = Value.asValue(vr).convertToJava(types[0], context); - argsIndex = 1; - } - else { - m = methods[argExpressions.length]; - types = m.getParameterTypes(); - argsIndex = 0; - } - for (int i = 0; i < argExpressions.length; i++) { - ValueRepresentation vr = ExpressionTool.lazyEvaluate(argExpressions[i], context, 1); - javaArgs[argsIndex] = Value.asValue(vr).convertToJava(types[argsIndex], context); - argsIndex++; - } - Object result; - try { - result = m.invoke(instance, javaArgs); - } - catch (Exception e) { - Throwable cause = e; - if (e instanceof InvocationTargetException) { - cause = e.getCause(); - } - String msg = "Error invoking " + fe.getId() + "\n" + cause.getClass().getName(); - if (cause.getMessage() != null) { - msg += ": " + cause.getMessage(); - } - throw new XPathException(msg, cause); - } - if (result == null) { - return EmptyIterator.getInstance(); - } - else { - Value v = Value.convertJavaObjectToXPath(result, SequenceType.ANY_SEQUENCE, context); - return v.iterate(); - } - } - -} +package com.occamlab.te.saxon; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import net.sf.saxon.Controller; +import net.sf.saxon.expr.Expression; +import net.sf.saxon.expr.ExpressionTool; +import net.sf.saxon.expr.StaticContext; +import net.sf.saxon.expr.XPathContext; +import net.sf.saxon.om.EmptyIterator; +import net.sf.saxon.om.SequenceIterator; +import net.sf.saxon.om.StructuredQName; +import net.sf.saxon.om.ValueRepresentation; +import net.sf.saxon.trans.XPathException; +import net.sf.saxon.value.ObjectValue; +import net.sf.saxon.value.SequenceType; +import net.sf.saxon.value.Value; + +import com.occamlab.te.TEClassLoader; +import com.occamlab.te.TECore; +import com.occamlab.te.Test; +import com.occamlab.te.index.FunctionEntry; +import com.occamlab.te.util.Misc; + +public class TEJavaFunctionCall extends TEFunctionCall { + + FunctionEntry fe; + + Method[] methods = null; + + public TEJavaFunctionCall(FunctionEntry fe, StructuredQName functionName, Expression[] staticArgs, + StaticContext env) throws XPathException { + super(functionName, staticArgs, env); + this.fe = fe; + } + + public SequenceIterator iterate(XPathContext context) throws XPathException { + Controller controller = context.getController(); + ObjectValue ov = (ObjectValue) controller.getParameter("{" + Test.TE_NS + "}core"); + TECore core = (TECore) ov.getObject(); + TEClassLoader cl = core.getEngine().getClassLoader(core.getOpts().getSourcesName()); + + if (methods == null) { + methods = new Method[fe.getMaxArgs() + 1]; + for (int i = fe.getMinArgs(); i <= fe.getMaxArgs(); i++) { + try { + methods[i] = Misc.getMethod(fe.getClassName(), fe.getMethod(), cl, i); + } + catch (Exception e) { + throw new XPathException("Error: Unable to bind function " + fe.getName(), e); + } + } + } + + Object instance = null; + if (fe.isInitialized()) { + instance = core.getFunctionInstance(fe.hashCode()); + if (instance == null) { + try { + instance = Misc.makeInstance(fe.getClassName(), fe.getClassParams(), cl); + core.putFunctionInstance(fe.hashCode(), instance); + } + catch (Exception e) { + throw new XPathException(e); + } + } + } + Expression[] argExpressions = getArguments(); + Object[] javaArgs = new Object[argExpressions.length]; + Method m; + Class[] types; + int argsIndex; + if (fe.usesContext()) { + m = methods[argExpressions.length + 1]; + types = m.getParameterTypes(); + ValueRepresentation vr = context.getContextItem(); + javaArgs[0] = Value.asValue(vr).convertToJava(types[0], context); + argsIndex = 1; + } + else { + m = methods[argExpressions.length]; + types = m.getParameterTypes(); + argsIndex = 0; + } + for (int i = 0; i < argExpressions.length; i++) { + ValueRepresentation vr = ExpressionTool.lazyEvaluate(argExpressions[i], context, 1); + javaArgs[argsIndex] = Value.asValue(vr).convertToJava(types[argsIndex], context); + argsIndex++; + } + Object result; + try { + result = m.invoke(instance, javaArgs); + } + catch (Exception e) { + Throwable cause = e; + if (e instanceof InvocationTargetException) { + cause = e.getCause(); + } + String msg = "Error invoking " + fe.getId() + "\n" + cause.getClass().getName(); + if (cause.getMessage() != null) { + msg += ": " + cause.getMessage(); + } + throw new XPathException(msg, cause); + } + if (result == null) { + return EmptyIterator.getInstance(); + } + else { + Value v = Value.convertJavaObjectToXPath(result, SequenceType.ANY_SEQUENCE, context); + return v.iterate(); + } + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/saxon/TEXSLFunctionCall.java b/teamengine-core/src/main/java/com/occamlab/te/saxon/TEXSLFunctionCall.java index ca35a1d2c..16ba0d2d0 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/saxon/TEXSLFunctionCall.java +++ b/teamengine-core/src/main/java/com/occamlab/te/saxon/TEXSLFunctionCall.java @@ -1,127 +1,147 @@ -package com.occamlab.te.saxon; - -import static com.occamlab.te.saxon.GetTypeFunctionCall.getTypeName; - -import java.io.CharArrayReader; -import java.util.List; - -import javax.xml.namespace.QName; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - -import net.sf.saxon.Controller; -import net.sf.saxon.expr.Expression; -import net.sf.saxon.expr.ExpressionTool; -import net.sf.saxon.expr.StaticContext; -import net.sf.saxon.expr.XPathContext; -import net.sf.saxon.om.Axis; -import net.sf.saxon.om.EmptyIterator; -import net.sf.saxon.om.NodeInfo; -import net.sf.saxon.om.SequenceIterator; -import net.sf.saxon.om.StructuredQName; -import net.sf.saxon.om.ValueRepresentation; -import net.sf.saxon.trans.XPathException; -import net.sf.saxon.type.ItemType; -import net.sf.saxon.type.SchemaType; -import net.sf.saxon.value.ObjectValue; -import net.sf.saxon.value.Value; - -import org.w3c.dom.Attr; -import org.w3c.dom.Node; - -import com.occamlab.te.TECore; -import com.occamlab.te.Test; -import com.occamlab.te.index.FunctionEntry; -import com.occamlab.te.util.DomUtils; - -public class TEXSLFunctionCall extends TEFunctionCall { - - FunctionEntry fe; - - public TEXSLFunctionCall(FunctionEntry fe, StructuredQName functionName, Expression[] staticArgs, - StaticContext env) { - super(functionName, staticArgs, env); - this.fe = fe; - } - - public static String getType(Expression expr, XPathContext context) throws XPathException { - ValueRepresentation vr = ExpressionTool.lazyEvaluate(expr, context, 1); - ItemType it = Value.asValue(vr).getItemType(context.getConfiguration().getTypeHierarchy()); - if (it instanceof SchemaType) { - return "xs:" + ((SchemaType) it).getName(); - } - return "xs:any"; - } - - public SequenceIterator iterate(XPathContext context) throws XPathException { - Controller controller = context.getController(); - ObjectValue ov = (ObjectValue) controller.getParameter("{" + Test.TE_NS + "}core"); - TECore core = (TECore) ov.getObject(); - - Expression[] argExpressions = getArguments(); - String xml = "\n"; - List params = fe.getParams(); - for (int i = 0; i < params.size(); i++) { - QName param = params.get(i); - xml += "\n"; - xml += ""; - xml += DomUtils.serializeNode(n); - xml += "\n"; - } - else if (type == Node.DOCUMENT_NODE) { - xml += " type=\"document-node()\">\n"; - xml += ""; - xml += DomUtils.serializeNode(n); - xml += "\n"; - } - else { - ItemType it = v.getItemType(context.getConfiguration().getTypeHierarchy()); - xml += " type=\"" + getTypeName(it) + "\">\n"; - xml += "" + n.getNodeValue() + "\n"; - } - } - catch (Exception e) { - ItemType it = v.getItemType(context.getConfiguration().getTypeHierarchy()); - xml += " type=\"" + getTypeName(it) + "\">\n"; - xml += "" + v.getStringValue() + "\n"; - } - xml += "\n"; - } - xml += ""; - Source src = new StreamSource(new CharArrayReader(xml.toCharArray())); - NodeInfo result = null; - try { - NodeInfo paramsNode = core.getEngine().getBuilder().build(src).getUnderlyingNode(); - result = core.executeXSLFunction(context, fe, paramsNode); - } - catch (Exception e) { - throw new RuntimeException(e); - } - if (result == null) { - return EmptyIterator.getInstance(); - } - else { - return result.iterateAxis(Axis.CHILD); - } - } - -} +package com.occamlab.te.saxon; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import static com.occamlab.te.saxon.GetTypeFunctionCall.getTypeName; + +import java.io.CharArrayReader; +import java.util.List; + +import javax.xml.namespace.QName; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; + +import net.sf.saxon.Controller; +import net.sf.saxon.expr.Expression; +import net.sf.saxon.expr.ExpressionTool; +import net.sf.saxon.expr.StaticContext; +import net.sf.saxon.expr.XPathContext; +import net.sf.saxon.om.Axis; +import net.sf.saxon.om.EmptyIterator; +import net.sf.saxon.om.NodeInfo; +import net.sf.saxon.om.SequenceIterator; +import net.sf.saxon.om.StructuredQName; +import net.sf.saxon.om.ValueRepresentation; +import net.sf.saxon.trans.XPathException; +import net.sf.saxon.type.ItemType; +import net.sf.saxon.type.SchemaType; +import net.sf.saxon.value.ObjectValue; +import net.sf.saxon.value.Value; + +import org.w3c.dom.Attr; +import org.w3c.dom.Node; + +import com.occamlab.te.TECore; +import com.occamlab.te.Test; +import com.occamlab.te.index.FunctionEntry; +import com.occamlab.te.util.DomUtils; + +public class TEXSLFunctionCall extends TEFunctionCall { + + FunctionEntry fe; + + public TEXSLFunctionCall(FunctionEntry fe, StructuredQName functionName, Expression[] staticArgs, + StaticContext env) { + super(functionName, staticArgs, env); + this.fe = fe; + } + + public static String getType(Expression expr, XPathContext context) throws XPathException { + ValueRepresentation vr = ExpressionTool.lazyEvaluate(expr, context, 1); + ItemType it = Value.asValue(vr).getItemType(context.getConfiguration().getTypeHierarchy()); + if (it instanceof SchemaType) { + return "xs:" + ((SchemaType) it).getName(); + } + return "xs:any"; + } + + public SequenceIterator iterate(XPathContext context) throws XPathException { + Controller controller = context.getController(); + ObjectValue ov = (ObjectValue) controller.getParameter("{" + Test.TE_NS + "}core"); + TECore core = (TECore) ov.getObject(); + + Expression[] argExpressions = getArguments(); + String xml = "\n"; + List params = fe.getParams(); + for (int i = 0; i < params.size(); i++) { + QName param = params.get(i); + xml += "\n"; + xml += ""; + xml += DomUtils.serializeNode(n); + xml += "\n"; + } + else if (type == Node.DOCUMENT_NODE) { + xml += " type=\"document-node()\">\n"; + xml += ""; + xml += DomUtils.serializeNode(n); + xml += "\n"; + } + else { + ItemType it = v.getItemType(context.getConfiguration().getTypeHierarchy()); + xml += " type=\"" + getTypeName(it) + "\">\n"; + xml += "" + n.getNodeValue() + "\n"; + } + } + catch (Exception e) { + ItemType it = v.getItemType(context.getConfiguration().getTypeHierarchy()); + xml += " type=\"" + getTypeName(it) + "\">\n"; + xml += "" + v.getStringValue() + "\n"; + } + xml += "\n"; + } + xml += ""; + Source src = new StreamSource(new CharArrayReader(xml.toCharArray())); + NodeInfo result = null; + try { + NodeInfo paramsNode = core.getEngine().getBuilder().build(src).getUnderlyingNode(); + result = core.executeXSLFunction(context, fe, paramsNode); + } + catch (Exception e) { + throw new RuntimeException(e); + } + if (result == null) { + return EmptyIterator.getInstance(); + } + else { + return result.iterateAxis(Axis.CHILD); + } + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/Constants.java b/teamengine-core/src/main/java/com/occamlab/te/util/Constants.java index 1f5c5c69f..e302628c5 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/Constants.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/Constants.java @@ -1,5 +1,25 @@ package com.occamlab.te.util; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + public class Constants { public static final String YYYY_M_MDD_H_HMMSS = "yyyy/MM/dd-HH:mm:ss"; diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/DateTimeUtils.java b/teamengine-core/src/main/java/com/occamlab/te/util/DateTimeUtils.java index e7b0a2942..1a689b0c4 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/DateTimeUtils.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/DateTimeUtils.java @@ -1,60 +1,80 @@ -package com.occamlab.te.util; - -import java.util.regex.Pattern; -import java.util.regex.Matcher; - -import org.joda.time.DateTime; -import org.joda.time.format.DateTimeFormatter; -import org.joda.time.format.ISODateTimeFormat; - -/** - * Provides various utility methods to manipulate temporal values. - * - */ -public class DateTimeUtils { - - /** - * Parses a temporal value and returns the beginning instant. If the provided value is - * an instant, it is returned in the local (server) time zone. - * @param timeStamp a string representation of a temporal value (year, month, date, or - * dateTime values conforming to XML Schema datatypes). - * @return a String (ISO-8601 syntax) representing the beginning moment of the given - * temporal value. - */ - public static String getBeginningInstant(String timeStamp) { - - // Ensure the string is in proper ISO form (make adjustments from - // XML-syntax) - if (timeStamp.endsWith("Z")) { - // No 'T' even though it ends with a 'Z', so add one - if (timeStamp.indexOf("T") == -1) { - StringBuffer buf = new StringBuffer(timeStamp); - int lastZ = buf.lastIndexOf("Z"); - buf.insert(lastZ, "T"); - timeStamp = buf.toString(); - } - } - Pattern pattern = Pattern.compile(".*[+-]\\d{2}:\\d{2}"); - Matcher matcher = pattern.matcher(timeStamp); - if (matcher.matches()) { - // There is a timezone, but no 'T', so add one - if (timeStamp.indexOf("T") == -1) { - StringBuffer buf = new StringBuffer(timeStamp); - int lastColon = buf.lastIndexOf(":"); - buf.insert(lastColon - 3, "T"); - timeStamp = buf.toString(); - } - } - DateTimeFormatter formatter = ISODateTimeFormat.dateOptionalTimeParser(); - DateTime dateTime = null; - try { - dateTime = formatter.parseDateTime(timeStamp); - } - catch (Exception e) { - System.out.println("DateTimeUtils ERROR: " + e.getMessage()); - } - - return dateTime.toString(); - } - -} \ No newline at end of file +package com.occamlab.te.util; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; + +/** + * Provides various utility methods to manipulate temporal values. + * + */ +public class DateTimeUtils { + + /** + * Parses a temporal value and returns the beginning instant. If the provided value is + * an instant, it is returned in the local (server) time zone. + * @param timeStamp a string representation of a temporal value (year, month, date, or + * dateTime values conforming to XML Schema datatypes). + * @return a String (ISO-8601 syntax) representing the beginning moment of the given + * temporal value. + */ + public static String getBeginningInstant(String timeStamp) { + + // Ensure the string is in proper ISO form (make adjustments from + // XML-syntax) + if (timeStamp.endsWith("Z")) { + // No 'T' even though it ends with a 'Z', so add one + if (timeStamp.indexOf("T") == -1) { + StringBuffer buf = new StringBuffer(timeStamp); + int lastZ = buf.lastIndexOf("Z"); + buf.insert(lastZ, "T"); + timeStamp = buf.toString(); + } + } + Pattern pattern = Pattern.compile(".*[+-]\\d{2}:\\d{2}"); + Matcher matcher = pattern.matcher(timeStamp); + if (matcher.matches()) { + // There is a timezone, but no 'T', so add one + if (timeStamp.indexOf("T") == -1) { + StringBuffer buf = new StringBuffer(timeStamp); + int lastColon = buf.lastIndexOf(":"); + buf.insert(lastColon - 3, "T"); + timeStamp = buf.toString(); + } + } + DateTimeFormatter formatter = ISODateTimeFormat.dateOptionalTimeParser(); + DateTime dateTime = null; + try { + dateTime = formatter.parseDateTime(timeStamp); + } + catch (Exception e) { + System.out.println("DateTimeUtils ERROR: " + e.getMessage()); + } + + return dateTime.toString(); + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/DocumentationHelper.java b/teamengine-core/src/main/java/com/occamlab/te/util/DocumentationHelper.java index 893eaa17e..892da31aa 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/DocumentationHelper.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/DocumentationHelper.java @@ -13,6 +13,26 @@ C. Heazel (WiSC): Added Fortify adjudication changes ****************************************************************************/ package com.occamlab.te.util; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.File; import java.io.FileOutputStream; import java.io.UnsupportedEncodingException; diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/DomUtils.java b/teamengine-core/src/main/java/com/occamlab/te/util/DomUtils.java index 5d3371eaa..d97b4988e 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/DomUtils.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/DomUtils.java @@ -1,424 +1,444 @@ -/** -* ************************************************************************** -* Contributor(s): -* C. Heazel (WiSC): Added Fortify adjudication changes -* -* ************************************************************************** -*/ -package com.occamlab.te.util; - -import java.io.StringReader; -import java.io.ByteArrayOutputStream; -import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import javax.xml.namespace.QName; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Source; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.dom.DOMResult; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; -import javax.xml.XMLConstants; // Addition for Fortify modifications - -import org.w3c.dom.Document; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.NodeList; -import org.w3c.dom.Node; -import org.w3c.dom.Comment; -import org.w3c.dom.Element; -import org.w3c.dom.Attr; - -/** - * Allows for manipulating of a DOM Document by adding/removing/etc elements and - * attributes. - * - * @author jparrpearson - */ -public class DomUtils { - - /** - * Adds the attribute to each node in the Document with the given name. - * @param doc the Document to add attributes to - * @param tagName the local name of the nodes to add the attribute to - * @param tagNamespaceURI the namespace uri of the nodes to add the attribute to - * @param attrName the name of the attribute to add - * @param attrValue the value of the attribute to add - * @return the original Document with the update attribute nodes - */ - public static Node addDomAttr(Document doc, String tagName, String tagNamespaceURI, String attrName, - String attrValue) { - - // Create a Document to work on - Document newDoc = null; - try { - System.setProperty("javax.xml.parsers.DocumentBuilderFactory", - "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl"); - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - DocumentBuilder db = dbf.newDocumentBuilder(); - newDoc = db.newDocument(); - } - catch (Exception e) { - e.printStackTrace(); - // Fortify Mod: If we got here there is no point going any further - return null; - } - - Transformer identity = null; - try { - TransformerFactory TF = TransformerFactory.newInstance(); - // Fortify Mod: disable external entity injection - TF.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - identity = TF.newTransformer(); - // End Fortify Mod - identity.transform(new DOMSource(doc), new DOMResult(newDoc)); - } - catch (Exception ex) { - System.out.println("ERROR: " + ex.getMessage()); - } - - // Get all named nodes in the doucment - NodeList namedTags = newDoc.getElementsByTagNameNS(tagNamespaceURI, tagName); - for (int i = 0; i < namedTags.getLength(); i++) { - // Add the attribute to each one - Element element = (Element) namedTags.item(i); - element.setAttribute(attrName, attrValue); - } - - // displayNode(newDoc); - return (Node) newDoc; - } - - /** - * Determines if there is a comment Node that contains the given string. - * @param node the Node to look in - * @param str the string value to match in the comment nodes - * - * CTL declaration, if we ever want to use it <!--Sample Usage: - * ctl:checkCommentNodes($xml.resp, 'complexContent')--> <ctl:function - * name="ctl:checkCommentNodes"> <ctl:param name="node"/> <ctl:param - * name="string"/> <ctl:description>Checks a Node for comments that contain - * the given string.</ctl:description> <ctl:java - * class="com.occamlab.te.util.DomUtils" method="checkCommentNodes"/> - * </ctl:function> - * @return the original Document with the update attribute nodes - */ - public static boolean checkCommentNodes(Node node, String str) { - - // Get nodes of node and go through them - NodeList children = node.getChildNodes(); - for (int i = 0; i < children.getLength(); i++) { - Node child = children.item(i); - NodeList childChildren = child.getChildNodes(); - if (childChildren.getLength() > 0) { - // Recurse for all children - boolean okDownThere = checkCommentNodes(child, str); - if (okDownThere) { - return true; - } - } - // Investigate comments - if (child.getNodeType() == Node.COMMENT_NODE) { - // If we got a comment that contains the string we are happy - Comment comment = (Comment) child; - if (comment.getNodeValue().contains(str)) { - return true; - } - } - } - return false; - } - - /** - * Serializes a Node to a String - */ - public static String serializeNode(Node node) { - return serializeSource(new DOMSource(node)); - } - - public static String serializeSource(Source source) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try { - TransformerFactory factory = TransformerFactory.newInstance(); - // Fortify Mod: disable external entity injection - factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer transformer = factory.newTransformer(); - // End Fortify Mod - - StreamResult dest = new StreamResult(baos); - transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); - transformer.transform(source, dest); - } - catch (Exception e) { - System.out.println("Error serializing node. " + e.getMessage()); - } - - return baos.toString(StandardCharsets.UTF_8); - } - - /** - * Serializes a Node to a String - */ - public static String serializeNoNS(Node node) { - StringBuffer buf = new StringBuffer(); - buf.append("<"); - buf.append(node.getLocalName()); - for (Entry entry : getAttributes(node).entrySet()) { - QName name = entry.getKey(); - if (name.getNamespaceURI() != null) { - buf.append(" "); - buf.append(name.getLocalPart()); - buf.append("=\""); - buf.append(entry.getValue()); - buf.append("\""); - } - } - boolean tagOpen = true; - NodeList children = node.getChildNodes(); - for (int i = 0; i < children.getLength(); i++) { - Node n = children.item(i); - short type = node.getNodeType(); - if (type == Node.TEXT_NODE) { - if (tagOpen) { - buf.append(">\n"); - tagOpen = false; - } - buf.append(node.getTextContent()); - } - else if (type == Node.ELEMENT_NODE) { - if (tagOpen) { - buf.append(">\n"); - tagOpen = false; - } - buf.append(serializeNoNS(n)); - buf.append("\n"); - } - } - if (tagOpen) { - buf.append("/>\n"); - } - else { - buf.append("\n"); - } - return buf.toString(); - // ByteArrayOutputStream baos = new ByteArrayOutputStream(); - // try { - // TransformerFactory factory = TransformerFactory.newInstance(); - // File f = Misc.getResourceAsFile("com/occamlab/te/drop-ns.xsl"); - // Transformer transformer = factory.newTransformer(new - // StreamSource(f)); - // - // DOMSource src = new DOMSource(node); - // StreamResult dest = new StreamResult(baos); - // transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, - // "yes"); - // transformer.transform(src, dest); - // } catch (Exception e) { - // System.out.println("Error serializing node. "+e.getMessage()); - // } - // - // return baos.toString(); - } - - /** HELPER METHOD TO PRINT A DOM TO STDOUT */ - static public void displayNode(Node node) { - try { - TransformerFactory TF = TransformerFactory.newInstance(); - // Fortify Mod: disable external entity injection - TF.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer identity = TF.newTransformer(); - // End Fortify Mod - identity.transform(new DOMSource(node), new StreamResult(System.out)); - } - catch (Exception ex) { - System.out.println("ERROR: " + ex.getMessage()); - } - } - - static public Element getElement(Node node) { - if (node.getNodeType() == Node.DOCUMENT_NODE) { - return ((Document) node).getDocumentElement(); - } - else if (node.getNodeType() == Node.ELEMENT_NODE) { - return (Element) node; - } - return null; - } - - static public Map getAttributes(Node node) { - Map atts = new HashMap<>(); - NamedNodeMap nnm = node.getAttributes(); - if (nnm != null) { - for (int i = 0; i < nnm.getLength(); i++) { - Attr att = (Attr) nnm.item(i); - String uri = att.getBaseURI(); - String localname = att.getLocalName(); - String prefix = att.getPrefix(); - QName name; - if (uri == null) { - name = new QName(localname); - } - else if (prefix == null) { - name = new QName(uri, localname); - } - else { - name = new QName(uri, localname, prefix); - } - if (prefix == null || !(prefix.equals("xmlns") || prefix.equals("xml"))) { - atts.put(name, att.getValue()); - } - } - } - return atts; - } - - static public Document createDocument(Node node) throws Exception { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - // Fortify Mod: Disable entity expansion to foil External Entity Injections - dbf.setExpandEntityReferences(false); - Document doc = dbf.newDocumentBuilder().newDocument(); - if (node != null) { - // Fortify Mod: disable external entity injection - TransformerFactory tf = TransformerFactory.newInstance(); - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer t = tf.newTransformer(); - // End Fortify Mod - t.transform(new DOMSource(node), new DOMResult(doc)); - } - return doc; - } - - static public Element getChildElement(Node node) { - NodeList nl = node.getChildNodes(); - for (int i = 0; i < nl.getLength(); i++) { - Node n = nl.item(i); - if (n.getNodeType() == Node.ELEMENT_NODE) { - return (Element) n; - } - } - return null; - } - - static public List getChildElements(Node node) { - ArrayList list = new ArrayList<>(); - NodeList nl = node.getChildNodes(); - for (int i = 0; i < nl.getLength(); i++) { - Node n = nl.item(i); - if (n.getNodeType() == Node.ELEMENT_NODE) { - list.add((Element) nl.item(i)); - } - } - return list; - } - - static public Element getElementByTagName(Node node, String tagname) { - NodeList nl; - if (node.getNodeType() == Node.DOCUMENT_NODE) { - nl = ((Document) node).getElementsByTagName(tagname); - } - else if (node.getNodeType() == Node.ELEMENT_NODE) { - nl = ((Element) node).getElementsByTagName(tagname); - } - else { - return null; - } - if (nl.getLength() >= 0) { - return (Element) nl.item(0); - } - else { - return null; - } - } - - static public Element getElementByTagNameNS(Node node, String namespaceURI, String localName) { - NodeList nl; - if (node.getNodeType() == Node.DOCUMENT_NODE) { - nl = ((Document) node).getElementsByTagNameNS(namespaceURI, localName); - } - else if (node.getNodeType() == Node.ELEMENT_NODE) { - nl = ((Element) node).getElementsByTagNameNS(namespaceURI, localName); - } - else { - return null; - } - if (nl.getLength() > 0) { - return (Element) nl.item(0); - } - else { - return null; - } - } - - static public List getElementsByTagName(Node node, String tagname) { - ArrayList list = new ArrayList<>(); - NodeList nl; - if (node.getNodeType() == Node.DOCUMENT_NODE) { - nl = ((Document) node).getElementsByTagName(tagname); - } - else if (node.getNodeType() == Node.ELEMENT_NODE) { - nl = ((Element) node).getElementsByTagName(tagname); - } - else { - return null; - } - for (int i = 0; i < nl.getLength(); i++) { - list.add((Element) nl.item(i)); - } - return list; - } - - static public List getElementsByTagNameNS(Node node, String namespaceURI, String localName) { - ArrayList list = new ArrayList<>(); - NodeList nl; - if (node.getNodeType() == Node.DOCUMENT_NODE) { - nl = ((Document) node).getElementsByTagNameNS(namespaceURI, localName); - } - else if (node.getNodeType() == Node.ELEMENT_NODE) { - nl = ((Element) node).getElementsByTagNameNS(namespaceURI, localName); - } - else { - return null; - } - for (int i = 0; i < nl.getLength(); i++) { - list.add((Element) nl.item(i)); - } - return list; - } - - /** - * Convert text node to element. - * @param xmlString - * @return Return the document object. - * @throws Exception - */ - public static Document convertToElementNode(String xmlString) throws Exception { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - // Fortify Mod: Disable entity expansion to foil External Entity Injections - dbf.setExpandEntityReferences(false); - Document doc = dbf.newDocumentBuilder().newDocument(); - if (xmlString != null) { - // Fortify Mod: disable external entity injection - TransformerFactory tf = TransformerFactory.newInstance(); - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer t = tf.newTransformer(); - // End Fortify Mod - t.transform(new StreamSource(new StringReader(xmlString)), new DOMResult(doc)); - } - return doc; - } - -} +/** +* ************************************************************************** +* Contributor(s): +* C. Heazel (WiSC): Added Fortify adjudication changes +* +* ************************************************************************** +*/ +package com.occamlab.te.util; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.StringReader; +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import javax.xml.XMLConstants; // Addition for Fortify modifications + +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.NodeList; +import org.w3c.dom.Node; +import org.w3c.dom.Comment; +import org.w3c.dom.Element; +import org.w3c.dom.Attr; + +/** + * Allows for manipulating of a DOM Document by adding/removing/etc elements and + * attributes. + * + * @author jparrpearson + */ +public class DomUtils { + + /** + * Adds the attribute to each node in the Document with the given name. + * @param doc the Document to add attributes to + * @param tagName the local name of the nodes to add the attribute to + * @param tagNamespaceURI the namespace uri of the nodes to add the attribute to + * @param attrName the name of the attribute to add + * @param attrValue the value of the attribute to add + * @return the original Document with the update attribute nodes + */ + public static Node addDomAttr(Document doc, String tagName, String tagNamespaceURI, String attrName, + String attrValue) { + + // Create a Document to work on + Document newDoc = null; + try { + System.setProperty("javax.xml.parsers.DocumentBuilderFactory", + "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl"); + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + DocumentBuilder db = dbf.newDocumentBuilder(); + newDoc = db.newDocument(); + } + catch (Exception e) { + e.printStackTrace(); + // Fortify Mod: If we got here there is no point going any further + return null; + } + + Transformer identity = null; + try { + TransformerFactory TF = TransformerFactory.newInstance(); + // Fortify Mod: disable external entity injection + TF.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + identity = TF.newTransformer(); + // End Fortify Mod + identity.transform(new DOMSource(doc), new DOMResult(newDoc)); + } + catch (Exception ex) { + System.out.println("ERROR: " + ex.getMessage()); + } + + // Get all named nodes in the doucment + NodeList namedTags = newDoc.getElementsByTagNameNS(tagNamespaceURI, tagName); + for (int i = 0; i < namedTags.getLength(); i++) { + // Add the attribute to each one + Element element = (Element) namedTags.item(i); + element.setAttribute(attrName, attrValue); + } + + // displayNode(newDoc); + return (Node) newDoc; + } + + /** + * Determines if there is a comment Node that contains the given string. + * @param node the Node to look in + * @param str the string value to match in the comment nodes + * + * CTL declaration, if we ever want to use it <!--Sample Usage: + * ctl:checkCommentNodes($xml.resp, 'complexContent')--> <ctl:function + * name="ctl:checkCommentNodes"> <ctl:param name="node"/> <ctl:param + * name="string"/> <ctl:description>Checks a Node for comments that contain + * the given string.</ctl:description> <ctl:java + * class="com.occamlab.te.util.DomUtils" method="checkCommentNodes"/> + * </ctl:function> + * @return the original Document with the update attribute nodes + */ + public static boolean checkCommentNodes(Node node, String str) { + + // Get nodes of node and go through them + NodeList children = node.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + NodeList childChildren = child.getChildNodes(); + if (childChildren.getLength() > 0) { + // Recurse for all children + boolean okDownThere = checkCommentNodes(child, str); + if (okDownThere) { + return true; + } + } + // Investigate comments + if (child.getNodeType() == Node.COMMENT_NODE) { + // If we got a comment that contains the string we are happy + Comment comment = (Comment) child; + if (comment.getNodeValue().contains(str)) { + return true; + } + } + } + return false; + } + + /** + * Serializes a Node to a String + */ + public static String serializeNode(Node node) { + return serializeSource(new DOMSource(node)); + } + + public static String serializeSource(Source source) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + TransformerFactory factory = TransformerFactory.newInstance(); + // Fortify Mod: disable external entity injection + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer transformer = factory.newTransformer(); + // End Fortify Mod + + StreamResult dest = new StreamResult(baos); + transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + transformer.transform(source, dest); + } + catch (Exception e) { + System.out.println("Error serializing node. " + e.getMessage()); + } + + return baos.toString(StandardCharsets.UTF_8); + } + + /** + * Serializes a Node to a String + */ + public static String serializeNoNS(Node node) { + StringBuffer buf = new StringBuffer(); + buf.append("<"); + buf.append(node.getLocalName()); + for (Entry entry : getAttributes(node).entrySet()) { + QName name = entry.getKey(); + if (name.getNamespaceURI() != null) { + buf.append(" "); + buf.append(name.getLocalPart()); + buf.append("=\""); + buf.append(entry.getValue()); + buf.append("\""); + } + } + boolean tagOpen = true; + NodeList children = node.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node n = children.item(i); + short type = node.getNodeType(); + if (type == Node.TEXT_NODE) { + if (tagOpen) { + buf.append(">\n"); + tagOpen = false; + } + buf.append(node.getTextContent()); + } + else if (type == Node.ELEMENT_NODE) { + if (tagOpen) { + buf.append(">\n"); + tagOpen = false; + } + buf.append(serializeNoNS(n)); + buf.append("\n"); + } + } + if (tagOpen) { + buf.append("/>\n"); + } + else { + buf.append("\n"); + } + return buf.toString(); + // ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // try { + // TransformerFactory factory = TransformerFactory.newInstance(); + // File f = Misc.getResourceAsFile("com/occamlab/te/drop-ns.xsl"); + // Transformer transformer = factory.newTransformer(new + // StreamSource(f)); + // + // DOMSource src = new DOMSource(node); + // StreamResult dest = new StreamResult(baos); + // transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, + // "yes"); + // transformer.transform(src, dest); + // } catch (Exception e) { + // System.out.println("Error serializing node. "+e.getMessage()); + // } + // + // return baos.toString(); + } + + /** HELPER METHOD TO PRINT A DOM TO STDOUT */ + static public void displayNode(Node node) { + try { + TransformerFactory TF = TransformerFactory.newInstance(); + // Fortify Mod: disable external entity injection + TF.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer identity = TF.newTransformer(); + // End Fortify Mod + identity.transform(new DOMSource(node), new StreamResult(System.out)); + } + catch (Exception ex) { + System.out.println("ERROR: " + ex.getMessage()); + } + } + + static public Element getElement(Node node) { + if (node.getNodeType() == Node.DOCUMENT_NODE) { + return ((Document) node).getDocumentElement(); + } + else if (node.getNodeType() == Node.ELEMENT_NODE) { + return (Element) node; + } + return null; + } + + static public Map getAttributes(Node node) { + Map atts = new HashMap<>(); + NamedNodeMap nnm = node.getAttributes(); + if (nnm != null) { + for (int i = 0; i < nnm.getLength(); i++) { + Attr att = (Attr) nnm.item(i); + String uri = att.getBaseURI(); + String localname = att.getLocalName(); + String prefix = att.getPrefix(); + QName name; + if (uri == null) { + name = new QName(localname); + } + else if (prefix == null) { + name = new QName(uri, localname); + } + else { + name = new QName(uri, localname, prefix); + } + if (prefix == null || !(prefix.equals("xmlns") || prefix.equals("xml"))) { + atts.put(name, att.getValue()); + } + } + } + return atts; + } + + static public Document createDocument(Node node) throws Exception { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + // Fortify Mod: Disable entity expansion to foil External Entity Injections + dbf.setExpandEntityReferences(false); + Document doc = dbf.newDocumentBuilder().newDocument(); + if (node != null) { + // Fortify Mod: disable external entity injection + TransformerFactory tf = TransformerFactory.newInstance(); + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer t = tf.newTransformer(); + // End Fortify Mod + t.transform(new DOMSource(node), new DOMResult(doc)); + } + return doc; + } + + static public Element getChildElement(Node node) { + NodeList nl = node.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node n = nl.item(i); + if (n.getNodeType() == Node.ELEMENT_NODE) { + return (Element) n; + } + } + return null; + } + + static public List getChildElements(Node node) { + ArrayList list = new ArrayList<>(); + NodeList nl = node.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node n = nl.item(i); + if (n.getNodeType() == Node.ELEMENT_NODE) { + list.add((Element) nl.item(i)); + } + } + return list; + } + + static public Element getElementByTagName(Node node, String tagname) { + NodeList nl; + if (node.getNodeType() == Node.DOCUMENT_NODE) { + nl = ((Document) node).getElementsByTagName(tagname); + } + else if (node.getNodeType() == Node.ELEMENT_NODE) { + nl = ((Element) node).getElementsByTagName(tagname); + } + else { + return null; + } + if (nl.getLength() >= 0) { + return (Element) nl.item(0); + } + else { + return null; + } + } + + static public Element getElementByTagNameNS(Node node, String namespaceURI, String localName) { + NodeList nl; + if (node.getNodeType() == Node.DOCUMENT_NODE) { + nl = ((Document) node).getElementsByTagNameNS(namespaceURI, localName); + } + else if (node.getNodeType() == Node.ELEMENT_NODE) { + nl = ((Element) node).getElementsByTagNameNS(namespaceURI, localName); + } + else { + return null; + } + if (nl.getLength() > 0) { + return (Element) nl.item(0); + } + else { + return null; + } + } + + static public List getElementsByTagName(Node node, String tagname) { + ArrayList list = new ArrayList<>(); + NodeList nl; + if (node.getNodeType() == Node.DOCUMENT_NODE) { + nl = ((Document) node).getElementsByTagName(tagname); + } + else if (node.getNodeType() == Node.ELEMENT_NODE) { + nl = ((Element) node).getElementsByTagName(tagname); + } + else { + return null; + } + for (int i = 0; i < nl.getLength(); i++) { + list.add((Element) nl.item(i)); + } + return list; + } + + static public List getElementsByTagNameNS(Node node, String namespaceURI, String localName) { + ArrayList list = new ArrayList<>(); + NodeList nl; + if (node.getNodeType() == Node.DOCUMENT_NODE) { + nl = ((Document) node).getElementsByTagNameNS(namespaceURI, localName); + } + else if (node.getNodeType() == Node.ELEMENT_NODE) { + nl = ((Element) node).getElementsByTagNameNS(namespaceURI, localName); + } + else { + return null; + } + for (int i = 0; i < nl.getLength(); i++) { + list.add((Element) nl.item(i)); + } + return list; + } + + /** + * Convert text node to element. + * @param xmlString + * @return Return the document object. + * @throws Exception + */ + public static Document convertToElementNode(String xmlString) throws Exception { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + // Fortify Mod: Disable entity expansion to foil External Entity Injections + dbf.setExpandEntityReferences(false); + Document doc = dbf.newDocumentBuilder().newDocument(); + if (xmlString != null) { + // Fortify Mod: disable external entity injection + TransformerFactory tf = TransformerFactory.newInstance(); + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer t = tf.newTransformer(); + // End Fortify Mod + t.transform(new StreamSource(new StringReader(xmlString)), new DOMResult(doc)); + } + return doc; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/IOUtils.java b/teamengine-core/src/main/java/com/occamlab/te/util/IOUtils.java index f1c9004b3..20c65dec6 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/IOUtils.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/IOUtils.java @@ -1,225 +1,245 @@ -/** - * ************************************************************************** - * - * Contributor(s): - * C. Heazel (WiSC): Added Fortify adjudication changes - * - *************************************************************************** - */ -package com.occamlab.te.util; - -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.nio.charset.StandardCharsets; -import java.util.logging.Logger; - -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import javax.xml.XMLConstants; // Addition for Fortify modifications - -import org.w3c.dom.Document; - -/** - * Provides various utility methods to read/write from files and streams. - * - * @author jparrpearson - */ -public class IOUtils { - - private static final Logger LOGR = Logger.getLogger(IOUtils.class.getName()); - - /** - * Converts an org.w3c.dom.Document element to an java.io.InputStream. - * @param edoc the org.w3c.dom.Document to be converted - * @return InputStream the InputStream value of the passed doument - */ - public static InputStream DocumentToInputStream(Document edoc) throws IOException { - - // Create the input and output for use in the transformation - final org.w3c.dom.Document doc = edoc; - final PipedOutputStream pos = new PipedOutputStream(); - PipedInputStream pis = new PipedInputStream(); - pis.connect(pos); - - (new Thread(new Runnable() { - - public void run() { - // Use the Transformer.transform() method to save the Document - // to a StreamResult - try { - TransformerFactory tFactory = TransformerFactory.newInstance(); - // Fortify Mod: prevent external entity injection - tFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer transformer = tFactory.newTransformer(); - transformer.setOutputProperty("encoding", "UTF-8"); - transformer.setOutputProperty("indent", "yes"); - transformer.transform(new DOMSource(doc), new StreamResult(pos)); - } - catch (Exception e) { - throw new RuntimeException("Error converting Document to InputStream. " + e.getMessage()); - } - finally { - try { - pos.close(); - } - catch (IOException e) { - - } - } - } - }, "IOUtils.DocumentToInputStream(Document edoc)")).start(); - - return pis; - } - - /** - * Reads the content of an input stream into a String value using the UTF-8 charset. - * @param in The InputStream from which the content is read. - * @return A String representing the content of the input stream; an empty string is - * returned if an error occurs. - */ - public static String inputStreamToString(InputStream in) { - StringBuffer buffer = new StringBuffer(); - try { - BufferedReader br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8), 1024); - String line; - while ((line = br.readLine()) != null) { - buffer.append(line); - } - } - catch (IOException iox) { - LOGR.warning(iox.getMessage()); - } - return buffer.toString(); - } - - /** - * Converts an InputStream to a byte[] - * - */ - public static byte[] inputStreamToBytes(InputStream in) { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - try { - byte[] buffer = new byte[1024]; - int len; - while ((len = in.read(buffer)) != -1) { - out.write(buffer, 0, len); - } - } - catch (Exception e) { - System.out.println("Error converting InputStream to byte[]: " + e.getMessage()); - } - return out.toByteArray(); - } - - /** - * Writes a generic object to a file - */ - public static boolean writeObjectToFile(Object obj, File f) { - try { - FileOutputStream fout = new FileOutputStream(f); - ObjectOutputStream oos = new ObjectOutputStream(fout); - oos.writeObject(obj); - oos.close(); - } - catch (Exception e) { - System.out.println("Error writing Object to file: " + e.getMessage()); - return false; - } - return true; - } - - /** - * Writes a byte[] to a file - */ - public static boolean writeBytesToFile(byte[] bytes, File f) { - try { - FileOutputStream fout = new FileOutputStream(f); - fout.write(bytes); - fout.close(); - } - catch (Exception e) { - System.out.println("Error writing byte[] to file: " + e.getMessage()); - return false; - } - return true; - } - - /** - * Reads in a file that contains only an object - */ - public static Object readObjectFromFile(File f) { - Object obj = null; - try { - FileInputStream fin = new FileInputStream(f); - ObjectInputStream ois = new ObjectInputStream(fin); - obj = ois.readObject(); - ois.close(); - } - catch (Exception e) { - System.out.println("Error reading Object from file: " + e.getMessage()); - return null; - } - return obj; - } - - /** - * Reads in a file as a byte[] - */ - public static byte[] readBytesFromFile(File f) { - byte[] bytes = null; - try { - int filesize = (int) f.length(); - bytes = new byte[filesize]; - DataInputStream in = new DataInputStream(new FileInputStream(f)); - in.readFully(bytes); - in.close(); - } - catch (Exception e) { - System.out.println("Error reading byte[] from file: " + e.getMessage()); - return null; - } - return bytes; - } - - /** - * Polls a file periodically until it 1) exists or 2) the timeout is exceeded (returns - * null) Reads the file as a java Object - */ - public static Object pollFile(File file, int timeout, int interval) throws InterruptedException { - // Convert time from s to ms for Thread - int fullTimeout = Math.round(timeout * 1000); - - // Split up the timeout to poll every x amount of time - int timeoutShard = Math.round(fullTimeout / interval); - - // Poll until file exists, return if it exists - for (int i = 0; i < interval; i++) { - Thread.sleep(timeoutShard); - if (file.exists()) { - return readObjectFromFile(file); - } - } - - // Return null if time is up and still no file - return null; - } - - public static Object pollFile(File file, int timeout) throws InterruptedException { - return pollFile(file, timeout, 25); - } - -} +/** + * ************************************************************************** + * + * Contributor(s): + * C. Heazel (WiSC): Added Fortify adjudication changes + * + *************************************************************************** + */ +package com.occamlab.te.util; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.logging.Logger; + +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.XMLConstants; // Addition for Fortify modifications + +import org.w3c.dom.Document; + +/** + * Provides various utility methods to read/write from files and streams. + * + * @author jparrpearson + */ +public class IOUtils { + + private static final Logger LOGR = Logger.getLogger(IOUtils.class.getName()); + + /** + * Converts an org.w3c.dom.Document element to an java.io.InputStream. + * @param edoc the org.w3c.dom.Document to be converted + * @return InputStream the InputStream value of the passed doument + */ + public static InputStream DocumentToInputStream(Document edoc) throws IOException { + + // Create the input and output for use in the transformation + final org.w3c.dom.Document doc = edoc; + final PipedOutputStream pos = new PipedOutputStream(); + PipedInputStream pis = new PipedInputStream(); + pis.connect(pos); + + (new Thread(new Runnable() { + + public void run() { + // Use the Transformer.transform() method to save the Document + // to a StreamResult + try { + TransformerFactory tFactory = TransformerFactory.newInstance(); + // Fortify Mod: prevent external entity injection + tFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer transformer = tFactory.newTransformer(); + transformer.setOutputProperty("encoding", "UTF-8"); + transformer.setOutputProperty("indent", "yes"); + transformer.transform(new DOMSource(doc), new StreamResult(pos)); + } + catch (Exception e) { + throw new RuntimeException("Error converting Document to InputStream. " + e.getMessage()); + } + finally { + try { + pos.close(); + } + catch (IOException e) { + + } + } + } + }, "IOUtils.DocumentToInputStream(Document edoc)")).start(); + + return pis; + } + + /** + * Reads the content of an input stream into a String value using the UTF-8 charset. + * @param in The InputStream from which the content is read. + * @return A String representing the content of the input stream; an empty string is + * returned if an error occurs. + */ + public static String inputStreamToString(InputStream in) { + StringBuffer buffer = new StringBuffer(); + try { + BufferedReader br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8), 1024); + String line; + while ((line = br.readLine()) != null) { + buffer.append(line); + } + } + catch (IOException iox) { + LOGR.warning(iox.getMessage()); + } + return buffer.toString(); + } + + /** + * Converts an InputStream to a byte[] + * + */ + public static byte[] inputStreamToBytes(InputStream in) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try { + byte[] buffer = new byte[1024]; + int len; + while ((len = in.read(buffer)) != -1) { + out.write(buffer, 0, len); + } + } + catch (Exception e) { + System.out.println("Error converting InputStream to byte[]: " + e.getMessage()); + } + return out.toByteArray(); + } + + /** + * Writes a generic object to a file + */ + public static boolean writeObjectToFile(Object obj, File f) { + try { + FileOutputStream fout = new FileOutputStream(f); + ObjectOutputStream oos = new ObjectOutputStream(fout); + oos.writeObject(obj); + oos.close(); + } + catch (Exception e) { + System.out.println("Error writing Object to file: " + e.getMessage()); + return false; + } + return true; + } + + /** + * Writes a byte[] to a file + */ + public static boolean writeBytesToFile(byte[] bytes, File f) { + try { + FileOutputStream fout = new FileOutputStream(f); + fout.write(bytes); + fout.close(); + } + catch (Exception e) { + System.out.println("Error writing byte[] to file: " + e.getMessage()); + return false; + } + return true; + } + + /** + * Reads in a file that contains only an object + */ + public static Object readObjectFromFile(File f) { + Object obj = null; + try { + FileInputStream fin = new FileInputStream(f); + ObjectInputStream ois = new ObjectInputStream(fin); + obj = ois.readObject(); + ois.close(); + } + catch (Exception e) { + System.out.println("Error reading Object from file: " + e.getMessage()); + return null; + } + return obj; + } + + /** + * Reads in a file as a byte[] + */ + public static byte[] readBytesFromFile(File f) { + byte[] bytes = null; + try { + int filesize = (int) f.length(); + bytes = new byte[filesize]; + DataInputStream in = new DataInputStream(new FileInputStream(f)); + in.readFully(bytes); + in.close(); + } + catch (Exception e) { + System.out.println("Error reading byte[] from file: " + e.getMessage()); + return null; + } + return bytes; + } + + /** + * Polls a file periodically until it 1) exists or 2) the timeout is exceeded (returns + * null) Reads the file as a java Object + */ + public static Object pollFile(File file, int timeout, int interval) throws InterruptedException { + // Convert time from s to ms for Thread + int fullTimeout = Math.round(timeout * 1000); + + // Split up the timeout to poll every x amount of time + int timeoutShard = Math.round(fullTimeout / interval); + + // Poll until file exists, return if it exists + for (int i = 0; i < interval; i++) { + Thread.sleep(timeoutShard); + if (file.exists()) { + return readObjectFromFile(file); + } + } + + // Return null if time is up and still no file + return null; + } + + public static Object pollFile(File file, int timeout) throws InterruptedException { + return pollFile(file, timeout, 25); + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/LogUtils.java b/teamengine-core/src/main/java/com/occamlab/te/util/LogUtils.java index 416bae471..e88fe5fb0 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/LogUtils.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/LogUtils.java @@ -1,633 +1,653 @@ -/** - * ************************************************************************** - * - * Version Date: January 24, 2018 - * - * Contributor(s): - * C. Heazel (WiSC): - * Added Fortify adjudication changes - * Changed session id format to UUID - * - *************************************************************************** - */ -package com.occamlab.te.util; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.ByteArrayInputStream; -import java.io.CharArrayReader; -import java.io.File; -import java.io.FileFilter; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.RandomAccessFile; -import java.io.StringReader; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.xml.namespace.QName; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMResult; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; -import javax.xml.XMLConstants; // Addition for Fortify modifications - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import com.occamlab.te.TECore; -import com.occamlab.te.util.TEPath; // Fortify Mod - -import net.sf.saxon.s9api.Axis; -import net.sf.saxon.s9api.XdmNode; - -import static java.lang.Long.valueOf; - -public class LogUtils { - - private static final Logger LOGR = Logger.getLogger(LogUtils.class.getName()); - - /** - * Creates a Writer used to write test results to the log.xml file. - * @param logDir The directory containing the test session results. - * @param callpath A test session identifier. - * @return A PrintWriter object, or {@code null} if one could not be created. - * @throws Exception - */ - public static PrintWriter createLog(File logDir, String callpath) throws Exception { - if (logDir != null) { - File dir = new File(logDir, callpath); - // Fortify Mod: use TEPath to validate the path to the log file - TEPath tpath = new TEPath(dir.getAbsolutePath()); - if (!tpath.isValid()) { - return null; - } - String path = logDir.toString() + "/" + callpath.split("/")[0]; - System.setProperty("PATH", path); - dir.mkdirs(); - File f = new File(dir, "log.xml"); - f.delete(); - BufferedWriter writer = new BufferedWriter( - new OutputStreamWriter(new FileOutputStream(f), StandardCharsets.UTF_8)); - return new PrintWriter(writer); - } - return null; - } - - // Reads a log from disk - public static Document readLog(File logDir, String callpath) throws Exception { - File dir = new File(logDir, callpath); - File f = new File(dir, "log.xml"); - if (f.exists()) { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - // Fortify Mod: Disable entity expansion to foil External Entity Injections - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.newDocument(); - TransformerFactory tf = TransformerFactory.newInstance(); - // Fortify Mod: prevent external entity injection - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer t = tf.newTransformer(); - t.setErrorListener(new com.occamlab.te.NullErrorListener()); - try { - t.transform(new StreamSource(f), new DOMResult(doc)); - } - catch (Exception e) { - // Issue ets-wcs10 #54 To handle invalid characters in response - if (e.getMessage().contains("An invalid XML character")) { - String validString = readValidCharsFromLogFile(f); - writeValidCharsToLogFile(f, validString); - } - // The log may not have been closed properly. - // Try again with a closing tag - RandomAccessFile raf = new RandomAccessFile(f, "r"); - int l = valueOf(raf.length()).intValue(); - byte[] buf = new byte[l + 8]; - raf.read(buf); - raf.close(); - buf[l] = '\n'; - buf[l + 1] = '<'; - buf[l + 2] = '/'; - buf[l + 3] = 'l'; - buf[l + 4] = 'o'; - buf[l + 5] = 'g'; - buf[l + 6] = '>'; - buf[l + 7] = '\n'; - doc = db.newDocument(); - tf.newTransformer().transform(new StreamSource(new ByteArrayInputStream(buf)), new DOMResult(doc)); - } - return doc; - } - else { - return null; - } - } - - public static String readValidCharsFromLogFile(File path) throws IOException { - StringBuilder sb = new StringBuilder(); - try (BufferedReader br = new BufferedReader(new FileReader(path))) { - String sCurrentLine; - while ((sCurrentLine = br.readLine()) != null) { - String strippedLine = stripNonValidXMLCharacters(sCurrentLine); - - if (strippedLine.length() != sCurrentLine.length()) { - if (strippedLine.contains("")) { - StringBuilder builder = new StringBuilder(strippedLine); - builder.insert(builder.indexOf("") + 9, ""), "]]>"); - strippedLine = builder.toString(); - } - } - sb.append(strippedLine); - } - } - if (sb.toString().indexOf("") != -1) { - sb.replace(sb.indexOf(""), sb.length(), ""); - } - return sb.toString(); - } - - public static void writeValidCharsToLogFile(File file, String validString) throws IOException { - StringWriter stringWriter = new StringWriter(); - StreamResult xmlOutput = new StreamResult(stringWriter); - TransformerFactory transformerFactory = TransformerFactory.newInstance(); - Transformer transformer; - try { - transformer = transformerFactory.newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty(OutputKeys.CDATA_SECTION_ELEMENTS, "content"); - transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); - - Source xmlInput = new StreamSource(new StringReader(validString)); - transformer.transform(xmlInput, xmlOutput); - } - catch (TransformerException e) { - System.out.println(e.getMessage()); - } - BufferedWriter writer = new BufferedWriter(new FileWriter(file)); - writer.write(xmlOutput.getWriter().toString()); - writer.close(); - } - - public static String stripNonValidXMLCharacters(String in) { - StringBuffer out = new StringBuffer(); - char current; - - if (in == null || (in.isEmpty())) - return ""; - for (int i = 0; i < in.length(); i++) { - current = in.charAt(i); - if ((current == 0x9) || (current == 0xA) || (current == 0xD) || ((current >= 0x20) && (current <= 0xD7FF)) - || ((current >= 0xE000) && (current <= 0xFFFD)) || ((current >= 0x10000) && (current <= 0x10FFFF))) - out.append(current); - } - return out.toString().replaceAll("&#", ""); - } - - // Returns the id of a test from its log document - public static String getTestIdFromLog(Document log) throws Exception { - Element starttest = DomUtils.getElementByTagName(log, "starttest"); - String namespace = starttest.getAttribute("namespace-uri"); - String localName = starttest.getAttribute("local-name"); - return "{" + namespace + "}" + localName; - } - - public static int getResultFromLog(Document log) throws Exception { - if (log != null) { - Element endtest = DomUtils.getElementByTagName(log, "endtest"); - if (endtest != null) { - return Integer.parseInt(endtest.getAttribute("result")); - } - } - return -1; - } - - // Returns the parameters to a test from its log document - public static List getParamListFromLog(net.sf.saxon.s9api.DocumentBuilder builder, Document log) - throws Exception { - List list = new ArrayList<>(); - Element starttest = (Element) log.getElementsByTagName("starttest").item(0); - for (Element param : DomUtils.getElementsByTagName(starttest, "param")) { - String value = DomUtils.getElementByTagName(param, "value").getTextContent(); - list.add(param.getAttribute("local-name") + "=" + value); - } - return list; - } - - // Returns the parameters to a test from its log document - public static XdmNode getParamsFromLog(net.sf.saxon.s9api.DocumentBuilder builder, Document log) throws Exception { - Element starttest = (Element) log.getElementsByTagName("starttest").item(0); - NodeList nl = starttest.getElementsByTagName("params"); - if (nl == null || nl.getLength() == 0) { - return null; - } - else { - Document doc = DomUtils.createDocument(nl.item(0)); - return builder.build(new DOMSource(doc)); - } - } - - // Returns the context node for a test from its log document - public static XdmNode getContextFromLog(net.sf.saxon.s9api.DocumentBuilder builder, Document log) throws Exception { - Element starttest = (Element) log.getElementsByTagName("starttest").item(0); - NodeList nl = starttest.getElementsByTagName("context"); - if (nl == null || nl.getLength() == 0) { - return null; - } - else { - Element context = (Element) nl.item(0); - Element value = (Element) context.getElementsByTagName("value").item(0); - nl = value.getChildNodes(); - for (int i = 0; i < nl.getLength(); i++) { - Node n = nl.item(i); - if (n.getNodeType() == Node.ATTRIBUTE_NODE) { - String s = DomUtils.serializeNode(value); - XdmNode xn = builder.build(new StreamSource(new CharArrayReader(s.toCharArray()))); - return (XdmNode) xn.axisIterator(Axis.ATTRIBUTE).next(); - } - else if (n.getNodeType() == Node.ELEMENT_NODE) { - Document doc = DomUtils.createDocument(n); - return builder.build(new DOMSource(doc)); - } - } - } - return null; - } - - private static Element makeTestListElement(DocumentBuilder db, Document owner, File logdir, String path) - throws Exception { - File log = new File(new File(logdir, path), "log.xml"); - Document logdoc = LogUtils.readLog(log.getParentFile(), "."); - if (logdoc == null) { - return null; - } - Element log_e = DomUtils.getElementByTagName(logdoc, "log"); - if (log_e == null) { - return null; - } - Element test = owner.createElement("test"); - int result = TECore.PASS; - String type = "Mandatory"; - boolean complete = false; - boolean childrenFailed = false; - boolean hasCache = false; - for (Element e : DomUtils.getChildElements(log_e)) { - if (e.getNodeName().equals("starttest")) { - NamedNodeMap atts = e.getAttributes(); - for (int j = 0; j < atts.getLength(); j++) { - String nodeName = atts.item(j).getNodeName(); - String nodeValue = atts.item(j).getNodeValue(); - if ("defaultResult".equals(nodeName)) { - result = Integer.parseInt(nodeValue); - } - else if ("type".equals(nodeName)) { // 2011-03-07 PwD - type = nodeValue; - } - test.setAttribute(nodeName, nodeValue); - } - } - else if (e.getNodeName().equals("endtest")) { - complete = true; - int code = Integer.parseInt(e.getAttribute("result")); - if (childrenFailed) { - result = TECore.INHERITED_FAILURE; - } - else { - result = code; - } - } - else if (e.getNodeName().equals("testcall")) { - String newpath = e.getAttribute("path"); - Element child = makeTestListElement(db, owner, logdir, newpath); - if (child != null) { - child.setAttribute("path", newpath); - int code = Integer.parseInt(child.getAttribute("result")); - if (code == TECore.FAIL || code == TECore.INHERITED_FAILURE) { - childrenFailed = true; - } - test.appendChild(child); - } - } - else if (e.getNodeName().equals("cache")) { - hasCache = true; - } - } - test.setAttribute("result", Integer.toString(result)); - test.setAttribute("complete", complete ? "yes" : "no"); - test.setAttribute("hasCache", hasCache ? "yes" : "no"); - return test; - } - - /** - * Produces a document containing a collection of tests run in a base suite. - * @param logdir A File denoting the location of the test log directory. - * @param path A session identifier. - * @param excludes A list of tests to ignore. - * @return A Document node where <test> is the document element - * @throws Exception If any errors occur. - */ - public static Document makeTestList(File logdir, String path, List> excludes) throws Exception { - // Fortify Mod: validate logdir and path - // If they don't form a valid path, throw an error - File tfile = new File(logdir, path); - TEPath tpath = new TEPath(tfile.getAbsolutePath()); - if (!tpath.isValid()) { - throw new IllegalArgumentException("Illegal path = " + tfile.getAbsolutePath()); - } - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - // Fortify Mod: Disable entity expansion to foil External Entity Injections - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc; - File testListFile = new File(logdir, path + File.separator + "testlist.xml"); - long testListDate = testListFile.lastModified(); - File rootlog = new File(logdir, path + File.separator + "log.xml"); - boolean updated; - if (testListFile.exists() && testListDate >= rootlog.lastModified()) { - try { - doc = db.parse(testListFile); - updated = (updateTestListElement(db, doc.getDocumentElement(), logdir, testListDate) != null); - } - catch (Exception e) { - - if (e.toString().contains("Premature end of file")) { - return null; - } - else { - throw new Exception("Error while writting the 'testlist.xml' file." + e); - } - } - } - else { - doc = db.newDocument(); - Element test = makeTestListElement(db, doc, logdir, path); - if (test != null) { - doc.appendChild(test); - doc.getDocumentElement().setAttribute("path", path); - } - updated = true; - } - if (updated) { - TransformerFactory tf = TransformerFactory.newInstance(); - // Fortify Mod: disable external entity injection - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer t = tf.newTransformer(); - t.setOutputProperty(OutputKeys.INDENT, "yes"); - t.transform(new DOMSource(doc), new StreamResult(testListFile)); - } - if (excludes.size() > 0) { - removeExcludes(doc.getDocumentElement(), new ArrayList<>(), excludes); - updateTestListElement(db, doc.getDocumentElement(), logdir, 0); - } - if (LOGR.isLoggable(Level.CONFIG)) { - StringBuilder msg = new StringBuilder("Read source test list in "); - msg.append(testListFile.getParent()).append("\n"); - msg.append(DomUtils.serializeNode(doc)); - LOGR.config(msg.toString()); - } - return doc; - } - - public static Document makeTestList(File logdir, String path) throws Exception { - List> excludes = new ArrayList<>(); - return makeTestList(logdir, path, excludes); - } - - /* - * Recalculate each result. If testListDate != 0, then reread new log files as well - */ - private static Element updateTestListElement(DocumentBuilder db, Element test, File logdir, long testListDate) - throws Exception { - String path = test.getAttribute("path"); - long logdate = 0; - if (testListDate > 0) { - logdate = new File(logdir, path + File.separator + "log.xml").lastModified(); - } - if (logdate > testListDate) { - Element newtest = makeTestListElement(db, test.getOwnerDocument(), logdir, path); - test.getParentNode().replaceChild(newtest, test); - return newtest; - } - else { - boolean updated = false; - boolean childrenFailed = false; - for (Element subtest : DomUtils.getChildElements(test)) { - Element newsubtest = updateTestListElement(db, subtest, logdir, testListDate); - if (newsubtest != null) { - updated = true; - int code = Integer.parseInt(newsubtest.getAttribute("result")); - if (code == TECore.FAIL || code == TECore.INHERITED_FAILURE) { - childrenFailed = true; - } - } - } - if (updated || testListDate == 0) { - int result = Integer.parseInt(test.getAttribute("result")); - int newresult = TECore.PASS; - if (result == TECore.FAIL) { - newresult = TECore.FAIL; - } - else if (childrenFailed) { - newresult = TECore.INHERITED_FAILURE; - } - else if (result == TECore.WARNING) { - newresult = TECore.WARNING; - } - if (newresult != result) { - test.setAttribute("result", Integer.toString(newresult)); - return test; - } - } - return null; - } - } - - private static void removeExcludes(Element test, List pathQName, List> excludes) - throws Exception { - List testQName = new ArrayList<>(pathQName); - String namespaceURI = test.getAttribute("namespace-uri"); - String localPart = test.getAttribute("local-name"); - String prefix = test.getAttribute("prefix"); - QName qname = new QName(namespaceURI, localPart, prefix); - testQName.add(qname); - if (excludes.contains(testQName)) { - test.getParentNode().removeChild(test); - } - else { - for (Element subtest : DomUtils.getChildElements(test)) { - removeExcludes(subtest, testQName, excludes); - } - } - } - - /** - * Generates a session identifier. The value corresponds to the name of a - * sub-directory (session) in the root test log directory. - * @return a session id string - */ - public static String generateSessionId(File logDir) { - int i = 1; - String session = "s0001"; - while (new File(logDir, session).exists() && i < 10000) { - i++; - session = "s" + Integer.toString(10000 + i).substring(1); - } - return session; - } - - /** - * Generate a file in logDir refererring all logfiles. Create a file called - * "report_logs.xml" in the log folder that includes all logs listed inside the - * directory. author F.Vitale vitale@imaa.cnr.it - * @param sessionLogDir considered log directory - * @throws Exception - */ - public static void createFullReportLog(String sessionLogDir) throws Exception { - LOGR.log(Level.WARNING, "Creating report log for " + sessionLogDir); - // Fortify Mod: validate sessionLogDir argument - TEPath tpath = new TEPath(sessionLogDir); - if (!tpath.isValid()) { - throw new IllegalArgumentException("Illegal path = " + tpath.toString()); - } - // Make sure the session log directory exits - File dir = new File(sessionLogDir); - if (!dir.exists()) { - if (!dir.mkdir()) { - if (!dir.mkdirs()) { - throw new RuntimeException("Unable to create report log directory " + sessionLogDir); - } - } - } - File xml_logs_report_file = new File(sessionLogDir + File.separator + "report_logs.xml"); - if (xml_logs_report_file.exists()) { - xml_logs_report_file.delete(); - xml_logs_report_file.createNewFile(); - } - xml_logs_report_file = new File(sessionLogDir + File.separator + "report_logs.xml"); - // xml_logs_report_file = new - // File("C:\\TE_BASE\\users\\cheazel\\dummy\\report_logs.xml"); - OutputStream report_logs = new FileOutputStream(xml_logs_report_file); - List files = null; - Document result = null; - - files = getFileListing(new File(sessionLogDir)); - - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - // Fortify Mod: Disable entity expansion to foil External Entity Injections - factory.setExpandEntityReferences(false); - DocumentBuilder builder = factory.newDocumentBuilder(); - - // Create the document - Document doc = builder.newDocument(); - // Fill the document - Element execution = doc.createElement("execution"); - execution.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xi", "http://www.w3.org/2001/XInclude"); - doc.appendChild(execution); - for (File file : files) { - // all files are Sorted with CompareTO - Element include = doc.createElementNS("http://www.w3.org/2001/XInclude", "xi:include"); - include.setAttribute("href", file.getAbsolutePath()); - execution.appendChild(include); - } - // Serialize the document into System.out - TransformerFactory xformFactory = TransformerFactory.newInstance(); - // Fortify Mod: disable external entity injection - xformFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer idTransform = xformFactory.newTransformer(); - Source input = new DOMSource(doc); - Result output = new StreamResult(report_logs); - idTransform.transform(input, output); - // Fortify Mod: Close report_logs and release its resources - report_logs.close(); - result = doc; // actually we do not needs results - } - - /** - * Recursively walk a directory tree and return a List of all log files found. - * @param logDir die to walk - * @return - * @throws Exception - */ - private static List getFileListing(File logDir) throws Exception { - return getFileListingLogs(logDir); - } - - /** - * Get all log files and directories and make recursive call. - * @param aStartingDir - * @return - * @throws Exception - */ - static private List getFileListingLogs(File aStartingDir) throws Exception { - List result = new ArrayList<>(); - File[] logfiles = aStartingDir.listFiles(new FileFilter() { - - @Override - public boolean accept(File pathname) { - return pathname.isFile(); - } - }); - List logFilesList = Arrays.asList(logfiles); - File[] allDirs = aStartingDir.listFiles(new FileFilter() { - @Override - public boolean accept(File pathname) { - return pathname.isDirectory(); - } - }); - for (File file : logFilesList) { - if (file.getName().equals("log.xml")) { - result.add(file); - } - } - List allDirsList = Arrays.asList(allDirs); - allDirsList.sort(new Comparator<>() { - public int compare(File o1, File o2) { - - if (o1.lastModified() > o2.lastModified()) { - return +1; - } - else if (o1.lastModified() < o2.lastModified()) { - return -1; - } - else { - return 0; - } - } - - }); - for (File file : allDirsList) { - if (!file.isFile()) { - List deeperList = getFileListingLogs(file); - result.addAll(deeperList); - } - } - return result; - } - -} +/** + * ************************************************************************** + * + * Version Date: January 24, 2018 + * + * Contributor(s): + * C. Heazel (WiSC): + * Added Fortify adjudication changes + * Changed session id format to UUID + * + *************************************************************************** + */ +package com.occamlab.te.util; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; +import java.io.CharArrayReader; +import java.io.File; +import java.io.FileFilter; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.RandomAccessFile; +import java.io.StringReader; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import javax.xml.XMLConstants; // Addition for Fortify modifications + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.occamlab.te.TECore; +import com.occamlab.te.util.TEPath; // Fortify Mod + +import net.sf.saxon.s9api.Axis; +import net.sf.saxon.s9api.XdmNode; + +import static java.lang.Long.valueOf; + +public class LogUtils { + + private static final Logger LOGR = Logger.getLogger(LogUtils.class.getName()); + + /** + * Creates a Writer used to write test results to the log.xml file. + * @param logDir The directory containing the test session results. + * @param callpath A test session identifier. + * @return A PrintWriter object, or {@code null} if one could not be created. + * @throws Exception + */ + public static PrintWriter createLog(File logDir, String callpath) throws Exception { + if (logDir != null) { + File dir = new File(logDir, callpath); + // Fortify Mod: use TEPath to validate the path to the log file + TEPath tpath = new TEPath(dir.getAbsolutePath()); + if (!tpath.isValid()) { + return null; + } + String path = logDir.toString() + "/" + callpath.split("/")[0]; + System.setProperty("PATH", path); + dir.mkdirs(); + File f = new File(dir, "log.xml"); + f.delete(); + BufferedWriter writer = new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(f), StandardCharsets.UTF_8)); + return new PrintWriter(writer); + } + return null; + } + + // Reads a log from disk + public static Document readLog(File logDir, String callpath) throws Exception { + File dir = new File(logDir, callpath); + File f = new File(dir, "log.xml"); + if (f.exists()) { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + // Fortify Mod: Disable entity expansion to foil External Entity Injections + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.newDocument(); + TransformerFactory tf = TransformerFactory.newInstance(); + // Fortify Mod: prevent external entity injection + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer t = tf.newTransformer(); + t.setErrorListener(new com.occamlab.te.NullErrorListener()); + try { + t.transform(new StreamSource(f), new DOMResult(doc)); + } + catch (Exception e) { + // Issue ets-wcs10 #54 To handle invalid characters in response + if (e.getMessage().contains("An invalid XML character")) { + String validString = readValidCharsFromLogFile(f); + writeValidCharsToLogFile(f, validString); + } + // The log may not have been closed properly. + // Try again with a closing tag + RandomAccessFile raf = new RandomAccessFile(f, "r"); + int l = valueOf(raf.length()).intValue(); + byte[] buf = new byte[l + 8]; + raf.read(buf); + raf.close(); + buf[l] = '\n'; + buf[l + 1] = '<'; + buf[l + 2] = '/'; + buf[l + 3] = 'l'; + buf[l + 4] = 'o'; + buf[l + 5] = 'g'; + buf[l + 6] = '>'; + buf[l + 7] = '\n'; + doc = db.newDocument(); + tf.newTransformer().transform(new StreamSource(new ByteArrayInputStream(buf)), new DOMResult(doc)); + } + return doc; + } + else { + return null; + } + } + + public static String readValidCharsFromLogFile(File path) throws IOException { + StringBuilder sb = new StringBuilder(); + try (BufferedReader br = new BufferedReader(new FileReader(path))) { + String sCurrentLine; + while ((sCurrentLine = br.readLine()) != null) { + String strippedLine = stripNonValidXMLCharacters(sCurrentLine); + + if (strippedLine.length() != sCurrentLine.length()) { + if (strippedLine.contains("")) { + StringBuilder builder = new StringBuilder(strippedLine); + builder.insert(builder.indexOf("") + 9, ""), "]]>"); + strippedLine = builder.toString(); + } + } + sb.append(strippedLine); + } + } + if (sb.toString().indexOf("") != -1) { + sb.replace(sb.indexOf(""), sb.length(), ""); + } + return sb.toString(); + } + + public static void writeValidCharsToLogFile(File file, String validString) throws IOException { + StringWriter stringWriter = new StringWriter(); + StreamResult xmlOutput = new StreamResult(stringWriter); + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer; + try { + transformer = transformerFactory.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.CDATA_SECTION_ELEMENTS, "content"); + transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + + Source xmlInput = new StreamSource(new StringReader(validString)); + transformer.transform(xmlInput, xmlOutput); + } + catch (TransformerException e) { + System.out.println(e.getMessage()); + } + BufferedWriter writer = new BufferedWriter(new FileWriter(file)); + writer.write(xmlOutput.getWriter().toString()); + writer.close(); + } + + public static String stripNonValidXMLCharacters(String in) { + StringBuffer out = new StringBuffer(); + char current; + + if (in == null || (in.isEmpty())) + return ""; + for (int i = 0; i < in.length(); i++) { + current = in.charAt(i); + if ((current == 0x9) || (current == 0xA) || (current == 0xD) || ((current >= 0x20) && (current <= 0xD7FF)) + || ((current >= 0xE000) && (current <= 0xFFFD)) || ((current >= 0x10000) && (current <= 0x10FFFF))) + out.append(current); + } + return out.toString().replaceAll("&#", ""); + } + + // Returns the id of a test from its log document + public static String getTestIdFromLog(Document log) throws Exception { + Element starttest = DomUtils.getElementByTagName(log, "starttest"); + String namespace = starttest.getAttribute("namespace-uri"); + String localName = starttest.getAttribute("local-name"); + return "{" + namespace + "}" + localName; + } + + public static int getResultFromLog(Document log) throws Exception { + if (log != null) { + Element endtest = DomUtils.getElementByTagName(log, "endtest"); + if (endtest != null) { + return Integer.parseInt(endtest.getAttribute("result")); + } + } + return -1; + } + + // Returns the parameters to a test from its log document + public static List getParamListFromLog(net.sf.saxon.s9api.DocumentBuilder builder, Document log) + throws Exception { + List list = new ArrayList<>(); + Element starttest = (Element) log.getElementsByTagName("starttest").item(0); + for (Element param : DomUtils.getElementsByTagName(starttest, "param")) { + String value = DomUtils.getElementByTagName(param, "value").getTextContent(); + list.add(param.getAttribute("local-name") + "=" + value); + } + return list; + } + + // Returns the parameters to a test from its log document + public static XdmNode getParamsFromLog(net.sf.saxon.s9api.DocumentBuilder builder, Document log) throws Exception { + Element starttest = (Element) log.getElementsByTagName("starttest").item(0); + NodeList nl = starttest.getElementsByTagName("params"); + if (nl == null || nl.getLength() == 0) { + return null; + } + else { + Document doc = DomUtils.createDocument(nl.item(0)); + return builder.build(new DOMSource(doc)); + } + } + + // Returns the context node for a test from its log document + public static XdmNode getContextFromLog(net.sf.saxon.s9api.DocumentBuilder builder, Document log) throws Exception { + Element starttest = (Element) log.getElementsByTagName("starttest").item(0); + NodeList nl = starttest.getElementsByTagName("context"); + if (nl == null || nl.getLength() == 0) { + return null; + } + else { + Element context = (Element) nl.item(0); + Element value = (Element) context.getElementsByTagName("value").item(0); + nl = value.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node n = nl.item(i); + if (n.getNodeType() == Node.ATTRIBUTE_NODE) { + String s = DomUtils.serializeNode(value); + XdmNode xn = builder.build(new StreamSource(new CharArrayReader(s.toCharArray()))); + return (XdmNode) xn.axisIterator(Axis.ATTRIBUTE).next(); + } + else if (n.getNodeType() == Node.ELEMENT_NODE) { + Document doc = DomUtils.createDocument(n); + return builder.build(new DOMSource(doc)); + } + } + } + return null; + } + + private static Element makeTestListElement(DocumentBuilder db, Document owner, File logdir, String path) + throws Exception { + File log = new File(new File(logdir, path), "log.xml"); + Document logdoc = LogUtils.readLog(log.getParentFile(), "."); + if (logdoc == null) { + return null; + } + Element log_e = DomUtils.getElementByTagName(logdoc, "log"); + if (log_e == null) { + return null; + } + Element test = owner.createElement("test"); + int result = TECore.PASS; + String type = "Mandatory"; + boolean complete = false; + boolean childrenFailed = false; + boolean hasCache = false; + for (Element e : DomUtils.getChildElements(log_e)) { + if (e.getNodeName().equals("starttest")) { + NamedNodeMap atts = e.getAttributes(); + for (int j = 0; j < atts.getLength(); j++) { + String nodeName = atts.item(j).getNodeName(); + String nodeValue = atts.item(j).getNodeValue(); + if ("defaultResult".equals(nodeName)) { + result = Integer.parseInt(nodeValue); + } + else if ("type".equals(nodeName)) { // 2011-03-07 PwD + type = nodeValue; + } + test.setAttribute(nodeName, nodeValue); + } + } + else if (e.getNodeName().equals("endtest")) { + complete = true; + int code = Integer.parseInt(e.getAttribute("result")); + if (childrenFailed) { + result = TECore.INHERITED_FAILURE; + } + else { + result = code; + } + } + else if (e.getNodeName().equals("testcall")) { + String newpath = e.getAttribute("path"); + Element child = makeTestListElement(db, owner, logdir, newpath); + if (child != null) { + child.setAttribute("path", newpath); + int code = Integer.parseInt(child.getAttribute("result")); + if (code == TECore.FAIL || code == TECore.INHERITED_FAILURE) { + childrenFailed = true; + } + test.appendChild(child); + } + } + else if (e.getNodeName().equals("cache")) { + hasCache = true; + } + } + test.setAttribute("result", Integer.toString(result)); + test.setAttribute("complete", complete ? "yes" : "no"); + test.setAttribute("hasCache", hasCache ? "yes" : "no"); + return test; + } + + /** + * Produces a document containing a collection of tests run in a base suite. + * @param logdir A File denoting the location of the test log directory. + * @param path A session identifier. + * @param excludes A list of tests to ignore. + * @return A Document node where <test> is the document element + * @throws Exception If any errors occur. + */ + public static Document makeTestList(File logdir, String path, List> excludes) throws Exception { + // Fortify Mod: validate logdir and path + // If they don't form a valid path, throw an error + File tfile = new File(logdir, path); + TEPath tpath = new TEPath(tfile.getAbsolutePath()); + if (!tpath.isValid()) { + throw new IllegalArgumentException("Illegal path = " + tfile.getAbsolutePath()); + } + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + // Fortify Mod: Disable entity expansion to foil External Entity Injections + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc; + File testListFile = new File(logdir, path + File.separator + "testlist.xml"); + long testListDate = testListFile.lastModified(); + File rootlog = new File(logdir, path + File.separator + "log.xml"); + boolean updated; + if (testListFile.exists() && testListDate >= rootlog.lastModified()) { + try { + doc = db.parse(testListFile); + updated = (updateTestListElement(db, doc.getDocumentElement(), logdir, testListDate) != null); + } + catch (Exception e) { + + if (e.toString().contains("Premature end of file")) { + return null; + } + else { + throw new Exception("Error while writting the 'testlist.xml' file." + e); + } + } + } + else { + doc = db.newDocument(); + Element test = makeTestListElement(db, doc, logdir, path); + if (test != null) { + doc.appendChild(test); + doc.getDocumentElement().setAttribute("path", path); + } + updated = true; + } + if (updated) { + TransformerFactory tf = TransformerFactory.newInstance(); + // Fortify Mod: disable external entity injection + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer t = tf.newTransformer(); + t.setOutputProperty(OutputKeys.INDENT, "yes"); + t.transform(new DOMSource(doc), new StreamResult(testListFile)); + } + if (excludes.size() > 0) { + removeExcludes(doc.getDocumentElement(), new ArrayList<>(), excludes); + updateTestListElement(db, doc.getDocumentElement(), logdir, 0); + } + if (LOGR.isLoggable(Level.CONFIG)) { + StringBuilder msg = new StringBuilder("Read source test list in "); + msg.append(testListFile.getParent()).append("\n"); + msg.append(DomUtils.serializeNode(doc)); + LOGR.config(msg.toString()); + } + return doc; + } + + public static Document makeTestList(File logdir, String path) throws Exception { + List> excludes = new ArrayList<>(); + return makeTestList(logdir, path, excludes); + } + + /* + * Recalculate each result. If testListDate != 0, then reread new log files as well + */ + private static Element updateTestListElement(DocumentBuilder db, Element test, File logdir, long testListDate) + throws Exception { + String path = test.getAttribute("path"); + long logdate = 0; + if (testListDate > 0) { + logdate = new File(logdir, path + File.separator + "log.xml").lastModified(); + } + if (logdate > testListDate) { + Element newtest = makeTestListElement(db, test.getOwnerDocument(), logdir, path); + test.getParentNode().replaceChild(newtest, test); + return newtest; + } + else { + boolean updated = false; + boolean childrenFailed = false; + for (Element subtest : DomUtils.getChildElements(test)) { + Element newsubtest = updateTestListElement(db, subtest, logdir, testListDate); + if (newsubtest != null) { + updated = true; + int code = Integer.parseInt(newsubtest.getAttribute("result")); + if (code == TECore.FAIL || code == TECore.INHERITED_FAILURE) { + childrenFailed = true; + } + } + } + if (updated || testListDate == 0) { + int result = Integer.parseInt(test.getAttribute("result")); + int newresult = TECore.PASS; + if (result == TECore.FAIL) { + newresult = TECore.FAIL; + } + else if (childrenFailed) { + newresult = TECore.INHERITED_FAILURE; + } + else if (result == TECore.WARNING) { + newresult = TECore.WARNING; + } + if (newresult != result) { + test.setAttribute("result", Integer.toString(newresult)); + return test; + } + } + return null; + } + } + + private static void removeExcludes(Element test, List pathQName, List> excludes) + throws Exception { + List testQName = new ArrayList<>(pathQName); + String namespaceURI = test.getAttribute("namespace-uri"); + String localPart = test.getAttribute("local-name"); + String prefix = test.getAttribute("prefix"); + QName qname = new QName(namespaceURI, localPart, prefix); + testQName.add(qname); + if (excludes.contains(testQName)) { + test.getParentNode().removeChild(test); + } + else { + for (Element subtest : DomUtils.getChildElements(test)) { + removeExcludes(subtest, testQName, excludes); + } + } + } + + /** + * Generates a session identifier. The value corresponds to the name of a + * sub-directory (session) in the root test log directory. + * @return a session id string + */ + public static String generateSessionId(File logDir) { + int i = 1; + String session = "s0001"; + while (new File(logDir, session).exists() && i < 10000) { + i++; + session = "s" + Integer.toString(10000 + i).substring(1); + } + return session; + } + + /** + * Generate a file in logDir refererring all logfiles. Create a file called + * "report_logs.xml" in the log folder that includes all logs listed inside the + * directory. author F.Vitale vitale@imaa.cnr.it + * @param sessionLogDir considered log directory + * @throws Exception + */ + public static void createFullReportLog(String sessionLogDir) throws Exception { + LOGR.log(Level.WARNING, "Creating report log for " + sessionLogDir); + // Fortify Mod: validate sessionLogDir argument + TEPath tpath = new TEPath(sessionLogDir); + if (!tpath.isValid()) { + throw new IllegalArgumentException("Illegal path = " + tpath.toString()); + } + // Make sure the session log directory exits + File dir = new File(sessionLogDir); + if (!dir.exists()) { + if (!dir.mkdir()) { + if (!dir.mkdirs()) { + throw new RuntimeException("Unable to create report log directory " + sessionLogDir); + } + } + } + File xml_logs_report_file = new File(sessionLogDir + File.separator + "report_logs.xml"); + if (xml_logs_report_file.exists()) { + xml_logs_report_file.delete(); + xml_logs_report_file.createNewFile(); + } + xml_logs_report_file = new File(sessionLogDir + File.separator + "report_logs.xml"); + // xml_logs_report_file = new + // File("C:\\TE_BASE\\users\\cheazel\\dummy\\report_logs.xml"); + OutputStream report_logs = new FileOutputStream(xml_logs_report_file); + List files = null; + Document result = null; + + files = getFileListing(new File(sessionLogDir)); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + // Fortify Mod: Disable entity expansion to foil External Entity Injections + factory.setExpandEntityReferences(false); + DocumentBuilder builder = factory.newDocumentBuilder(); + + // Create the document + Document doc = builder.newDocument(); + // Fill the document + Element execution = doc.createElement("execution"); + execution.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xi", "http://www.w3.org/2001/XInclude"); + doc.appendChild(execution); + for (File file : files) { + // all files are Sorted with CompareTO + Element include = doc.createElementNS("http://www.w3.org/2001/XInclude", "xi:include"); + include.setAttribute("href", file.getAbsolutePath()); + execution.appendChild(include); + } + // Serialize the document into System.out + TransformerFactory xformFactory = TransformerFactory.newInstance(); + // Fortify Mod: disable external entity injection + xformFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer idTransform = xformFactory.newTransformer(); + Source input = new DOMSource(doc); + Result output = new StreamResult(report_logs); + idTransform.transform(input, output); + // Fortify Mod: Close report_logs and release its resources + report_logs.close(); + result = doc; // actually we do not needs results + } + + /** + * Recursively walk a directory tree and return a List of all log files found. + * @param logDir die to walk + * @return + * @throws Exception + */ + private static List getFileListing(File logDir) throws Exception { + return getFileListingLogs(logDir); + } + + /** + * Get all log files and directories and make recursive call. + * @param aStartingDir + * @return + * @throws Exception + */ + static private List getFileListingLogs(File aStartingDir) throws Exception { + List result = new ArrayList<>(); + File[] logfiles = aStartingDir.listFiles(new FileFilter() { + + @Override + public boolean accept(File pathname) { + return pathname.isFile(); + } + }); + List logFilesList = Arrays.asList(logfiles); + File[] allDirs = aStartingDir.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.isDirectory(); + } + }); + for (File file : logFilesList) { + if (file.getName().equals("log.xml")) { + result.add(file); + } + } + List allDirsList = Arrays.asList(allDirs); + allDirsList.sort(new Comparator<>() { + public int compare(File o1, File o2) { + + if (o1.lastModified() > o2.lastModified()) { + return +1; + } + else if (o1.lastModified() < o2.lastModified()) { + return -1; + } + else { + return 0; + } + } + + }); + for (File file : allDirsList) { + if (!file.isFile()) { + List deeperList = getFileListingLogs(file); + result.addAll(deeperList); + } + } + return result; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/Misc.java b/teamengine-core/src/main/java/com/occamlab/te/util/Misc.java index fd2becc07..08144a483 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/Misc.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/Misc.java @@ -1,202 +1,222 @@ -/* - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): - C. Heazel (WiSC): Added Fortify adjudication changes - */ -package com.occamlab.te.util; - -import com.occamlab.te.TEClassLoader; -import java.io.File; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.util.List; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMResult; -import javax.xml.transform.stream.StreamSource; -import javax.xml.XMLConstants; // Addition for Fortify modifications -import org.w3c.dom.Document; -import org.w3c.dom.Node; - -public class Misc { - - // Deletes a directory and its contents - public static void deleteDir(File dir) { - if (dir.isDirectory()) { - deleteDirContents(dir); - dir.delete(); - } - } - - /** - * Deletes the contents of a directory, including subdirectories. - * @param dir The directory to be emptied. - */ - public static void deleteDirContents(File dir) { - if (!dir.isDirectory() || !dir.exists()) { - throw new IllegalArgumentException(dir.getAbsolutePath() + " is not a directory or does not exist."); - } - String[] children = dir.list(); - for (int i = 0; i < children.length; i++) { - File f = new File(dir, children[i]); - if (f.isDirectory()) { - deleteDirContents(f); - } - f.delete(); - } - } - - // Deletes just the sub directories for a certain directory - public static void deleteSubDirs(File dir) { - String[] children = dir.list(); - for (int i = 0; i < children.length; i++) { - File f = new File(dir, children[i]); - if (f.isDirectory()) { - deleteDir(f); - } - } - } - - // Loads a file into memory from the classpath - public static File getResourceAsFile(String resource) { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - return new File(URLDecoder.decode(cl.getResource(resource).getFile(), StandardCharsets.UTF_8)); - } - - // Loads a DOM Document from the classpath - Document getResourceAsDoc(String resource) throws Exception { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - InputStream is = cl.getResourceAsStream(resource); - if (is != null) { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - // Fortify Mod: prevent external entity injection - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - // Fortify Mod: prevent external entity injection - TransformerFactory tf = TransformerFactory.newInstance(); - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer t = tf.newTransformer(); - // Transformer t = TransformerFactory.newInstance().newTransformer(); - // End Fortify Mod - Document doc = db.newDocument(); - t.transform(new StreamSource(is), new DOMResult(doc)); - // Fortify Mod: Close the InputStream and release its resources - is.close(); - return doc; - } - else { - return null; - } - } - - // Returns the URL for file on the classpath as a String - public static String getResourceURL(String resource) { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - return cl.getResource(resource).toString(); - } - - public static Method getMethod(String className, String methodName, TEClassLoader cl, int minArgs, int maxArgs) - throws Exception { - // cl.registerClass(className); - Class c = Class.forName(className, true, cl); - Method[] methods = c.getMethods(); - for (int i = 0; i < methods.length; i++) { - Method m = methods[i]; - int count = m.getParameterTypes().length; - if (m.getName().equals(methodName) && count >= minArgs && count <= maxArgs) { - return m; - } - } - String argsDesc = Integer.toString(minArgs); - if (maxArgs > minArgs) { - argsDesc += " to " + maxArgs + " argument"; - } - if (minArgs > 1 || maxArgs > 1) { - argsDesc += "s"; - } - throw new Exception( - "Error: Method " + methodName + " with " + argsDesc + " was not found in class " + className); - } - - public static Method getMethod(String className, String methodName, TEClassLoader cl, int argCount) - throws Exception { - return getMethod(className, methodName, cl, argCount, argCount); - } - - public static Object makeInstance(String className, List classParams, TEClassLoader cl) throws Exception { - // cl.registerClass(className); - Class c = Class.forName(className, true, cl); - Constructor[] constructors = c.getConstructors(); - int paramCount = 0; - if (classParams != null) { - paramCount = classParams.size(); - } - Object[] classParamObjects = new Object[paramCount]; - for (int i = 0; i < constructors.length; i++) { - Class[] types = constructors[i].getParameterTypes(); - if (types.length == paramCount) { - boolean constructorCorrect = true; - for (int j = 0; j < types.length; j++) { - Node n = classParams.get(j); - if (Document.class.isAssignableFrom(types[j])) { - if (n instanceof Document) { - classParamObjects[j] = (Document) n; - } - else { - classParamObjects[j] = DomUtils.createDocument(n); - } - } - else if (Node.class.isAssignableFrom(types[j])) { - classParamObjects[j] = n; - } - else if (types[j].equals(String.class)) { - classParamObjects[j] = n.getTextContent(); - } - else if (types[j].toString().equals("char")) { - classParamObjects[j] = n.getTextContent().charAt(0); - } - else if (types[j].toString().equals("boolean")) { - classParamObjects[j] = Boolean.parseBoolean(n.getTextContent()); - } - else if (types[j].toString().equals("byte")) { - classParamObjects[j] = Byte.parseByte(n.getTextContent()); - } - else if (types[j].toString().equals("short")) { - classParamObjects[j] = Short.parseShort(n.getTextContent()); - } - else if (types[j].toString().equals("int")) { - classParamObjects[j] = Integer.parseInt(n.getTextContent()); - } - else if (types[j].toString().equals("float")) { - classParamObjects[j] = Float.parseFloat(n.getTextContent()); - } - else if (types[j].toString().equals("double")) { - classParamObjects[j] = Double.parseDouble(n.getTextContent()); - } - else { - constructorCorrect = false; - break; - } - } - if (constructorCorrect) { - return constructors[i].newInstance(classParamObjects); - } - } - } - throw new Exception("No compatible constructors found in class " + className); - } - -} +/* + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): + C. Heazel (WiSC): Added Fortify adjudication changes + */ +package com.occamlab.te.util; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.occamlab.te.TEClassLoader; +import java.io.File; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.List; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.stream.StreamSource; +import javax.xml.XMLConstants; // Addition for Fortify modifications +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +public class Misc { + + // Deletes a directory and its contents + public static void deleteDir(File dir) { + if (dir.isDirectory()) { + deleteDirContents(dir); + dir.delete(); + } + } + + /** + * Deletes the contents of a directory, including subdirectories. + * @param dir The directory to be emptied. + */ + public static void deleteDirContents(File dir) { + if (!dir.isDirectory() || !dir.exists()) { + throw new IllegalArgumentException(dir.getAbsolutePath() + " is not a directory or does not exist."); + } + String[] children = dir.list(); + for (int i = 0; i < children.length; i++) { + File f = new File(dir, children[i]); + if (f.isDirectory()) { + deleteDirContents(f); + } + f.delete(); + } + } + + // Deletes just the sub directories for a certain directory + public static void deleteSubDirs(File dir) { + String[] children = dir.list(); + for (int i = 0; i < children.length; i++) { + File f = new File(dir, children[i]); + if (f.isDirectory()) { + deleteDir(f); + } + } + } + + // Loads a file into memory from the classpath + public static File getResourceAsFile(String resource) { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + return new File(URLDecoder.decode(cl.getResource(resource).getFile(), StandardCharsets.UTF_8)); + } + + // Loads a DOM Document from the classpath + Document getResourceAsDoc(String resource) throws Exception { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + InputStream is = cl.getResourceAsStream(resource); + if (is != null) { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + // Fortify Mod: prevent external entity injection + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + // Fortify Mod: prevent external entity injection + TransformerFactory tf = TransformerFactory.newInstance(); + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer t = tf.newTransformer(); + // Transformer t = TransformerFactory.newInstance().newTransformer(); + // End Fortify Mod + Document doc = db.newDocument(); + t.transform(new StreamSource(is), new DOMResult(doc)); + // Fortify Mod: Close the InputStream and release its resources + is.close(); + return doc; + } + else { + return null; + } + } + + // Returns the URL for file on the classpath as a String + public static String getResourceURL(String resource) { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + return cl.getResource(resource).toString(); + } + + public static Method getMethod(String className, String methodName, TEClassLoader cl, int minArgs, int maxArgs) + throws Exception { + // cl.registerClass(className); + Class c = Class.forName(className, true, cl); + Method[] methods = c.getMethods(); + for (int i = 0; i < methods.length; i++) { + Method m = methods[i]; + int count = m.getParameterTypes().length; + if (m.getName().equals(methodName) && count >= minArgs && count <= maxArgs) { + return m; + } + } + String argsDesc = Integer.toString(minArgs); + if (maxArgs > minArgs) { + argsDesc += " to " + maxArgs + " argument"; + } + if (minArgs > 1 || maxArgs > 1) { + argsDesc += "s"; + } + throw new Exception( + "Error: Method " + methodName + " with " + argsDesc + " was not found in class " + className); + } + + public static Method getMethod(String className, String methodName, TEClassLoader cl, int argCount) + throws Exception { + return getMethod(className, methodName, cl, argCount, argCount); + } + + public static Object makeInstance(String className, List classParams, TEClassLoader cl) throws Exception { + // cl.registerClass(className); + Class c = Class.forName(className, true, cl); + Constructor[] constructors = c.getConstructors(); + int paramCount = 0; + if (classParams != null) { + paramCount = classParams.size(); + } + Object[] classParamObjects = new Object[paramCount]; + for (int i = 0; i < constructors.length; i++) { + Class[] types = constructors[i].getParameterTypes(); + if (types.length == paramCount) { + boolean constructorCorrect = true; + for (int j = 0; j < types.length; j++) { + Node n = classParams.get(j); + if (Document.class.isAssignableFrom(types[j])) { + if (n instanceof Document) { + classParamObjects[j] = (Document) n; + } + else { + classParamObjects[j] = DomUtils.createDocument(n); + } + } + else if (Node.class.isAssignableFrom(types[j])) { + classParamObjects[j] = n; + } + else if (types[j].equals(String.class)) { + classParamObjects[j] = n.getTextContent(); + } + else if (types[j].toString().equals("char")) { + classParamObjects[j] = n.getTextContent().charAt(0); + } + else if (types[j].toString().equals("boolean")) { + classParamObjects[j] = Boolean.parseBoolean(n.getTextContent()); + } + else if (types[j].toString().equals("byte")) { + classParamObjects[j] = Byte.parseByte(n.getTextContent()); + } + else if (types[j].toString().equals("short")) { + classParamObjects[j] = Short.parseShort(n.getTextContent()); + } + else if (types[j].toString().equals("int")) { + classParamObjects[j] = Integer.parseInt(n.getTextContent()); + } + else if (types[j].toString().equals("float")) { + classParamObjects[j] = Float.parseFloat(n.getTextContent()); + } + else if (types[j].toString().equals("double")) { + classParamObjects[j] = Double.parseDouble(n.getTextContent()); + } + else { + constructorCorrect = false; + break; + } + } + if (constructorCorrect) { + return constructors[i].newInstance(classParamObjects); + } + } + } + throw new Exception("No compatible constructors found in class " + className); + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/NullWriter.java b/teamengine-core/src/main/java/com/occamlab/te/util/NullWriter.java index 265da3945..7198789d1 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/NullWriter.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/NullWriter.java @@ -4,6 +4,26 @@ */ package com.occamlab.te.util; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.IOException; import java.io.Writer; diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/Soap11MessageBuilder.java b/teamengine-core/src/main/java/com/occamlab/te/util/Soap11MessageBuilder.java index 0abc6897a..2ac91dc14 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/Soap11MessageBuilder.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/Soap11MessageBuilder.java @@ -9,6 +9,26 @@ Intecs SPA are Copyright (C) 2008-2009, Intecs SPA. All Rights Reserved. ****************************************************************************/ package com.occamlab.te.util; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.util.List; import org.w3c.dom.Attr; import org.w3c.dom.Document; diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/Soap12MessageBuilder.java b/teamengine-core/src/main/java/com/occamlab/te/util/Soap12MessageBuilder.java index 195708aaf..2365a1f62 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/Soap12MessageBuilder.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/Soap12MessageBuilder.java @@ -9,6 +9,26 @@ Intecs SPA are Copyright (C) 2008-2009, Intecs SPA. All Rights Reserved. ****************************************************************************/ package com.occamlab.te.util; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.util.List; import org.w3c.dom.Attr; import org.w3c.dom.Document; diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/SoapUtils.java b/teamengine-core/src/main/java/com/occamlab/te/util/SoapUtils.java index c77aa3ffd..117c1b7d2 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/SoapUtils.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/SoapUtils.java @@ -1,173 +1,193 @@ -/**************************************************************************** - * - * The Original Code is TEAM Engine. - * - * The Initial Developer of the Original Code is Intecs SPA. Portions created by - * Intecs SPA are Copyright (C) 2008-2009, Intecs SPA. All Rights Reserved. - * - * Contributor(s): - * C. Heazel (WiSC): Added Fortify adjudication changes - * - ****************************************************************************/ -package com.occamlab.te.util; - -import java.io.ByteArrayOutputStream; - -import java.io.InputStream; -import java.util.List; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMResult; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; -import javax.xml.XMLConstants; // Addition for Fortify modifications - -import org.w3c.dom.Attr; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import javax.xml.transform.OutputKeys; - -/** - * @author Simone Gianfranceschi - */ -public class SoapUtils { - - public static final String SOAP_V_1_1 = "1.1"; - - public static final String SOAP_V_1_2 = "1.2"; - - /** - * A method to get the SOAP message from the input stream. author Simone - * Gianfranceschi - * @param in the input stream to be used to get the SOAP message. - * @return the SOAP message - * - */ - public static Document getSOAPMessage(InputStream in) throws Exception { - /* - * ByteArrayOutputStream out = new ByteArrayOutputStream(); int b; while ((b = - * in.read()) != -1) { out.write(b); } - * - * System.out.println("OUT:" + out.toString()); - */ - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - // Fortify Mod: Disable entity expansion to foil External Entity Injections - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document soapMessage = db.newDocument(); - // Fortify Mod: prevent external entity injection - TransformerFactory tf = TransformerFactory.newInstance(); - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer t = tf.newTransformer(); - // End Fortify Mod - t.transform(new StreamSource(in), new DOMResult(soapMessage)); - return soapMessage; - } - - /** - * A method to extract the content of the SOAP body. author Simone Gianfranceschi - * @param soapMessage the SOAP message. - * @return the content of the body of the input SOAP message. - * - */ - public static Document getSoapBody(Document soapMessage) throws Exception { - Element envelope = soapMessage.getDocumentElement(); - Element body = DomUtils.getChildElement(DomUtils.getElementByTagName(envelope, envelope.getPrefix() + ":Body")); - Document content = DomUtils.createDocument(body); - - Element documentRoot = content.getDocumentElement(); - addNSdeclarations(envelope, documentRoot); - addNSdeclarations(body, documentRoot); - return content; - } - - /** - * A method to copy namespaces declarations. author Simone Gianfranceschi - * @param source the source message containing the namespaces to be copied on the - * target message. - * @param target the target message. - * - */ - public static void addNSdeclarations(Element source, Element target) throws Exception { - NamedNodeMap sourceAttributes = source.getAttributes(); - Attr attribute; - String attributeName; - for (int i = 0; i <= sourceAttributes.getLength() - 1; i++) { - attribute = (Attr) sourceAttributes.item(i); - attributeName = attribute.getName(); - if (attributeName.startsWith("xmlns") && !attributeName.startsWith("xmlns:soap-env")) { - // System.out.println("XMLNS:" + - // attributeName+":"+attribute.getValue()); - target.setAttribute(attributeName, attribute.getValue()); - } - } - } - - /** - * A method to create a SOAP message and retrieve it as byte. author Simone - * Gianfranceschi - * @param version the SOAP version to be used (1.1 or 1.2). - * @param headerBlocks the list of Header Blocks to be included in the SOAP Header . - * @param body the XML message to be included in the SOAP BODY element. - * @param encoding the encoding to be used for the message creation. - * @return The created SOAP message as byte. - * - */ - public static byte[] getSoapMessageAsByte(String version, List headerBlocks, Element body, String encoding) - throws Exception { - Document message = createSoapMessage(version, headerBlocks, body); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - TransformerFactory tf = TransformerFactory.newInstance(); - // Fortify Mod: prevent external entity injection - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer t = tf.newTransformer(); - // End Fortify Mod - t.setOutputProperty(OutputKeys.ENCODING, encoding); - t.transform(new DOMSource(message), new StreamResult(baos)); - - // System.out.println("SOAP MESSAGE : " + baos.toString()); - - return baos.toByteArray(); - } - - /** - * A method to create a SOAP message. The SOAP message, including the Header is - * created and returned as DOM Document. author Simone Gianfranceschi - * @param version the SOAP version to be used (1.1 or 1.2). - * @param headerBlocks the list of Header Blocks to be included in the SOAP Header . - * @param body the XML message to be included in the SOAP BODY element. - * @return The created SOAP message as document. - * - */ - public static Document createSoapMessage(String version, List headerBlocks, Element body) throws Exception { - Document message = null; - NodeList children = body.getChildNodes(); - // Loop in order to remove dummy nodes (spaces, CR) - for (int i = 0; i < children.getLength(); i++) { - if (children.item(i).getNodeType() != Node.ELEMENT_NODE - && children.item(i).getNodeType() == Node.TEXT_NODE) { - Document bodyDoc = DomUtils.convertToElementNode(body.getTextContent().trim()); - if (bodyDoc.getFirstChild().getNodeType() == Node.ELEMENT_NODE) { - body = (Element) bodyDoc.getFirstChild(); - } - } - if (version.equals(SOAP_V_1_1)) { - message = Soap11MessageBuilder.getSoapMessage(headerBlocks, body); - } - else { - message = Soap12MessageBuilder.getSoapMessage(headerBlocks, body); - } - break; - } - return message; - } - -} +/**************************************************************************** + * + * The Original Code is TEAM Engine. + * + * The Initial Developer of the Original Code is Intecs SPA. Portions created by + * Intecs SPA are Copyright (C) 2008-2009, Intecs SPA. All Rights Reserved. + * + * Contributor(s): + * C. Heazel (WiSC): Added Fortify adjudication changes + * + ****************************************************************************/ +package com.occamlab.te.util; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.ByteArrayOutputStream; + +import java.io.InputStream; +import java.util.List; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import javax.xml.XMLConstants; // Addition for Fortify modifications + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import javax.xml.transform.OutputKeys; + +/** + * @author Simone Gianfranceschi + */ +public class SoapUtils { + + public static final String SOAP_V_1_1 = "1.1"; + + public static final String SOAP_V_1_2 = "1.2"; + + /** + * A method to get the SOAP message from the input stream. author Simone + * Gianfranceschi + * @param in the input stream to be used to get the SOAP message. + * @return the SOAP message + * + */ + public static Document getSOAPMessage(InputStream in) throws Exception { + /* + * ByteArrayOutputStream out = new ByteArrayOutputStream(); int b; while ((b = + * in.read()) != -1) { out.write(b); } + * + * System.out.println("OUT:" + out.toString()); + */ + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + // Fortify Mod: Disable entity expansion to foil External Entity Injections + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document soapMessage = db.newDocument(); + // Fortify Mod: prevent external entity injection + TransformerFactory tf = TransformerFactory.newInstance(); + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer t = tf.newTransformer(); + // End Fortify Mod + t.transform(new StreamSource(in), new DOMResult(soapMessage)); + return soapMessage; + } + + /** + * A method to extract the content of the SOAP body. author Simone Gianfranceschi + * @param soapMessage the SOAP message. + * @return the content of the body of the input SOAP message. + * + */ + public static Document getSoapBody(Document soapMessage) throws Exception { + Element envelope = soapMessage.getDocumentElement(); + Element body = DomUtils.getChildElement(DomUtils.getElementByTagName(envelope, envelope.getPrefix() + ":Body")); + Document content = DomUtils.createDocument(body); + + Element documentRoot = content.getDocumentElement(); + addNSdeclarations(envelope, documentRoot); + addNSdeclarations(body, documentRoot); + return content; + } + + /** + * A method to copy namespaces declarations. author Simone Gianfranceschi + * @param source the source message containing the namespaces to be copied on the + * target message. + * @param target the target message. + * + */ + public static void addNSdeclarations(Element source, Element target) throws Exception { + NamedNodeMap sourceAttributes = source.getAttributes(); + Attr attribute; + String attributeName; + for (int i = 0; i <= sourceAttributes.getLength() - 1; i++) { + attribute = (Attr) sourceAttributes.item(i); + attributeName = attribute.getName(); + if (attributeName.startsWith("xmlns") && !attributeName.startsWith("xmlns:soap-env")) { + // System.out.println("XMLNS:" + + // attributeName+":"+attribute.getValue()); + target.setAttribute(attributeName, attribute.getValue()); + } + } + } + + /** + * A method to create a SOAP message and retrieve it as byte. author Simone + * Gianfranceschi + * @param version the SOAP version to be used (1.1 or 1.2). + * @param headerBlocks the list of Header Blocks to be included in the SOAP Header . + * @param body the XML message to be included in the SOAP BODY element. + * @param encoding the encoding to be used for the message creation. + * @return The created SOAP message as byte. + * + */ + public static byte[] getSoapMessageAsByte(String version, List headerBlocks, Element body, String encoding) + throws Exception { + Document message = createSoapMessage(version, headerBlocks, body); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + TransformerFactory tf = TransformerFactory.newInstance(); + // Fortify Mod: prevent external entity injection + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer t = tf.newTransformer(); + // End Fortify Mod + t.setOutputProperty(OutputKeys.ENCODING, encoding); + t.transform(new DOMSource(message), new StreamResult(baos)); + + // System.out.println("SOAP MESSAGE : " + baos.toString()); + + return baos.toByteArray(); + } + + /** + * A method to create a SOAP message. The SOAP message, including the Header is + * created and returned as DOM Document. author Simone Gianfranceschi + * @param version the SOAP version to be used (1.1 or 1.2). + * @param headerBlocks the list of Header Blocks to be included in the SOAP Header . + * @param body the XML message to be included in the SOAP BODY element. + * @return The created SOAP message as document. + * + */ + public static Document createSoapMessage(String version, List headerBlocks, Element body) throws Exception { + Document message = null; + NodeList children = body.getChildNodes(); + // Loop in order to remove dummy nodes (spaces, CR) + for (int i = 0; i < children.getLength(); i++) { + if (children.item(i).getNodeType() != Node.ELEMENT_NODE + && children.item(i).getNodeType() == Node.TEXT_NODE) { + Document bodyDoc = DomUtils.convertToElementNode(body.getTextContent().trim()); + if (bodyDoc.getFirstChild().getNodeType() == Node.ELEMENT_NODE) { + body = (Element) bodyDoc.getFirstChild(); + } + } + if (version.equals(SOAP_V_1_1)) { + message = Soap11MessageBuilder.getSoapMessage(headerBlocks, body); + } + else { + message = Soap12MessageBuilder.getSoapMessage(headerBlocks, body); + } + break; + } + return message; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/Stopwatch.java b/teamengine-core/src/main/java/com/occamlab/te/util/Stopwatch.java index 518bdabcc..9af7ecbc2 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/Stopwatch.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/Stopwatch.java @@ -1,41 +1,61 @@ -package com.occamlab.te.util; - -import java.util.Map; -import java.util.HashMap; -import java.util.Date; - -/** - * Support ctl:startStopwatch and ctl:elapsedTime functions so test script authors can - * time execution of test activities. - * - * @author Paul Daisey (Image Matters LLC) - * - */ -public class Stopwatch { - - static Map watchesMap = new HashMap<>(); - - /** - * Start a named Stopwatch - * @param watchName - */ - public static void start(String watchName) { - watchesMap.put(watchName, new Date()); - } - - /** - * @param watchName - * @return elapsed time in milliseconds for a named Watch, or 0 if watchName not - * started - */ - public static String elapsedTime(String watchName) { - long elapsed = 0; - Date start = watchesMap.get(watchName); - if (start != null) { - Date end = new Date(); - elapsed = end.getTime() - start.getTime(); - } - return Long.toString(elapsed); - } - -} +package com.occamlab.te.util; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.Map; +import java.util.HashMap; +import java.util.Date; + +/** + * Support ctl:startStopwatch and ctl:elapsedTime functions so test script authors can + * time execution of test activities. + * + * @author Paul Daisey (Image Matters LLC) + * + */ +public class Stopwatch { + + static Map watchesMap = new HashMap<>(); + + /** + * Start a named Stopwatch + * @param watchName + */ + public static void start(String watchName) { + watchesMap.put(watchName, new Date()); + } + + /** + * @param watchName + * @return elapsed time in milliseconds for a named Watch, or 0 if watchName not + * started + */ + public static String elapsedTime(String watchName) { + long elapsed = 0; + Date start = watchesMap.get(watchName); + if (start != null) { + Date end = new Date(); + elapsed = end.getTime() - start.getTime(); + } + return Long.toString(elapsed); + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/StringUtils.java b/teamengine-core/src/main/java/com/occamlab/te/util/StringUtils.java index 43335d68b..4e878c993 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/StringUtils.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/StringUtils.java @@ -1,76 +1,96 @@ -package com.occamlab.te.util; - -/** - * Utilities to do more advanced processing on Strings than what is available in XSLT. - * - * @author jparrpearson - */ -public class StringUtils { - - /** - * Extracts the path from a file path string (everything before the last '/'). - * @param filePath the string to parse - * @return the path without the filename, or the original path/string if no occurance - * of a dir seperator - */ - public static String getPathFromString(String filePath) { - String newPath = filePath; - - int forwardInd = filePath.lastIndexOf("/"); - int backInd = filePath.lastIndexOf("\\"); - - if (forwardInd > backInd) { - newPath = filePath.substring(0, forwardInd + 1); - } - else { - newPath = filePath.substring(0, backInd + 1); - } - - // still original if no occurance of "/" or "\" - return newPath; - } - - /** - * Extracts the filename from a path. - * @param filePath the string to parse - * @return the path containing only the filename itself - */ - public static String getFilenameFromString(String filePath) { - String newPath = filePath; - - int forwardInd = filePath.lastIndexOf("/"); - int backInd = filePath.lastIndexOf("\\"); - - if (forwardInd > backInd) { - newPath = filePath.substring(forwardInd + 1); - } - else { - newPath = filePath.substring(backInd + 1); - } - - // still original if no occurance of "/" or "\" - return newPath; - } - - // Replaces all occurences of match in str with replacement - public static String replaceAll(String str, String match, String replacement) { - String newStr = str; - int i = newStr.indexOf(match); - while (i >= 0) { - newStr = newStr.substring(0, i) + replacement + newStr.substring(i + match.length()); - i = newStr.indexOf(match); - } - return newStr; - } - - public static String escapeXML(String str) { - String ret = str; - ret = ret.replaceAll("\"", """); - ret = ret.replaceAll("&", "&"); - ret = ret.replaceAll("<", "<"); - ret = ret.replaceAll(">", ">"); - ret = ret.replaceAll("'", "'"); - return ret; - } - -} \ No newline at end of file +package com.occamlab.te.util; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +/** + * Utilities to do more advanced processing on Strings than what is available in XSLT. + * + * @author jparrpearson + */ +public class StringUtils { + + /** + * Extracts the path from a file path string (everything before the last '/'). + * @param filePath the string to parse + * @return the path without the filename, or the original path/string if no occurance + * of a dir seperator + */ + public static String getPathFromString(String filePath) { + String newPath = filePath; + + int forwardInd = filePath.lastIndexOf("/"); + int backInd = filePath.lastIndexOf("\\"); + + if (forwardInd > backInd) { + newPath = filePath.substring(0, forwardInd + 1); + } + else { + newPath = filePath.substring(0, backInd + 1); + } + + // still original if no occurance of "/" or "\" + return newPath; + } + + /** + * Extracts the filename from a path. + * @param filePath the string to parse + * @return the path containing only the filename itself + */ + public static String getFilenameFromString(String filePath) { + String newPath = filePath; + + int forwardInd = filePath.lastIndexOf("/"); + int backInd = filePath.lastIndexOf("\\"); + + if (forwardInd > backInd) { + newPath = filePath.substring(forwardInd + 1); + } + else { + newPath = filePath.substring(backInd + 1); + } + + // still original if no occurance of "/" or "\" + return newPath; + } + + // Replaces all occurences of match in str with replacement + public static String replaceAll(String str, String match, String replacement) { + String newStr = str; + int i = newStr.indexOf(match); + while (i >= 0) { + newStr = newStr.substring(0, i) + replacement + newStr.substring(i + match.length()); + i = newStr.indexOf(match); + } + return newStr; + } + + public static String escapeXML(String str) { + String ret = str; + ret = ret.replaceAll("\"", """); + ret = ret.replaceAll("&", "&"); + ret = ret.replaceAll("<", "<"); + ret = ret.replaceAll(">", ">"); + ret = ret.replaceAll("'", "'"); + return ret; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/TEPath.java b/teamengine-core/src/main/java/com/occamlab/te/util/TEPath.java index a01f8dc66..05550d9cb 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/TEPath.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/TEPath.java @@ -1,5 +1,25 @@ package com.occamlab.te.util; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.IOError; import java.io.IOException; import java.io.File; diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/URLConnectionUtils.java b/teamengine-core/src/main/java/com/occamlab/te/util/URLConnectionUtils.java index cb3c5b697..90bef981e 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/URLConnectionUtils.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/URLConnectionUtils.java @@ -1,83 +1,103 @@ -package com.occamlab.te.util; - -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URLConnection; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Class of utilities for URL Connections, Java 7 (JDK 1.7.0) and later. - * - * @author Paul Daisey (Image Matters LLC) - * - */ -public class URLConnectionUtils { - - private static final Logger LOGR = Logger.getLogger(URLConnectionUtils.class.getName()); - - static { - try { - System.setProperty("sun.net.http.errorstream.enableBuffering", "true"); - System.setProperty("sun.net.http.errorstream.timeout", "600"); - } - catch (Exception e) { - LOGR.warning("Failed to enable buffering of error stream.\n" + e.getMessage()); - e.fillInStackTrace(); - e.printStackTrace(System.err); - } - } - - /** - * Get an input stream from a URL connection. In case of an IOException, get the - * ErrorStream instead, if it is available. This makes it possible to obtain an - * ows:ExceptionReport when the server returns HTTP code 400 Bad Request. - * - * This method depends upon features of class - * sun.net.www.protocol.http.HttpURLConnection introduced in Java version 7 (JDK - * 1.7.0). From its Javadoc: - * - * System properties related to error stream handling: - * - * sun.net.http.errorstream.enableBuffering = - * - * With the above system property set to true (default is false), when the response - * code is >=400, the HTTP handler will try to buffer the response body (up to a - * certain amount and within a time limit). Thus freeing up the underlying socket - * connection for reuse. The rationale behind this is that usually when the server - * responds with a >=400 error (client error or server error, such as 404 file not - * found), the server will send a small response body to explain who to contact and - * what to do to recover. With this property set to true, even if the application - * doesn't call getErrorStream(), read the response body, and then call close(), the - * underlying socket connection can still be kept-alive and reused. The following two - * system properties provide further control to the error stream buffering behaviour. - * - * sun.net.http.errorstream.timeout = the timeout (in millisec) waiting the - * error stream to be buffered; default is 300 ms - * - * sun.net.http.errorstream.bufferSize = the size (in bytes) to use for the - * buffering the error stream; default is 4k - * @return InputStream from URLConnection if available, or the error stream if the - * connection failed but the server sent useful data, or null. - */ - public static InputStream getInputStream(URLConnection uc) throws IOException { - InputStream is = null; - try { - is = uc.getInputStream(); - } - catch (IOException ioe) { - if (LOGR.isLoggable(Level.FINE)) { - String msg = String.format("Failed to resolve URL %s.\nTrying error stream...\n %s", uc.getURL(), - ioe.getMessage()); - LOGR.fine(msg); - } - if (HttpURLConnection.class.isInstance(uc)) { - HttpURLConnection huc = (HttpURLConnection) uc; - is = huc.getErrorStream(); - } - } - return is; - } - -} +package com.occamlab.te.util; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URLConnection; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Class of utilities for URL Connections, Java 7 (JDK 1.7.0) and later. + * + * @author Paul Daisey (Image Matters LLC) + * + */ +public class URLConnectionUtils { + + private static final Logger LOGR = Logger.getLogger(URLConnectionUtils.class.getName()); + + static { + try { + System.setProperty("sun.net.http.errorstream.enableBuffering", "true"); + System.setProperty("sun.net.http.errorstream.timeout", "600"); + } + catch (Exception e) { + LOGR.warning("Failed to enable buffering of error stream.\n" + e.getMessage()); + e.fillInStackTrace(); + e.printStackTrace(System.err); + } + } + + /** + * Get an input stream from a URL connection. In case of an IOException, get the + * ErrorStream instead, if it is available. This makes it possible to obtain an + * ows:ExceptionReport when the server returns HTTP code 400 Bad Request. + * + * This method depends upon features of class + * sun.net.www.protocol.http.HttpURLConnection introduced in Java version 7 (JDK + * 1.7.0). From its Javadoc: + * + * System properties related to error stream handling: + * + * sun.net.http.errorstream.enableBuffering = + * + * With the above system property set to true (default is false), when the response + * code is >=400, the HTTP handler will try to buffer the response body (up to a + * certain amount and within a time limit). Thus freeing up the underlying socket + * connection for reuse. The rationale behind this is that usually when the server + * responds with a >=400 error (client error or server error, such as 404 file not + * found), the server will send a small response body to explain who to contact and + * what to do to recover. With this property set to true, even if the application + * doesn't call getErrorStream(), read the response body, and then call close(), the + * underlying socket connection can still be kept-alive and reused. The following two + * system properties provide further control to the error stream buffering behaviour. + * + * sun.net.http.errorstream.timeout = the timeout (in millisec) waiting the + * error stream to be buffered; default is 300 ms + * + * sun.net.http.errorstream.bufferSize = the size (in bytes) to use for the + * buffering the error stream; default is 4k + * @return InputStream from URLConnection if available, or the error stream if the + * connection failed but the server sent useful data, or null. + */ + public static InputStream getInputStream(URLConnection uc) throws IOException { + InputStream is = null; + try { + is = uc.getInputStream(); + } + catch (IOException ioe) { + if (LOGR.isLoggable(Level.FINE)) { + String msg = String.format("Failed to resolve URL %s.\nTrying error stream...\n %s", uc.getURL(), + ioe.getMessage()); + LOGR.fine(msg); + } + if (HttpURLConnection.class.isInstance(uc)) { + HttpURLConnection huc = (HttpURLConnection) uc; + is = huc.getErrorStream(); + } + } + return is; + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/Utils.java b/teamengine-core/src/main/java/com/occamlab/te/util/Utils.java index 507c66a6a..6dd5e1563 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/Utils.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/Utils.java @@ -1,289 +1,309 @@ -/** - * ************************************************************************** - * - * Contributor(s): - * C. Heazel (WiSC): Added Fortify adjudication changes - * - *************************************************************************** - */ -package com.occamlab.te.util; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.xml.namespace.NamespaceContext; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathFactory; - -import org.apache.commons.io.FileUtils; -import org.w3c.dom.Document; -import org.xml.sax.InputSource; - -/** - * Provides various utility methods (general collection). - * - * @author jparrpearson - */ -public class Utils { - - private static Logger jlogger = Logger.getLogger("com.occamlab.te.util.Utils"); - - private static String JAR_URI_PREFIX = "jar:file:"; - - /** - * Returns a random string of a certain length - * - */ - public static String randomString(int len, Random random) { - if (len < 1) { - return ""; - } - int start = ' '; - int end = 'z' + 1; - - StringBuffer buffer = new StringBuffer(); - int gap = end - start; - - while (len-- != 0) { - char ch; - ch = (char) (random.nextInt(gap) + start); - - if (Character.isLetterOrDigit(ch)) { - buffer.append(ch); - } - else { - len++; - } - } - return buffer.toString(); - } - - /** - * Uses MD5 to create a hash value for the given String - * - */ - public static String generateMD5(String text) { - byte[] md5hash = null; - try { - MessageDigest md; - md = MessageDigest.getInstance("MD5"); - md5hash = new byte[8]; - md.update(text.getBytes(StandardCharsets.ISO_8859_1), 0, text.length()); - md5hash = md.digest(); - } - catch (Exception e) { - jlogger.log(Level.SEVERE, "Error generating MD5: " + e.getMessage(), e); - - System.out.println("Error generating MD5: " + e.getMessage()); - return ""; - } - return convertToHex(md5hash); - } - - /** - * Converts a String to Hex digits - * - */ - private static String convertToHex(byte[] data) { - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < data.length; i++) { - int halfbyte = (data[i] >>> 4) & 0x0F; - int two_halfs = 0; - do { - if ((0 <= halfbyte) && (halfbyte <= 9)) { - buf.append((char) ('0' + halfbyte)); - } - else { - buf.append((char) ('a' + (halfbyte - 10))); - } - halfbyte = data[i] & 0x0F; - } - while (two_halfs++ < 1); - } - return buf.toString(); - } - - /** - * Converts an XPointer to XPath and evaulates the result (JAXP) - * - */ - public static String evaluateXPointer(String xpointer, InputStream is) { - String results = ""; - // Parse the XPointer into usable namespaces and XPath expressions - int xmlnsStart = xpointer.indexOf("xmlns(") + "xmlns(".length(); - int xmlnsEnd = xpointer.indexOf(")", xmlnsStart); - int xpathStart = xpointer.indexOf("xpointer(") + "xpointer(".length(); - int xpathEnd = xpointer.indexOf(")", xpathStart); - String xmlnsStr = xpointer.substring(xmlnsStart, xmlnsEnd); - String xpathStr = xpointer.substring(xpathStart, xpathEnd); - // System.out.println("xmlnsStr: "+xmlnsStr+" xpathStr: "+xpathStr); - try { - XPath xpath = XPathFactory.newInstance().newXPath(); - String[] namespaces = xmlnsStr.split(","); - // Add namespaces to XPath element - MyNamespaceContext context = new MyNamespaceContext(); - for (int i = 0; i < namespaces.length; i++) { - String[] xmlnsParts = namespaces[i].split("="); - context.setNamespace(xmlnsParts[0], xmlnsParts[1]); - xpath.setNamespaceContext(context); - } - InputSource src = new InputSource(is); - results = (String) xpath.evaluate(xpathStr, src); - // System.out.println("results: "+results); - } - catch (Exception e) { - jlogger.log(Level.SEVERE, "Error in evaluating XPointer. " + e.getMessage(), e); - - System.out.println("Error in evaluating XPointer. " + e.getMessage()); - } - return results; - } - - public static String evaluateXPointer(String xpointer, Document doc) { - InputStream is = null; - try { - is = IOUtils.DocumentToInputStream(doc); - } - catch (IOException e) { - jlogger.log(Level.SEVERE, "evaluateXPointer", e); - - } - - return evaluateXPointer(xpointer, is); - } - - public static String evaluateXPointer(String xpointer, byte[] bytes) { - Document doc = null; - try { - ByteArrayInputStream baip = new ByteArrayInputStream(bytes); - System.setProperty("javax.xml.parsers.DocumentBuilderFactory", - "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl"); - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - // Fortify Mod: prevent external entity injection - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - doc = db.parse(baip); - } - catch (Exception e) { - jlogger.log(Level.SEVERE, "evaluateXPointer", e); - - } - - return evaluateXPointer(xpointer, doc); - } - - /** - * Custom namespace class for adding additional namespaces for XPath evaluation - * - */ - public static class MyNamespaceContext implements NamespaceContext { - - private Map map; - - public MyNamespaceContext() { - map = new HashMap<>(); - } - - public void setNamespace(String prefix, String namespaceURI) { - map.put(prefix, namespaceURI); - } - - public String getNamespaceURI(String prefix) { - return (String) map.get(prefix); - } - - public String getPrefix(String namespaceURI) { - Set keys = map.keySet(); - for (Iterator iterator = keys.iterator(); iterator.hasNext();) { - String prefix = (String) iterator.next(); - String uri = (String) map.get(prefix); - if (uri.equals(namespaceURI)) - return prefix; - } - return null; - } - - public Iterator getPrefixes(String namespaceURI) { - List prefixes = new ArrayList<>(); - Set keys = map.keySet(); - for (Iterator iterator = keys.iterator(); iterator.hasNext();) { - String prefix = (String) iterator.next(); - String uri = (String) map.get(prefix); - if (uri.equals(namespaceURI)) - prefixes.add(prefix); - } - return prefixes.iterator(); - } - - } - - public static void copyResourceDir(URL resourceDirUrl, File destDir) throws IOException { - - String resourceDirUrlString = resourceDirUrl.toString(); - String resourceDir = resourceDirUrl.getPath(); - - int indexOfExcMark = resourceDirUrlString.indexOf("!"); - - if (resourceDirUrlString.startsWith(JAR_URI_PREFIX) && indexOfExcMark > -1) { - try { - copyResourcesFromJar( - new JarFile(resourceDirUrlString.substring(JAR_URI_PREFIX.length(), indexOfExcMark)), - resourceDirUrlString.substring(indexOfExcMark + 2), destDir); - } - catch (IOException e) { - jlogger.log(Level.SEVERE, "Could not copy resources from jar.", e); - } - } - else { - FileUtils.copyDirectory(new File(resourceDir), destDir); - } - } - - private static void copyResourcesFromJar(JarFile jarFile, String jarDir, File htmlOutput) throws IOException { - for (Enumeration jarEntries = jarFile.entries(); jarEntries.hasMoreElements();) { - JarEntry jarEntry = jarEntries.nextElement(); - if (jarEntry.getName().startsWith(jarDir + "/") && !jarEntry.isDirectory()) { - File dest = new File( - htmlOutput.getAbsolutePath() + "/" + jarEntry.getName().substring(jarDir.length() + 1)); - File parent = dest.getParentFile(); - if (parent != null) { - parent.mkdirs(); - } - try (FileOutputStream out = new FileOutputStream(dest); - InputStream in = jarFile.getInputStream(jarEntry)) { - byte[] buffer = new byte[8 * 1024]; - - int s = 0; - while ((s = in.read(buffer)) > 0) { - out.write(buffer, 0, s); - } - } - catch (IOException e) { - throw new IOException("Could not copy resource from jar file: " + jarEntry.getName(), e); - } - } - } - } - -} +/** + * ************************************************************************** + * + * Contributor(s): + * C. Heazel (WiSC): Added Fortify adjudication changes + * + *************************************************************************** + */ +package com.occamlab.te.util; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathFactory; + +import org.apache.commons.io.FileUtils; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; + +/** + * Provides various utility methods (general collection). + * + * @author jparrpearson + */ +public class Utils { + + private static Logger jlogger = Logger.getLogger("com.occamlab.te.util.Utils"); + + private static String JAR_URI_PREFIX = "jar:file:"; + + /** + * Returns a random string of a certain length + * + */ + public static String randomString(int len, Random random) { + if (len < 1) { + return ""; + } + int start = ' '; + int end = 'z' + 1; + + StringBuffer buffer = new StringBuffer(); + int gap = end - start; + + while (len-- != 0) { + char ch; + ch = (char) (random.nextInt(gap) + start); + + if (Character.isLetterOrDigit(ch)) { + buffer.append(ch); + } + else { + len++; + } + } + return buffer.toString(); + } + + /** + * Uses MD5 to create a hash value for the given String + * + */ + public static String generateMD5(String text) { + byte[] md5hash = null; + try { + MessageDigest md; + md = MessageDigest.getInstance("MD5"); + md5hash = new byte[8]; + md.update(text.getBytes(StandardCharsets.ISO_8859_1), 0, text.length()); + md5hash = md.digest(); + } + catch (Exception e) { + jlogger.log(Level.SEVERE, "Error generating MD5: " + e.getMessage(), e); + + System.out.println("Error generating MD5: " + e.getMessage()); + return ""; + } + return convertToHex(md5hash); + } + + /** + * Converts a String to Hex digits + * + */ + private static String convertToHex(byte[] data) { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < data.length; i++) { + int halfbyte = (data[i] >>> 4) & 0x0F; + int two_halfs = 0; + do { + if ((0 <= halfbyte) && (halfbyte <= 9)) { + buf.append((char) ('0' + halfbyte)); + } + else { + buf.append((char) ('a' + (halfbyte - 10))); + } + halfbyte = data[i] & 0x0F; + } + while (two_halfs++ < 1); + } + return buf.toString(); + } + + /** + * Converts an XPointer to XPath and evaulates the result (JAXP) + * + */ + public static String evaluateXPointer(String xpointer, InputStream is) { + String results = ""; + // Parse the XPointer into usable namespaces and XPath expressions + int xmlnsStart = xpointer.indexOf("xmlns(") + "xmlns(".length(); + int xmlnsEnd = xpointer.indexOf(")", xmlnsStart); + int xpathStart = xpointer.indexOf("xpointer(") + "xpointer(".length(); + int xpathEnd = xpointer.indexOf(")", xpathStart); + String xmlnsStr = xpointer.substring(xmlnsStart, xmlnsEnd); + String xpathStr = xpointer.substring(xpathStart, xpathEnd); + // System.out.println("xmlnsStr: "+xmlnsStr+" xpathStr: "+xpathStr); + try { + XPath xpath = XPathFactory.newInstance().newXPath(); + String[] namespaces = xmlnsStr.split(","); + // Add namespaces to XPath element + MyNamespaceContext context = new MyNamespaceContext(); + for (int i = 0; i < namespaces.length; i++) { + String[] xmlnsParts = namespaces[i].split("="); + context.setNamespace(xmlnsParts[0], xmlnsParts[1]); + xpath.setNamespaceContext(context); + } + InputSource src = new InputSource(is); + results = (String) xpath.evaluate(xpathStr, src); + // System.out.println("results: "+results); + } + catch (Exception e) { + jlogger.log(Level.SEVERE, "Error in evaluating XPointer. " + e.getMessage(), e); + + System.out.println("Error in evaluating XPointer. " + e.getMessage()); + } + return results; + } + + public static String evaluateXPointer(String xpointer, Document doc) { + InputStream is = null; + try { + is = IOUtils.DocumentToInputStream(doc); + } + catch (IOException e) { + jlogger.log(Level.SEVERE, "evaluateXPointer", e); + + } + + return evaluateXPointer(xpointer, is); + } + + public static String evaluateXPointer(String xpointer, byte[] bytes) { + Document doc = null; + try { + ByteArrayInputStream baip = new ByteArrayInputStream(bytes); + System.setProperty("javax.xml.parsers.DocumentBuilderFactory", + "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl"); + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + // Fortify Mod: prevent external entity injection + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + doc = db.parse(baip); + } + catch (Exception e) { + jlogger.log(Level.SEVERE, "evaluateXPointer", e); + + } + + return evaluateXPointer(xpointer, doc); + } + + /** + * Custom namespace class for adding additional namespaces for XPath evaluation + * + */ + public static class MyNamespaceContext implements NamespaceContext { + + private Map map; + + public MyNamespaceContext() { + map = new HashMap<>(); + } + + public void setNamespace(String prefix, String namespaceURI) { + map.put(prefix, namespaceURI); + } + + public String getNamespaceURI(String prefix) { + return (String) map.get(prefix); + } + + public String getPrefix(String namespaceURI) { + Set keys = map.keySet(); + for (Iterator iterator = keys.iterator(); iterator.hasNext();) { + String prefix = (String) iterator.next(); + String uri = (String) map.get(prefix); + if (uri.equals(namespaceURI)) + return prefix; + } + return null; + } + + public Iterator getPrefixes(String namespaceURI) { + List prefixes = new ArrayList<>(); + Set keys = map.keySet(); + for (Iterator iterator = keys.iterator(); iterator.hasNext();) { + String prefix = (String) iterator.next(); + String uri = (String) map.get(prefix); + if (uri.equals(namespaceURI)) + prefixes.add(prefix); + } + return prefixes.iterator(); + } + + } + + public static void copyResourceDir(URL resourceDirUrl, File destDir) throws IOException { + + String resourceDirUrlString = resourceDirUrl.toString(); + String resourceDir = resourceDirUrl.getPath(); + + int indexOfExcMark = resourceDirUrlString.indexOf("!"); + + if (resourceDirUrlString.startsWith(JAR_URI_PREFIX) && indexOfExcMark > -1) { + try { + copyResourcesFromJar( + new JarFile(resourceDirUrlString.substring(JAR_URI_PREFIX.length(), indexOfExcMark)), + resourceDirUrlString.substring(indexOfExcMark + 2), destDir); + } + catch (IOException e) { + jlogger.log(Level.SEVERE, "Could not copy resources from jar.", e); + } + } + else { + FileUtils.copyDirectory(new File(resourceDir), destDir); + } + } + + private static void copyResourcesFromJar(JarFile jarFile, String jarDir, File htmlOutput) throws IOException { + for (Enumeration jarEntries = jarFile.entries(); jarEntries.hasMoreElements();) { + JarEntry jarEntry = jarEntries.nextElement(); + if (jarEntry.getName().startsWith(jarDir + "/") && !jarEntry.isDirectory()) { + File dest = new File( + htmlOutput.getAbsolutePath() + "/" + jarEntry.getName().substring(jarDir.length() + 1)); + File parent = dest.getParentFile(); + if (parent != null) { + parent.mkdirs(); + } + try (FileOutputStream out = new FileOutputStream(dest); + InputStream in = jarFile.getInputStream(jarEntry)) { + byte[] buffer = new byte[8 * 1024]; + + int s = 0; + while ((s = in.read(buffer)) > 0) { + out.write(buffer, 0, s); + } + } + catch (IOException e) { + throw new IOException("Could not copy resource from jar file: " + jarEntry.getName(), e); + } + } + } + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/XMLParserUtils.java b/teamengine-core/src/main/java/com/occamlab/te/util/XMLParserUtils.java index d90d11cb4..7d316d61c 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/XMLParserUtils.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/XMLParserUtils.java @@ -1,44 +1,64 @@ -package com.occamlab.te.util; - -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.apache.xerces.impl.Constants; - -/** - * Provides various utility methods for constructing JAXP parsers. - * - */ -public class XMLParserUtils { - - /** - * Creates a SAXParser that is configured to resolve XInclude references but not - * perform schema validation. - * @param doBaseURIFixup A boolean value that specifies whether or not to add xml:base - * attributes when resolving xi:include elements; adding these attributes may render - * an instance document schema-invalid. - * @return An XInclude-aware SAXParser instance. - * - * @see XML Inclusions (XInclude) Version - * 1.0, Second Edition - */ - public static SAXParser createXIncludeAwareSAXParser(boolean doBaseURIFixup) { - SAXParserFactory factory = SAXParserFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setXIncludeAware(true); - SAXParser parser = null; - try { - factory.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FIXUP_BASE_URIS_FEATURE, - doBaseURIFixup); - parser = factory.newSAXParser(); - } - catch (Exception x) { - throw new RuntimeException(x); - } - return parser; - } - - private XMLParserUtils() { - } - -} +package com.occamlab.te.util; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.apache.xerces.impl.Constants; + +/** + * Provides various utility methods for constructing JAXP parsers. + * + */ +public class XMLParserUtils { + + /** + * Creates a SAXParser that is configured to resolve XInclude references but not + * perform schema validation. + * @param doBaseURIFixup A boolean value that specifies whether or not to add xml:base + * attributes when resolving xi:include elements; adding these attributes may render + * an instance document schema-invalid. + * @return An XInclude-aware SAXParser instance. + * + * @see XML Inclusions (XInclude) Version + * 1.0, Second Edition + */ + public static SAXParser createXIncludeAwareSAXParser(boolean doBaseURIFixup) { + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setXIncludeAware(true); + SAXParser parser = null; + try { + factory.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FIXUP_BASE_URIS_FEATURE, + doBaseURIFixup); + parser = factory.newSAXParser(); + } + catch (Exception x) { + throw new RuntimeException(x); + } + return parser; + } + + private XMLParserUtils() { + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/XMLUtils.java b/teamengine-core/src/main/java/com/occamlab/te/util/XMLUtils.java index ce333e518..2360ef3e1 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/XMLUtils.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/XMLUtils.java @@ -9,6 +9,26 @@ */ package com.occamlab.te.util; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/ZipUtils.java b/teamengine-core/src/main/java/com/occamlab/te/util/ZipUtils.java index ba0399b0a..c5b6dd20a 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/ZipUtils.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/ZipUtils.java @@ -1,59 +1,79 @@ -package com.occamlab.te.util; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -public class ZipUtils { - - /** - * Zips the directory and all of it's sub directories - * @param zipFile the file to write the files into, never null - * @param directoryToZip the directory to zip, never null - * @throws Exception if the zip file could not be created - * @throws IllegalArgumentException if the directoryToZip is not a directory - */ - public static void zipDir(File zipFile, File directoryToZip) throws Exception { - if (!directoryToZip.isDirectory()) { - throw new IllegalArgumentException("Directory to zip is not a directory"); - } - try { - ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile)); - File parentDir = new File(directoryToZip.toURI().resolve("..")); - for (File file : directoryToZip.listFiles()) { - zip(parentDir, file, out); - } - out.flush(); - out.close(); - } - catch (IOException e) { - throw new Exception(e.getMessage()); - } - - } - - private static void zip(File parentDir, File fileOrDirectoryToZip, ZipOutputStream out) throws IOException { - String filePath = parentDir.toURI().relativize(fileOrDirectoryToZip.toURI()).getPath(); - if (fileOrDirectoryToZip.isDirectory()) { - for (File file : fileOrDirectoryToZip.listFiles()) { - zip(parentDir, file, out); - } - } - else { - out.putNextEntry(new ZipEntry(filePath)); - FileInputStream in = new FileInputStream(fileOrDirectoryToZip); - - byte[] buffer = new byte[1024]; - int len; - while ((len = in.read(buffer)) != -1) { - out.write(buffer, 0, len); - } - out.closeEntry(); - in.close(); - } - } - -} +package com.occamlab.te.util; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +public class ZipUtils { + + /** + * Zips the directory and all of it's sub directories + * @param zipFile the file to write the files into, never null + * @param directoryToZip the directory to zip, never null + * @throws Exception if the zip file could not be created + * @throws IllegalArgumentException if the directoryToZip is not a directory + */ + public static void zipDir(File zipFile, File directoryToZip) throws Exception { + if (!directoryToZip.isDirectory()) { + throw new IllegalArgumentException("Directory to zip is not a directory"); + } + try { + ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile)); + File parentDir = new File(directoryToZip.toURI().resolve("..")); + for (File file : directoryToZip.listFiles()) { + zip(parentDir, file, out); + } + out.flush(); + out.close(); + } + catch (IOException e) { + throw new Exception(e.getMessage()); + } + + } + + private static void zip(File parentDir, File fileOrDirectoryToZip, ZipOutputStream out) throws IOException { + String filePath = parentDir.toURI().relativize(fileOrDirectoryToZip.toURI()).getPath(); + if (fileOrDirectoryToZip.isDirectory()) { + for (File file : fileOrDirectoryToZip.listFiles()) { + zip(parentDir, file, out); + } + } + else { + out.putNextEntry(new ZipEntry(filePath)); + FileInputStream in = new FileInputStream(fileOrDirectoryToZip); + + byte[] buffer = new byte[1024]; + int len; + while ((len = in.read(buffer)) != -1) { + out.write(buffer, 0, len); + } + out.closeEntry(); + in.close(); + } + } + +} diff --git a/teamengine-core/src/main/java/com/occamlab/te/util/protocols/data/Handler.java b/teamengine-core/src/main/java/com/occamlab/te/util/protocols/data/Handler.java index 140ba2b35..fec16ce03 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/util/protocols/data/Handler.java +++ b/teamengine-core/src/main/java/com/occamlab/te/util/protocols/data/Handler.java @@ -17,6 +17,26 @@ Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop ****************************************************************************/ package com.occamlab.te.util.protocols.data; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import static java.net.URLDecoder.decode; import java.io.ByteArrayInputStream; diff --git a/teamengine-core/src/main/java/com/occamlab/te/vocabulary/CITE.java b/teamengine-core/src/main/java/com/occamlab/te/vocabulary/CITE.java index c58ae6d4c..549d24c78 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/vocabulary/CITE.java +++ b/teamengine-core/src/main/java/com/occamlab/te/vocabulary/CITE.java @@ -6,6 +6,26 @@ */ package com.occamlab.te.vocabulary; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.Property; diff --git a/teamengine-core/src/main/java/com/occamlab/te/vocabulary/CONTENT.java b/teamengine-core/src/main/java/com/occamlab/te/vocabulary/CONTENT.java index 814858d57..c15012d67 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/vocabulary/CONTENT.java +++ b/teamengine-core/src/main/java/com/occamlab/te/vocabulary/CONTENT.java @@ -6,6 +6,26 @@ ************************************************************/ package com.occamlab.te.vocabulary; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.Property; diff --git a/teamengine-core/src/main/java/com/occamlab/te/vocabulary/EARL.java b/teamengine-core/src/main/java/com/occamlab/te/vocabulary/EARL.java index 25e3634af..3ea4e0dcf 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/vocabulary/EARL.java +++ b/teamengine-core/src/main/java/com/occamlab/te/vocabulary/EARL.java @@ -6,6 +6,26 @@ **************************************************************/ package com.occamlab.te.vocabulary; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.Property; diff --git a/teamengine-core/src/main/java/com/occamlab/te/vocabulary/HTTP.java b/teamengine-core/src/main/java/com/occamlab/te/vocabulary/HTTP.java index 67f5b8def..2b3984d72 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/vocabulary/HTTP.java +++ b/teamengine-core/src/main/java/com/occamlab/te/vocabulary/HTTP.java @@ -6,6 +6,26 @@ **************************************************************/ package com.occamlab.te.vocabulary; +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.Property; diff --git a/teamengine-core/src/main/java/com/occamlab/te/vocabulary/package-info.java b/teamengine-core/src/main/java/com/occamlab/te/vocabulary/package-info.java index 2e786d775..82982855f 100644 --- a/teamengine-core/src/main/java/com/occamlab/te/vocabulary/package-info.java +++ b/teamengine-core/src/main/java/com/occamlab/te/vocabulary/package-info.java @@ -5,3 +5,23 @@ * */ package com.occamlab.te.vocabulary; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ diff --git a/teamengine-core/src/main/java/net/sf/saxon/s9api/S9APIUtils.java b/teamengine-core/src/main/java/net/sf/saxon/s9api/S9APIUtils.java index 4b1564148..adeeb6ab6 100644 --- a/teamengine-core/src/main/java/net/sf/saxon/s9api/S9APIUtils.java +++ b/teamengine-core/src/main/java/net/sf/saxon/s9api/S9APIUtils.java @@ -1,32 +1,52 @@ -/* - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): No additional contributors to date - */ - -/* This file is in the s9api package so it can access the protected XdmNode constructor */ -package net.sf.saxon.s9api; - -import net.sf.saxon.om.NodeInfo; - -public class S9APIUtils { - - public static XdmNode makeNode(NodeInfo node) { - return new XdmNode(node); - } - - public static void setTransformerParam(XsltTransformer xt, String param, String value) throws SaxonApiException { - setTransformerParam(xt, new QName(param), value); - } - - public static void setTransformerParam(XsltTransformer xt, QName param, String value) throws SaxonApiException { - xt.setParameter(param, XdmItem.newAtomicValue(value, ItemType.ANY_ATOMIC_VALUE)); - } - -} +/* + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): No additional contributors to date + */ + +/* This file is in the s9api package so it can access the protected XdmNode constructor */ +package net.sf.saxon.s9api; + +/*- + * #%L + * TEAM Engine - Core Module + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import net.sf.saxon.om.NodeInfo; + +public class S9APIUtils { + + public static XdmNode makeNode(NodeInfo node) { + return new XdmNode(node); + } + + public static void setTransformerParam(XsltTransformer xt, String param, String value) throws SaxonApiException { + setTransformerParam(xt, new QName(param), value); + } + + public static void setTransformerParam(XsltTransformer xt, QName param, String value) throws SaxonApiException { + xt.setParameter(param, XdmItem.newAtomicValue(value, ItemType.ANY_ATOMIC_VALUE)); + } + +} diff --git a/teamengine-core/src/main/resources/config.xml b/teamengine-core/src/main/resources/config.xml index 8c2caf57a..6b26c0b02 100644 --- a/teamengine-core/src/main/resources/config.xml +++ b/teamengine-core/src/main/resources/config.xml @@ -1,4 +1,24 @@ + + OGC diff --git a/teamengine-realm/src/main/java/com/occamlab/te/realm/PBKDF2Realm.java b/teamengine-realm/src/main/java/com/occamlab/te/realm/PBKDF2Realm.java index f224781d8..ef7ddbdaa 100644 --- a/teamengine-realm/src/main/java/com/occamlab/te/realm/PBKDF2Realm.java +++ b/teamengine-realm/src/main/java/com/occamlab/te/realm/PBKDF2Realm.java @@ -17,6 +17,26 @@ package com.occamlab.te.realm; +/*- + * #%L + * TEAM Engine - Tomcat Realm + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.File; import java.lang.reflect.Constructor; import java.security.Principal; diff --git a/teamengine-realm/src/main/java/com/occamlab/te/realm/PasswordStorage.java b/teamengine-realm/src/main/java/com/occamlab/te/realm/PasswordStorage.java index 3a5916cfd..5f95e87ff 100644 --- a/teamengine-realm/src/main/java/com/occamlab/te/realm/PasswordStorage.java +++ b/teamengine-realm/src/main/java/com/occamlab/te/realm/PasswordStorage.java @@ -8,6 +8,26 @@ package com.occamlab.te.realm; +/*- + * #%L + * TEAM Engine - Tomcat Realm + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.InvalidKeySpecException; diff --git a/teamengine-realm/src/main/java/com/occamlab/te/realm/RestAuthenticationFilter.java b/teamengine-realm/src/main/java/com/occamlab/te/realm/RestAuthenticationFilter.java index bb79869e4..9112e0d83 100644 --- a/teamengine-realm/src/main/java/com/occamlab/te/realm/RestAuthenticationFilter.java +++ b/teamengine-realm/src/main/java/com/occamlab/te/realm/RestAuthenticationFilter.java @@ -1,5 +1,25 @@ package com.occamlab.te.realm; +/*- + * #%L + * TEAM Engine - Tomcat Realm + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Base64; diff --git a/teamengine-realm/src/main/java/com/occamlab/te/realm/UserFilesRealm.java b/teamengine-realm/src/main/java/com/occamlab/te/realm/UserFilesRealm.java index 78d248c78..b2ed94c0f 100644 --- a/teamengine-realm/src/main/java/com/occamlab/te/realm/UserFilesRealm.java +++ b/teamengine-realm/src/main/java/com/occamlab/te/realm/UserFilesRealm.java @@ -1,205 +1,225 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * ************************************************************************** - * - * Contributor(s): - * C. Heazel (WiSC): Added Fortify adjudication changes - * - *************************************************************************** - */ -package com.occamlab.te.realm; - -import java.io.File; -import java.lang.reflect.Constructor; -import java.security.Principal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import org.apache.catalina.Realm; -import org.apache.catalina.realm.GenericPrincipal; -import org.apache.catalina.realm.RealmBase; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -/** - * A Realm implementation that reads user information from an XML file located in a - * sub-directory of the users directory. A sample representation is shown below. - * - *
- * <user>
- *   <name>p.fogg</name>
- *   <roles>
- *     <name>user</name>
- *   </roles>
- *   <password>password</password>
- *   <email>p.fogg@example.org</email>
- * </user>
- * 
- *

- * WARNING: This implementation is deprecated, since it only handles - * clear text passwords. - *

- * - * @deprecated Superseded by {@link PBKDF2Realm}. - */ -@Deprecated -public class UserFilesRealm extends RealmBase { - - private static final Logger LOGR = Logger.getLogger(UserFilesRealm.class.getName()); - - private String rootPath = null; - - private DocumentBuilder DB = null; - - private HashMap principals = new HashMap<>(); - - private String password; - - public String getRoot() { - return rootPath; - } - - /** - * Sets the location of the root users directory. This is specified by the "root" - * attribute of the Realm element in the context definition. - * @param root A String specifying a directory location (TE_BASE/users). - */ - public void setRoot(String root) { - rootPath = root; - } - - private GenericPrincipal readPrincipal(String username) { - List roles = new ArrayList<>(); - File usersdir = new File(rootPath); - if (!usersdir.isDirectory()) { - usersdir = new File(System.getProperty("TE_BASE"), "users"); - } - File userfile = new File(new File(usersdir, username), "user.xml"); - if (!userfile.canRead()) { - return null; - } - Document userInfo = null; - try { - if (DB == null) { - // Fortify Mod: prevent external entity injection - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setExpandEntityReferences(false); - DB = dbf.newDocumentBuilder(); - // DB = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - } - userInfo = DB.parse(userfile); - } - catch (Exception e) { - LOGR.log(Level.WARNING, "Failed to read user info at " + userfile.getAbsolutePath(), e); - // Fortify Mod: If we failed to read user info then there is no point in - // continuing - return null; - } - Element userElement = (Element) (userInfo.getElementsByTagName("user").item(0)); - Element passwordElement = (Element) (userElement.getElementsByTagName("password").item(0)); - password = passwordElement.getTextContent(); - Element rolesElement = (Element) (userElement.getElementsByTagName("roles").item(0)); - NodeList roleElements = rolesElement.getElementsByTagName("name"); - for (int i = 0; i < roleElements.getLength(); i++) { - String name = ((Element) roleElements.item(i)).getTextContent(); - roles.add(name); - } - return createGenericPrincipal(username, roles); - } - - /** - * Creates a new GenericPrincipal representing the specified user. - * @param username The username for this user. - * @param roles The set of roles (specified using String values) associated with this - * user. - * @return A GenericPrincipal for use by this Realm implementation. - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - GenericPrincipal createGenericPrincipal(String username, List roles) { - Class klass = null; - try { - klass = Class.forName("org.apache.catalina.realm.GenericPrincipal"); - } - catch (ClassNotFoundException ex) { - LOGR.log(Level.SEVERE, ex.getMessage()); - // Fortify Mod: if klass is not populated, then there is no point in going - // forward - return null; - } - Constructor[] ctors = klass.getConstructors(); - Class firstParamType = ctors[0].getParameterTypes()[0]; - Class[] paramTypes = new Class[] { Realm.class, String.class, List.class }; - Object[] ctorArgs = new Object[] { this, username, roles }; - GenericPrincipal principal = null; - try { - if (Realm.class.isAssignableFrom(firstParamType)) { - // Tomcat 6 - Constructor ctor = klass.getConstructor(paramTypes); - principal = (GenericPrincipal) ctor.newInstance(ctorArgs); - } - else { - // Realm parameter removed in Tomcat 7 - Constructor ctor = klass.getConstructor(Arrays.copyOfRange(paramTypes, 1, paramTypes.length)); - principal = (GenericPrincipal) ctor.newInstance(Arrays.copyOfRange(ctorArgs, 1, ctorArgs.length)); - } - } - catch (Exception ex) { - LOGR.log(Level.WARNING, ex.getMessage()); - } - return principal; - } - - @Override - protected String getPassword(String username) { - GenericPrincipal principal = (GenericPrincipal) getPrincipal(username); - if (principal == null) { - return null; - } - else { - return password; - } - } - - @Override - protected Principal getPrincipal(String username) { - Principal principal; - - // Reread principal from file system if there is an asterisk (*) before - // the username - // This allows you to reset passwords without restarting Tomcat - // Just reset the password in the user.xml file, and attempt to login - // using *username - if (username.startsWith("*")) { - principal = readPrincipal(username.substring(1)); - if (principal != null) { - synchronized (principals) { - principals.put(username.substring(1), principal); - } - } - } - - synchronized (principals) { - principal = (Principal) principals.get(username); - } - if (principal == null) { - principal = readPrincipal(username); - if (principal != null) { - synchronized (principals) { - principals.put(username, principal); - } - } - } - return principal; - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * ************************************************************************** + * + * Contributor(s): + * C. Heazel (WiSC): Added Fortify adjudication changes + * + *************************************************************************** + */ +package com.occamlab.te.realm; + +/*- + * #%L + * TEAM Engine - Tomcat Realm + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.lang.reflect.Constructor; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import org.apache.catalina.Realm; +import org.apache.catalina.realm.GenericPrincipal; +import org.apache.catalina.realm.RealmBase; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +/** + * A Realm implementation that reads user information from an XML file located in a + * sub-directory of the users directory. A sample representation is shown below. + * + *
+ * <user>
+ *   <name>p.fogg</name>
+ *   <roles>
+ *     <name>user</name>
+ *   </roles>
+ *   <password>password</password>
+ *   <email>p.fogg@example.org</email>
+ * </user>
+ * 
+ *

+ * WARNING: This implementation is deprecated, since it only handles + * clear text passwords. + *

+ * + * @deprecated Superseded by {@link PBKDF2Realm}. + */ +@Deprecated +public class UserFilesRealm extends RealmBase { + + private static final Logger LOGR = Logger.getLogger(UserFilesRealm.class.getName()); + + private String rootPath = null; + + private DocumentBuilder DB = null; + + private HashMap principals = new HashMap<>(); + + private String password; + + public String getRoot() { + return rootPath; + } + + /** + * Sets the location of the root users directory. This is specified by the "root" + * attribute of the Realm element in the context definition. + * @param root A String specifying a directory location (TE_BASE/users). + */ + public void setRoot(String root) { + rootPath = root; + } + + private GenericPrincipal readPrincipal(String username) { + List roles = new ArrayList<>(); + File usersdir = new File(rootPath); + if (!usersdir.isDirectory()) { + usersdir = new File(System.getProperty("TE_BASE"), "users"); + } + File userfile = new File(new File(usersdir, username), "user.xml"); + if (!userfile.canRead()) { + return null; + } + Document userInfo = null; + try { + if (DB == null) { + // Fortify Mod: prevent external entity injection + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setExpandEntityReferences(false); + DB = dbf.newDocumentBuilder(); + // DB = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + } + userInfo = DB.parse(userfile); + } + catch (Exception e) { + LOGR.log(Level.WARNING, "Failed to read user info at " + userfile.getAbsolutePath(), e); + // Fortify Mod: If we failed to read user info then there is no point in + // continuing + return null; + } + Element userElement = (Element) (userInfo.getElementsByTagName("user").item(0)); + Element passwordElement = (Element) (userElement.getElementsByTagName("password").item(0)); + password = passwordElement.getTextContent(); + Element rolesElement = (Element) (userElement.getElementsByTagName("roles").item(0)); + NodeList roleElements = rolesElement.getElementsByTagName("name"); + for (int i = 0; i < roleElements.getLength(); i++) { + String name = ((Element) roleElements.item(i)).getTextContent(); + roles.add(name); + } + return createGenericPrincipal(username, roles); + } + + /** + * Creates a new GenericPrincipal representing the specified user. + * @param username The username for this user. + * @param roles The set of roles (specified using String values) associated with this + * user. + * @return A GenericPrincipal for use by this Realm implementation. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + GenericPrincipal createGenericPrincipal(String username, List roles) { + Class klass = null; + try { + klass = Class.forName("org.apache.catalina.realm.GenericPrincipal"); + } + catch (ClassNotFoundException ex) { + LOGR.log(Level.SEVERE, ex.getMessage()); + // Fortify Mod: if klass is not populated, then there is no point in going + // forward + return null; + } + Constructor[] ctors = klass.getConstructors(); + Class firstParamType = ctors[0].getParameterTypes()[0]; + Class[] paramTypes = new Class[] { Realm.class, String.class, List.class }; + Object[] ctorArgs = new Object[] { this, username, roles }; + GenericPrincipal principal = null; + try { + if (Realm.class.isAssignableFrom(firstParamType)) { + // Tomcat 6 + Constructor ctor = klass.getConstructor(paramTypes); + principal = (GenericPrincipal) ctor.newInstance(ctorArgs); + } + else { + // Realm parameter removed in Tomcat 7 + Constructor ctor = klass.getConstructor(Arrays.copyOfRange(paramTypes, 1, paramTypes.length)); + principal = (GenericPrincipal) ctor.newInstance(Arrays.copyOfRange(ctorArgs, 1, ctorArgs.length)); + } + } + catch (Exception ex) { + LOGR.log(Level.WARNING, ex.getMessage()); + } + return principal; + } + + @Override + protected String getPassword(String username) { + GenericPrincipal principal = (GenericPrincipal) getPrincipal(username); + if (principal == null) { + return null; + } + else { + return password; + } + } + + @Override + protected Principal getPrincipal(String username) { + Principal principal; + + // Reread principal from file system if there is an asterisk (*) before + // the username + // This allows you to reset passwords without restarting Tomcat + // Just reset the password in the user.xml file, and attempt to login + // using *username + if (username.startsWith("*")) { + principal = readPrincipal(username.substring(1)); + if (principal != null) { + synchronized (principals) { + principals.put(username.substring(1), principal); + } + } + } + + synchronized (principals) { + principal = (Principal) principals.get(username); + } + if (principal == null) { + principal = readPrincipal(username); + if (principal != null) { + synchronized (principals) { + principals.put(username, principal); + } + } + } + return principal; + } + +} diff --git a/teamengine-realm/src/main/resources/com/occamlab/te/realm/mbean-descriptor.xml b/teamengine-realm/src/main/resources/com/occamlab/te/realm/mbean-descriptor.xml index ba681c513..c09cc5b51 100644 --- a/teamengine-realm/src/main/resources/com/occamlab/te/realm/mbean-descriptor.xml +++ b/teamengine-realm/src/main/resources/com/occamlab/te/realm/mbean-descriptor.xml @@ -1,8 +1,27 @@ - - - + + + + diff --git a/teamengine-resources/src/main/resources/com/occamlab/te/PseudoCTLDocumentation.xsl b/teamengine-resources/src/main/resources/com/occamlab/te/PseudoCTLDocumentation.xsl index a713b9968..7e462d0c5 100644 --- a/teamengine-resources/src/main/resources/com/occamlab/te/PseudoCTLDocumentation.xsl +++ b/teamengine-resources/src/main/resources/com/occamlab/te/PseudoCTLDocumentation.xsl @@ -1,4 +1,24 @@ + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - Test Name: - -
- Test version: - -
- Time: - -
-
- Test INPUT: - - - -
- - - - - - - - - - - - - - - - - - - - : - - - - - -
-
-
- - - -
-
- Result: -
- - - - - - - - - - - - - - - - - - - - - - - - - - This test suite does not support evaluation of basic conformance classes. - Please contact the CITE team if you have any questions regarding the basic conformance - classes. - - - - -
- - - - - - -
- -
- Number of conformance classes tested: - -
- - - -
- Number of conformance classes passed: - -
-
- Number of conformance classes failed: - -
-
- - Core conformance classes (Pass = Green; Fail = Red; Skip = Grey): - - - - - - - - - - - - - - - - -
- - - -
-
-
-
-
-
-

- - - - - - - -
Color LegendPassFailSkip
- - - - - - - -
- -
- - - -
-

- -

-
-
- -

- -

-
-
-

- - - - - - - - - - - -
- Pass: - - - - - - - - Fail: - - - - - - - - Inherited fail: - - - - - - - - Skip: - - - - - - - - Total tests: - - - - - - - - - -
-

- -
- - - - - - - - - - - - - - 0 - - -
NameReason
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- -

- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

- -

- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- -

- - -
- - Could not handle assertion with result ''. Name is - ''. - - -
- - - - - - -
-
-
- - - - - - - - - - - - - - - - - - - - [ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

- -

-
Test Name: - -
Test Description: - -
Test Result: - -
Inputs :
Method: - - -
URI: - -
Outputs : - -
-                              
-                            
-
Reason of Failure: - - - - - - - - - - - - - -

- -

-
-
-
- - -
-
-
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

- -

-
Test Name: - -
Test Description: - - - - - - - - - - - - -
- - - - - - - - Class Name: - -
- Method Name: - -
- Path: - -
-
-
Test Result: - -
Test Requests: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Method: - -
URL: - -
Body: -
-                                    
-                                  
-
URL: - -
Body: -
-                                    
-                                  
-
URL: - -
URL: - -
Outputs: -
-                            
-                          
-
-
Reason of Failure: - - - - - - - - - - - - - -

- -

-
-
-
- - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | - Details ↗ - -
\ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + Test Name: + +
+ Test version: + +
+ Time: + +
+
+ Test INPUT: + + + +
+ + + + + + + + + + + + + + + + + + + + : + + + + + +
+
+
+ + + +
+
+ Result: +
+ + + + + + + + + + + + + + + + + + + + + + + + + + This test suite does not support evaluation of basic conformance classes. + Please contact the CITE team if you have any questions regarding the basic conformance + classes. + + + + +
+ + + + + + +
+ +
+ Number of conformance classes tested: + +
+ + + +
+ Number of conformance classes passed: + +
+
+ Number of conformance classes failed: + +
+
+ + Core conformance classes (Pass = Green; Fail = Red; Skip = Grey): + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+
+
+

+ + + + + + + +
Color LegendPassFailSkip
+ + + + + + + +
+ +
+ + + +
+

+ +

+
+
+ +

+ +

+
+
+

+ + + + + + + + + + + +
+ Pass: + + + + + + + + Fail: + + + + + + + + Inherited fail: + + + + + + + + Skip: + + + + + + + + Total tests: + + + + + + + + + +
+

+ +
+ + + + + + + + + + + + + + 0 + + +
NameReason
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +

+ + +
+ + Could not handle assertion with result ''. Name is + ''. + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + [ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ +

+
Test Name: + +
Test Description: + +
Test Result: + +
Inputs :
Method: + + +
URI: + +
Outputs : + +
+                              
+                            
+
Reason of Failure: + + + + + + + + + + + + + +

+ +

+
+
+
+ + +
+
+
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ +

+
Test Name: + +
Test Description: + + + + + + + + + + + + +
+ + + + + + + + Class Name: + +
+ Method Name: + +
+ Path: + +
+
+
Test Result: + +
Test Requests: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method: + +
URL: + +
Body: +
+                                    
+                                  
+
URL: + +
Body: +
+                                    
+                                  
+
URL: + +
URL: + +
Outputs: +
+                            
+                          
+
+
Reason of Failure: + + + + + + + + + + + + + +

+ +

+
+
+
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | + Details ↗ + +
diff --git a/teamengine-resources/src/main/resources/com/occamlab/te/ext/config.xsl b/teamengine-resources/src/main/resources/com/occamlab/te/ext/config.xsl index f46cd0005..d615b130b 100644 --- a/teamengine-resources/src/main/resources/com/occamlab/te/ext/config.xsl +++ b/teamengine-resources/src/main/resources/com/occamlab/te/ext/config.xsl @@ -1,28 +1,48 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/teamengine-resources/src/main/resources/com/occamlab/te/ext/session_info.xsl b/teamengine-resources/src/main/resources/com/occamlab/te/ext/session_info.xsl index 62b2fb330..69e20f9a1 100644 --- a/teamengine-resources/src/main/resources/com/occamlab/te/ext/session_info.xsl +++ b/teamengine-resources/src/main/resources/com/occamlab/te/ext/session_info.xsl @@ -1,22 +1,42 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/teamengine-resources/src/main/resources/com/occamlab/te/formfn.xsl b/teamengine-resources/src/main/resources/com/occamlab/te/formfn.xsl index 64e9c8a49..f2a6c24bc 100644 --- a/teamengine-resources/src/main/resources/com/occamlab/te/formfn.xsl +++ b/teamengine-resources/src/main/resources/com/occamlab/te/formfn.xsl @@ -1,3 +1,22 @@ + - - - - - - - - - - - - 2.0 - - - - - - - top - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Pass - - - - - - - - - - - - - - - <xsl:value-of select="ctl:title" /> - - - - - - - - - - - - - - - - - - - - - - <xsl:value-of select="ctl:title" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Pass - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Mandatory - - - - - - - - false - - - - - - - - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - xsl - - - - - - java - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Error: no outdir parameter - - - - - Error: outdir parameter is not a valid directory - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + 2.0 + + + + + + + top + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Pass + + + + + + + + + + + + + + + <xsl:value-of select="ctl:title" /> + + + + + + + + + + + + + + + + + + + + + + <xsl:value-of select="ctl:title" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Pass + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mandatory + + + + + + + + false + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + xsl + + + + + + java + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Error: no outdir parameter + + + + + Error: outdir parameter is not a valid directory + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/teamengine-resources/src/main/resources/com/occamlab/te/generate_source_html.xsl b/teamengine-resources/src/main/resources/com/occamlab/te/generate_source_html.xsl index 173c37add..29ea8fa84 100644 --- a/teamengine-resources/src/main/resources/com/occamlab/te/generate_source_html.xsl +++ b/teamengine-resources/src/main/resources/com/occamlab/te/generate_source_html.xsl @@ -1,84 +1,103 @@ - - - - - - - - - - - - - - - - - - - - - - - - - TextContent - - -
- 			
- 		
- -
- 			
- 		
-
- - - -
-	 		
- 				
- 			
-	 		
-	 			
-	 				
-		 				
-	 				
-	 			
- 			
- 			
- 			
- 			
-	 	
-
- - - - - Source for <xsl:value-of select="$filename"/> - - - - - - -
- + + + + + + + + + + + + + + + + + + + + + + + + + + TextContent + + +
+ 			
+ 		
+ +
+ 			
+ 		
+
+ + +
+
+	 		
+ 				
+ 			
+	 		
+	 			
+	 				
+		 				
+	 				
+	 			
+ 			
+ 			
+ 			
+ 			
+	 	
+ + + + + + Source for <xsl:value-of select="$filename"/> + + + + + + + + diff --git a/teamengine-resources/src/main/resources/com/occamlab/te/generate_xsl.xsl b/teamengine-resources/src/main/resources/com/occamlab/te/generate_xsl.xsl index 4749c212d..9435bed2d 100644 --- a/teamengine-resources/src/main/resources/com/occamlab/te/generate_xsl.xsl +++ b/teamengine-resources/src/main/resources/com/occamlab/te/generate_xsl.xsl @@ -1,1030 +1,1049 @@ - - - - - - - - - - - - - 2.0 - - - - - - - top - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Pass - - - - - - - - - - - - - - - <xsl:value-of select="ctl:title" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <xsl:value-of select="ctl:title" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Pass - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Mandatory - - - - - - - - false - - - - - - - - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - xsl - - - - - - java - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - , $te:parser-xml, '' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Error: no outdir parameter - - - - - Error: outdir parameter is not a valid directory - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Generates a named xsl:output definition for formatting structured messages - using the saxon:serialize() function. The name is obtained from the 'name' - pseudo-attribute of a ctl-msg processing instruction appearing in a ctl:test - element. - - - - - - - + + + + + + + + + + + + + + 2.0 + + + + + + + top + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Pass + + + + + + + + + + + + + + + <xsl:value-of select="ctl:title" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <xsl:value-of select="ctl:title" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Pass + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mandatory + + + + + + + + false + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + xsl + + + + + + java + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , $te:parser-xml, '' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Error: no outdir parameter + + + + + Error: outdir parameter is not a valid directory + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Generates a named xsl:output definition for formatting structured messages + using the saxon:serialize() function. The name is obtained from the 'name' + pseudo-attribute of a ctl-msg processing instruction appearing in a ctl:test + element. + + + + + + + diff --git a/teamengine-resources/src/main/resources/com/occamlab/te/logstyles/default.xsl b/teamengine-resources/src/main/resources/com/occamlab/te/logstyles/default.xsl index f0516260b..add922847 100644 --- a/teamengine-resources/src/main/resources/com/occamlab/te/logstyles/default.xsl +++ b/teamengine-resources/src/main/resources/com/occamlab/te/logstyles/default.xsl @@ -1,4 +1,24 @@ + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/teamengine-resources/src/main/resources/com/occamlab/te/stats/overall_stats.xsl b/teamengine-resources/src/main/resources/com/occamlab/te/stats/overall_stats.xsl index 74d92de72..23341e7a1 100644 --- a/teamengine-resources/src/main/resources/com/occamlab/te/stats/overall_stats.xsl +++ b/teamengine-resources/src/main/resources/com/occamlab/te/stats/overall_stats.xsl @@ -1,4 +1,24 @@ + + @@ -281,4 +301,4 @@ - \ No newline at end of file + diff --git a/teamengine-resources/src/main/resources/com/occamlab/te/stats/test_suite_stats.xsl b/teamengine-resources/src/main/resources/com/occamlab/te/stats/test_suite_stats.xsl index 03b6d1efe..f83b1f563 100644 --- a/teamengine-resources/src/main/resources/com/occamlab/te/stats/test_suite_stats.xsl +++ b/teamengine-resources/src/main/resources/com/occamlab/te/stats/test_suite_stats.xsl @@ -1,4 +1,24 @@ + + @@ -346,4 +366,4 @@ - \ No newline at end of file + diff --git a/teamengine-resources/src/main/resources/com/occamlab/te/test_report_html.xsl b/teamengine-resources/src/main/resources/com/occamlab/te/test_report_html.xsl index 3a6e8201a..ca67d4a30 100644 --- a/teamengine-resources/src/main/resources/com/occamlab/te/test_report_html.xsl +++ b/teamengine-resources/src/main/resources/com/occamlab/te/test_report_html.xsl @@ -1,4 +1,24 @@ + + + + @@ -111,4 +131,4 @@ - \ No newline at end of file + diff --git a/teamengine-resources/src/main/resources/com/occamlab/te/test_suite_overview_json.xsl b/teamengine-resources/src/main/resources/com/occamlab/te/test_suite_overview_json.xsl index 57a507b11..90a62f474 100644 --- a/teamengine-resources/src/main/resources/com/occamlab/te/test_suite_overview_json.xsl +++ b/teamengine-resources/src/main/resources/com/occamlab/te/test_suite_overview_json.xsl @@ -1,4 +1,24 @@ + + @@ -50,4 +70,4 @@ "" - \ No newline at end of file + diff --git a/teamengine-spi-ctl/src/main/java/com/occamlab/te/spi/ctl/CtlExecutor.java b/teamengine-spi-ctl/src/main/java/com/occamlab/te/spi/ctl/CtlExecutor.java index ce04762fe..81d2f95a3 100644 --- a/teamengine-spi-ctl/src/main/java/com/occamlab/te/spi/ctl/CtlExecutor.java +++ b/teamengine-spi-ctl/src/main/java/com/occamlab/te/spi/ctl/CtlExecutor.java @@ -8,6 +8,26 @@ package com.occamlab.te.spi.ctl; +/*- + * #%L + * TEAM Engine - CTL Test Suite Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import com.occamlab.te.CtlEarlReporter; import com.occamlab.te.Engine; import com.occamlab.te.Generator; diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/FixtureManager.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/FixtureManager.java index 8b375df7d..3493e3318 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/FixtureManager.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/FixtureManager.java @@ -1,94 +1,114 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.occamlab.te.spi.executors; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -/** - * Manages test fixtures that provide data to support the execution of a test run. Such - * data often describe the test subject or its environment. - */ -public class FixtureManager { - - /** - * A singleton instance of the manager. - */ - private static volatile FixtureManager manager; - - /** - * A collection of TestRunFixture objects, keyed by identifier (e.g. a UUID value). - */ - private Map fixtures; - - /** - * Returns a singleton manager in a lazy (but thread-safe) manner. - * @return the FixtureManager instance. - */ - public static FixtureManager getInstance() { - - // Employ a "double-checked locking" strategy because a lock is only - // needed upon initialization; synchronize on the monitor belonging to - // the class itself. - if (null == manager) { - synchronized (FixtureManager.class) { - // check again, because the thread might have been preempted - // just after the outer if was processed but before the - // synchronized statement was executed - if (manager == null) { - manager = new FixtureManager(); - } - } - } - return manager; - } - - /** - * Gets the fixture for the specified test run. If runId is an empty String and only - * one fixture exists this is returned. - * @param runId The test run identifier (may be an empty String). - * @return A TestRunFixture, or {@code null } if a matching one cannot be found. - */ - public TestRunFixture getFixture(String runId) { - if (runId.isEmpty() && this.fixtures.size() == 1) { - runId = this.fixtures.keySet().iterator().next(); - } - return fixtures.get(runId); - } - - /** - * Adds a fixture. - * @param runId The test run identifier. - * @param fixture The TestRunFixture to be added (or replaced). - */ - public void addFixture(String runId, TestRunFixture fixture) { - this.fixtures.put(runId, fixture); - } - - /** - * Removes a fixture. - * @param runId The test run identifier. - */ - public void removeFixture(String runId) { - this.fixtures.remove(runId); - } - - /** - * Lists the identifiers of registered test run fixtures. - * @return A Set containing fixture identifiers. - */ - public Set listFixtureIdentifiers() { - return fixtures.keySet(); - } - - private FixtureManager() { - this.fixtures = new HashMap<>(); - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.occamlab.te.spi.executors; + +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Manages test fixtures that provide data to support the execution of a test run. Such + * data often describe the test subject or its environment. + */ +public class FixtureManager { + + /** + * A singleton instance of the manager. + */ + private static volatile FixtureManager manager; + + /** + * A collection of TestRunFixture objects, keyed by identifier (e.g. a UUID value). + */ + private Map fixtures; + + /** + * Returns a singleton manager in a lazy (but thread-safe) manner. + * @return the FixtureManager instance. + */ + public static FixtureManager getInstance() { + + // Employ a "double-checked locking" strategy because a lock is only + // needed upon initialization; synchronize on the monitor belonging to + // the class itself. + if (null == manager) { + synchronized (FixtureManager.class) { + // check again, because the thread might have been preempted + // just after the outer if was processed but before the + // synchronized statement was executed + if (manager == null) { + manager = new FixtureManager(); + } + } + } + return manager; + } + + /** + * Gets the fixture for the specified test run. If runId is an empty String and only + * one fixture exists this is returned. + * @param runId The test run identifier (may be an empty String). + * @return A TestRunFixture, or {@code null } if a matching one cannot be found. + */ + public TestRunFixture getFixture(String runId) { + if (runId.isEmpty() && this.fixtures.size() == 1) { + runId = this.fixtures.keySet().iterator().next(); + } + return fixtures.get(runId); + } + + /** + * Adds a fixture. + * @param runId The test run identifier. + * @param fixture The TestRunFixture to be added (or replaced). + */ + public void addFixture(String runId, TestRunFixture fixture) { + this.fixtures.put(runId, fixture); + } + + /** + * Removes a fixture. + * @param runId The test run identifier. + */ + public void removeFixture(String runId) { + this.fixtures.remove(runId); + } + + /** + * Lists the identifiers of registered test run fixtures. + * @return A Set containing fixture identifiers. + */ + public Set listFixtureIdentifiers() { + return fixtures.keySet(); + } + + private FixtureManager() { + this.fixtures = new HashMap<>(); + } + +} diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/TestRunExecutor.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/TestRunExecutor.java index 9eeae5c63..1d263e000 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/TestRunExecutor.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/TestRunExecutor.java @@ -1,28 +1,48 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.occamlab.te.spi.executors; - -import javax.xml.transform.Source; -import org.w3c.dom.Document; - -/** - * An object responsible for executing a test run. - */ -public interface TestRunExecutor { - - /** - * Executes a test suite using the supplied test run arguments. - * @param testRunArgs A DOM Document node that contains the test run arguments. The - * content of the document is implementation-specific. - * @return A Source object that provides the (XML) results of the test run. - * - * @see Source - */ - Source execute(Document testRunArgs); - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.occamlab.te.spi.executors; + +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import javax.xml.transform.Source; +import org.w3c.dom.Document; + +/** + * An object responsible for executing a test run. + */ +public interface TestRunExecutor { + + /** + * Executes a test suite using the supplied test run arguments. + * @param testRunArgs A DOM Document node that contains the test run arguments. The + * content of the document is implementation-specific. + * @return A Source object that provides the (XML) results of the test run. + * + * @see Source + */ + Source execute(Document testRunArgs); + +} diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/TestRunFixture.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/TestRunFixture.java index 4267df161..6d86fbd06 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/TestRunFixture.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/TestRunFixture.java @@ -1,52 +1,72 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.occamlab.te.spi.executors; - -import java.util.Set; - -/** - * A test run fixture. Tests can reuse items in this shared fixture, but beware of - * undesirable interactions occurring if any tests modify the fixture. Such a fixture is - * best suited for providing "immutable" items that only need to be created once, such as - * metadata about the test subject or its environment, pre-compiled Schema objects, etc. - */ -public interface TestRunFixture { - - /** - * Adds an item to the fixture. If an item with the given name already exists it is - * replaced. - * @param name The name of the item. - * @param value The actual item to add. - */ - void addItem(String name, Object value); - - /** - * Retrieves an item from the fixture by name. - * @param name The name of the item to return. - * @return The item, or null if no corresponding item exists. - */ - Object getItem(String name); - - /** - * Returns a set of all item names. - * @return A Set containing the names of all items in the fixture. - */ - Set listItemNames(); - - /** - * Removes an item specified by name. - * @param name The name of the item to remove. - */ - void removeItem(String name); - - /** - * Removes all items in the fixture. - */ - void removeAllItems(); - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.occamlab.te.spi.executors; + +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.Set; + +/** + * A test run fixture. Tests can reuse items in this shared fixture, but beware of + * undesirable interactions occurring if any tests modify the fixture. Such a fixture is + * best suited for providing "immutable" items that only need to be created once, such as + * metadata about the test subject or its environment, pre-compiled Schema objects, etc. + */ +public interface TestRunFixture { + + /** + * Adds an item to the fixture. If an item with the given name already exists it is + * replaced. + * @param name The name of the item. + * @param value The actual item to add. + */ + void addItem(String name, Object value); + + /** + * Retrieves an item from the fixture by name. + * @param name The name of the item to return. + * @return The item, or null if no corresponding item exists. + */ + Object getItem(String name); + + /** + * Returns a set of all item names. + * @return A Set containing the names of all items in the fixture. + */ + Set listItemNames(); + + /** + * Removes an item specified by name. + * @param name The name of the item to remove. + */ + void removeItem(String name); + + /** + * Removes all items in the fixture. + */ + void removeAllItems(); + +} diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/AlterSuiteParametersListener.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/AlterSuiteParametersListener.java index 60eb97d1b..2d4993b73 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/AlterSuiteParametersListener.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/AlterSuiteParametersListener.java @@ -7,6 +7,26 @@ */ package com.occamlab.te.spi.executors.testng; +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.util.List; import java.util.Map; import java.util.UUID; diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/BasicXMLReporter.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/BasicXMLReporter.java index 2f4e168bd..c2423bba4 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/BasicXMLReporter.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/BasicXMLReporter.java @@ -1,52 +1,72 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.occamlab.te.spi.executors.testng; - -import java.util.List; -import org.testng.IReporter; -import org.testng.ISuite; -import org.testng.reporters.XMLReporter; -import org.testng.reporters.XMLReporterConfig; -import org.testng.xml.XmlSuite; - -/** - * A basic XML reporter that suppresses stack traces and writes the test results to a - * single file (testng-results.xml) in the specified output directory. - * - * @see
- * TestNG documentation, 6.2.5 - */ -public final class BasicXMLReporter implements IReporter { - - private final XMLReporter reporter; - - public BasicXMLReporter() { - this.reporter = createCustomXMLReporter(); - } - - @Override - public void generateReport(List xmlSuites, List suites, String outputDirectory) { - this.reporter.generateReport(xmlSuites, suites, outputDirectory); - } - - /** - * Creates an XML reporter that suppresses stack traces and includes test result - * attributes (if set). - * @return A customized reporter that generates an XML representation of the test - * results. The document element is <testng-results>. - */ - XMLReporter createCustomXMLReporter() { - XMLReporter customReporter = new XMLReporter(); - XMLReporterConfig config = customReporter.getConfig(); - config.setStackTraceOutput(XMLReporterConfig.StackTraceLevels.NONE); - config.setGenerateTestResultAttributes(true); - config.setGenerateGroupsAttribute(true); - return customReporter; - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.occamlab.te.spi.executors.testng; + +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.List; +import org.testng.IReporter; +import org.testng.ISuite; +import org.testng.reporters.XMLReporter; +import org.testng.reporters.XMLReporterConfig; +import org.testng.xml.XmlSuite; + +/** + * A basic XML reporter that suppresses stack traces and writes the test results to a + * single file (testng-results.xml) in the specified output directory. + * + * @see + * TestNG documentation, 6.2.5 + */ +public final class BasicXMLReporter implements IReporter { + + private final XMLReporter reporter; + + public BasicXMLReporter() { + this.reporter = createCustomXMLReporter(); + } + + @Override + public void generateReport(List xmlSuites, List suites, String outputDirectory) { + this.reporter.generateReport(xmlSuites, suites, outputDirectory); + } + + /** + * Creates an XML reporter that suppresses stack traces and includes test result + * attributes (if set). + * @return A customized reporter that generates an XML representation of the test + * results. The document element is <testng-results>. + */ + XMLReporter createCustomXMLReporter() { + XMLReporter customReporter = new XMLReporter(); + XMLReporterConfig config = customReporter.getConfig(); + config.setStackTraceOutput(XMLReporterConfig.StackTraceLevels.NONE); + config.setGenerateTestResultAttributes(true); + config.setGenerateGroupsAttribute(true); + return customReporter; + } + +} diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/EarlReporter.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/EarlReporter.java index 1e696fa92..545fba1a7 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/EarlReporter.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/EarlReporter.java @@ -14,6 +14,26 @@ package com.occamlab.te.spi.executors.testng; +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/TestNGExecutor.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/TestNGExecutor.java index 8fff9b305..ff2067ace 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/TestNGExecutor.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/TestNGExecutor.java @@ -1,300 +1,320 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - - * - * Contributor(s): - * Charles Heazel (WiSC): Modified to address Fortify issues - * Mods deferred until dependency on core is resolved. - * February 26, 2018 - */ -package com.occamlab.te.spi.executors.testng; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.xml.transform.Source; -import javax.xml.transform.sax.SAXSource; - -import org.apache.jena.rdf.model.Model; -import org.testng.TestNG; -import org.testng.xml.XmlSuite; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; - -import com.occamlab.te.spi.executors.TestRunExecutor; -import com.occamlab.te.spi.util.HtmlReport; -import com.occamlab.te.spi.util.TestRunUtils; - -/** - * - * Executes a TestNG test suite using the given test run arguments. - */ -public class TestNGExecutor implements TestRunExecutor { - - private static final Logger LOGR = Logger.getLogger(TestNGExecutor.class.getPackage().getName()); - - private static final List SUPPORTED_MEDIA_TYPES = Arrays.asList("application/xml", "application/zip", - "application/rdf+xml"); - - private final boolean useDefaultListeners; - - private File outputDir; - - private URI testngConfig; - - /** - * Constructs a TestNG executor with the given test suite definition. The default - * listeners are not used. - * @param testngSuite A reference to a file containing a TestNG suite definition (with - * <suite> as the document element). - */ - public TestNGExecutor(String testngSuite) { - this(testngSuite, System.getProperty("java.io.tmpdir"), false); - } - - /** - * Constructs a TestNG executor configured as indicated. - * @param testngSuite A reference to a file containing a TestNG suite definition. - * @param outputDirPath The location of the root directory for writing test results. - * If the directory does not exist and cannot be created, the location given by the - * "java.io.tmpdir" system property is used instead. - * @param useDefaultListeners A boolean value indicating whether or not to use the - * default set of listeners. - */ - public TestNGExecutor(String testngSuite, String outputDirPath, boolean useDefaultListeners) { - this.useDefaultListeners = useDefaultListeners; - this.outputDir = new File(outputDirPath, "testng"); - if (!this.outputDir.exists() && !this.outputDir.mkdirs()) { - LOGR.config("Failed to create output directory at " + this.outputDir); - this.outputDir = new File(System.getProperty("java.io.tmpdir")); - } - if (null != testngSuite && !testngSuite.isEmpty()) { - this.testngConfig = URI.create(testngSuite); - } - } - - /** - * Executes a test suite using the supplied test run arguments. The test run arguments - * are expected to be contained in an XML properties document structured as shown in - * the following example. - * - *
-	 * {@code
-	 * 
-	 * 
-	 *   Test run arguments
-	 *   atom-feed.xml
-	 *   L2
-	 * 
-	 * }
-	 * 
- * - *

- * Note:The actual arguments (key-value pairs) are suite-specific. - *

- * @param testRunArgs A DOM Document node that contains a set of XML properties. - * @return A Source object that provides an XML representation of the test results. - */ - @Override - public Source execute(Document testRunArgs) { - if (null == testRunArgs) { - throw new IllegalArgumentException("No test run arguments were supplied."); - } - - String runId = null; - String sourcesId = ""; - Map argsMap = extractTestRunArguments(testRunArgs); - - if (argsMap.containsKey("logDir")) { - this.outputDir = new File(argsMap.get("logDir")); - } - - if (argsMap.containsKey("sourcesId")) { - sourcesId = argsMap.get("sourcesId"); - } - - if (argsMap.containsKey("sessionId")) { - runId = argsMap.get("sessionId"); - TestRunUtils.save(this.outputDir, runId, sourcesId); - } - else { - runId = UUID.randomUUID().toString(); - } - - TestNG driver = new TestNG(); - setTestSuites(driver, this.testngConfig); - driver.setVerbose(0); - driver.setUseDefaultListeners(this.useDefaultListeners); - File runDir = new File(this.outputDir, runId); - if (!runDir.exists() && !runDir.mkdir()) { - runDir = this.outputDir; - LOGR.config("Created test run directory at " + runDir.getAbsolutePath()); - } - driver.setOutputDirectory(runDir.getAbsolutePath()); - AlterSuiteParametersListener listener = new AlterSuiteParametersListener(); - listener.setTestRunArgs(testRunArgs); - listener.setTestRunId(runId); - driver.addListener(listener); - try { - driver.run(); - } - catch (Exception e) { - XmlSuite suite = new org.testng.xml.XmlSuite(); - suite.setSuiteFiles(Arrays.asList(new String[] { this.testngConfig.toString() })); - suite.setParameters(argsMap); - EarlReporter earlReporter = new EarlReporter(); - Model model = earlReporter.initializeModel(suite); - earlReporter.addTestInputs(model, argsMap); - earlReporter.addTopLevelFailure(model, e.getMessage()); - try { - earlReporter.writeModel(model, runDir, true); - } - catch (IOException e1) { - LOGR.log(Level.SEVERE, "Error writing default model: " + e.getMessage()); - } - LOGR.log(Level.SEVERE, "Error while running: " + e.getMessage()); - throw e; - } - Source source = null; - try { - File resultsFile = getResultsFile(getPreferredMediaType(testRunArgs), driver.getOutputDirectory()); - InputStream inStream = new FileInputStream(resultsFile); - InputSource inSource = new InputSource(new InputStreamReader(inStream, StandardCharsets.UTF_8)); - source = new SAXSource(inSource); - source.setSystemId(resultsFile.toURI().toString()); - } - catch (IOException e) { - LOGR.log(Level.SEVERE, "Error reading test results: " + e.getMessage()); - } - return source; - } - - /** - * Returns the test results in the specified format. The default media type is - * "application/xml", but "application/rdf+xml" (RDF/XML) is also supported. - * @param mediaType The media type of the test results (XML or RDF/XML). - * @param outputDirectory The directory containing the test run output. - * @return A File containing the test results. - * @throws FileNotFoundException If no test results are found. - */ - File getResultsFile(String mediaType, String outputDirectory) throws FileNotFoundException { - // split out any media type parameters - String contentType = mediaType.split(";")[0]; - String fileName = null; - if (contentType.endsWith("rdf+xml") || contentType.endsWith("rdf+earl")) { - fileName = "earl-results.rdf"; - } - else if (contentType.endsWith("zip")) { - File htmlResult = HtmlReport.getHtmlResultZip(outputDirectory); - fileName = "result.zip"; - } - else { - fileName = "testng-results.xml"; - } - File resultsFile = new File(outputDirectory, fileName); - if (!resultsFile.exists()) { - throw new FileNotFoundException("Test run results not found at " + resultsFile.getAbsolutePath()); - } - return resultsFile; - } - - /** - * Gets the preferred media type for the test results as indicated by the value of the - * "acceptMediaType" key in the given properties file. The default value is - * "application/xml". - * @param testRunArgs An XML properties file containing test run arguments. - * @return The preferred media type. - */ - String getPreferredMediaType(Document testRunArgs) { - String mediaTypeFromTestRunArg = parseMediaTypeFromTestRunArgs(testRunArgs); - if (mediaTypeFromTestRunArg != null && SUPPORTED_MEDIA_TYPES.contains(mediaTypeFromTestRunArg)) - return mediaTypeFromTestRunArg; - return "application/xml"; - } - - /** - * Sets the test suite to run using the given URI reference. Three types of references - * are supported: - *
    - *
  • A file system reference
  • - *
  • A file: URI
  • - *
  • A jar: URI
  • - *
- * @param driver The main TestNG driver. - * @param ets A URI referring to a suite definition. - */ - private void setTestSuites(TestNG driver, URI ets) { - if (ets.getScheme().equalsIgnoreCase("jar")) { - // jar:{url}!/{entry} - String[] jarPath = ets.getSchemeSpecificPart().split("!"); - File jarFile = new File(URI.create(jarPath[0])); - driver.setTestJar(jarFile.getAbsolutePath()); - driver.setXmlPathInJar(jarPath[1].substring(1)); - } - else { - List testSuites = new ArrayList<>(); - File tngFile = new File(ets); - if (tngFile.exists()) { - LOGR.log(Level.CONFIG, "Using TestNG config file {0}", tngFile.getAbsolutePath()); - testSuites.add(tngFile.getAbsolutePath()); - } - else { - throw new IllegalArgumentException("A valid TestNG config file reference is required."); - } - driver.setTestSuites(testSuites); - } - } - - private String parseMediaTypeFromTestRunArgs(Document testRunArgs) { - NodeList entries = testRunArgs.getElementsByTagName("entry"); - for (int i = 0; i < entries.getLength(); i++) { - Element entry = (Element) entries.item(i); - if (entry.getAttribute("key").equals("acceptMediaType")) { - return entry.getTextContent().trim(); - } - } - return null; - } - - /** - * Extracts test run arguments from an XML properties file. The arguments are added to - * the resulting HashMap object as key-value pairs". - * @param testRunArgs An XML representation of a properties file containing an - * {@literal } element for each supplied argument. - * @return The HashMap containing settings for a test run, including a list of - * parameters (which may be empty). - * - */ - Map extractTestRunArguments(Document testRunArgs) { - Map argsMap = new HashMap<>(); - if (null != testRunArgs) { - NodeList entries = testRunArgs.getElementsByTagName("entry"); - for (int i = 0; i < entries.getLength(); i++) { - Element entry = (Element) entries.item(i); - argsMap.put(entry.getAttribute("key"), entry.getTextContent().trim()); - } - } - return argsMap; - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * + * Contributor(s): + * Charles Heazel (WiSC): Modified to address Fortify issues + * Mods deferred until dependency on core is resolved. + * February 26, 2018 + */ +package com.occamlab.te.spi.executors.testng; + +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.xml.transform.Source; +import javax.xml.transform.sax.SAXSource; + +import org.apache.jena.rdf.model.Model; +import org.testng.TestNG; +import org.testng.xml.XmlSuite; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +import com.occamlab.te.spi.executors.TestRunExecutor; +import com.occamlab.te.spi.util.HtmlReport; +import com.occamlab.te.spi.util.TestRunUtils; + +/** + * + * Executes a TestNG test suite using the given test run arguments. + */ +public class TestNGExecutor implements TestRunExecutor { + + private static final Logger LOGR = Logger.getLogger(TestNGExecutor.class.getPackage().getName()); + + private static final List SUPPORTED_MEDIA_TYPES = Arrays.asList("application/xml", "application/zip", + "application/rdf+xml"); + + private final boolean useDefaultListeners; + + private File outputDir; + + private URI testngConfig; + + /** + * Constructs a TestNG executor with the given test suite definition. The default + * listeners are not used. + * @param testngSuite A reference to a file containing a TestNG suite definition (with + * <suite> as the document element). + */ + public TestNGExecutor(String testngSuite) { + this(testngSuite, System.getProperty("java.io.tmpdir"), false); + } + + /** + * Constructs a TestNG executor configured as indicated. + * @param testngSuite A reference to a file containing a TestNG suite definition. + * @param outputDirPath The location of the root directory for writing test results. + * If the directory does not exist and cannot be created, the location given by the + * "java.io.tmpdir" system property is used instead. + * @param useDefaultListeners A boolean value indicating whether or not to use the + * default set of listeners. + */ + public TestNGExecutor(String testngSuite, String outputDirPath, boolean useDefaultListeners) { + this.useDefaultListeners = useDefaultListeners; + this.outputDir = new File(outputDirPath, "testng"); + if (!this.outputDir.exists() && !this.outputDir.mkdirs()) { + LOGR.config("Failed to create output directory at " + this.outputDir); + this.outputDir = new File(System.getProperty("java.io.tmpdir")); + } + if (null != testngSuite && !testngSuite.isEmpty()) { + this.testngConfig = URI.create(testngSuite); + } + } + + /** + * Executes a test suite using the supplied test run arguments. The test run arguments + * are expected to be contained in an XML properties document structured as shown in + * the following example. + * + *
+	 * {@code
+	 * 
+	 * 
+	 *   Test run arguments
+	 *   atom-feed.xml
+	 *   L2
+	 * 
+	 * }
+	 * 
+ * + *

+ * Note:The actual arguments (key-value pairs) are suite-specific. + *

+ * @param testRunArgs A DOM Document node that contains a set of XML properties. + * @return A Source object that provides an XML representation of the test results. + */ + @Override + public Source execute(Document testRunArgs) { + if (null == testRunArgs) { + throw new IllegalArgumentException("No test run arguments were supplied."); + } + + String runId = null; + String sourcesId = ""; + Map argsMap = extractTestRunArguments(testRunArgs); + + if (argsMap.containsKey("logDir")) { + this.outputDir = new File(argsMap.get("logDir")); + } + + if (argsMap.containsKey("sourcesId")) { + sourcesId = argsMap.get("sourcesId"); + } + + if (argsMap.containsKey("sessionId")) { + runId = argsMap.get("sessionId"); + TestRunUtils.save(this.outputDir, runId, sourcesId); + } + else { + runId = UUID.randomUUID().toString(); + } + + TestNG driver = new TestNG(); + setTestSuites(driver, this.testngConfig); + driver.setVerbose(0); + driver.setUseDefaultListeners(this.useDefaultListeners); + File runDir = new File(this.outputDir, runId); + if (!runDir.exists() && !runDir.mkdir()) { + runDir = this.outputDir; + LOGR.config("Created test run directory at " + runDir.getAbsolutePath()); + } + driver.setOutputDirectory(runDir.getAbsolutePath()); + AlterSuiteParametersListener listener = new AlterSuiteParametersListener(); + listener.setTestRunArgs(testRunArgs); + listener.setTestRunId(runId); + driver.addListener(listener); + try { + driver.run(); + } + catch (Exception e) { + XmlSuite suite = new org.testng.xml.XmlSuite(); + suite.setSuiteFiles(Arrays.asList(new String[] { this.testngConfig.toString() })); + suite.setParameters(argsMap); + EarlReporter earlReporter = new EarlReporter(); + Model model = earlReporter.initializeModel(suite); + earlReporter.addTestInputs(model, argsMap); + earlReporter.addTopLevelFailure(model, e.getMessage()); + try { + earlReporter.writeModel(model, runDir, true); + } + catch (IOException e1) { + LOGR.log(Level.SEVERE, "Error writing default model: " + e.getMessage()); + } + LOGR.log(Level.SEVERE, "Error while running: " + e.getMessage()); + throw e; + } + Source source = null; + try { + File resultsFile = getResultsFile(getPreferredMediaType(testRunArgs), driver.getOutputDirectory()); + InputStream inStream = new FileInputStream(resultsFile); + InputSource inSource = new InputSource(new InputStreamReader(inStream, StandardCharsets.UTF_8)); + source = new SAXSource(inSource); + source.setSystemId(resultsFile.toURI().toString()); + } + catch (IOException e) { + LOGR.log(Level.SEVERE, "Error reading test results: " + e.getMessage()); + } + return source; + } + + /** + * Returns the test results in the specified format. The default media type is + * "application/xml", but "application/rdf+xml" (RDF/XML) is also supported. + * @param mediaType The media type of the test results (XML or RDF/XML). + * @param outputDirectory The directory containing the test run output. + * @return A File containing the test results. + * @throws FileNotFoundException If no test results are found. + */ + File getResultsFile(String mediaType, String outputDirectory) throws FileNotFoundException { + // split out any media type parameters + String contentType = mediaType.split(";")[0]; + String fileName = null; + if (contentType.endsWith("rdf+xml") || contentType.endsWith("rdf+earl")) { + fileName = "earl-results.rdf"; + } + else if (contentType.endsWith("zip")) { + File htmlResult = HtmlReport.getHtmlResultZip(outputDirectory); + fileName = "result.zip"; + } + else { + fileName = "testng-results.xml"; + } + File resultsFile = new File(outputDirectory, fileName); + if (!resultsFile.exists()) { + throw new FileNotFoundException("Test run results not found at " + resultsFile.getAbsolutePath()); + } + return resultsFile; + } + + /** + * Gets the preferred media type for the test results as indicated by the value of the + * "acceptMediaType" key in the given properties file. The default value is + * "application/xml". + * @param testRunArgs An XML properties file containing test run arguments. + * @return The preferred media type. + */ + String getPreferredMediaType(Document testRunArgs) { + String mediaTypeFromTestRunArg = parseMediaTypeFromTestRunArgs(testRunArgs); + if (mediaTypeFromTestRunArg != null && SUPPORTED_MEDIA_TYPES.contains(mediaTypeFromTestRunArg)) + return mediaTypeFromTestRunArg; + return "application/xml"; + } + + /** + * Sets the test suite to run using the given URI reference. Three types of references + * are supported: + *
    + *
  • A file system reference
  • + *
  • A file: URI
  • + *
  • A jar: URI
  • + *
+ * @param driver The main TestNG driver. + * @param ets A URI referring to a suite definition. + */ + private void setTestSuites(TestNG driver, URI ets) { + if (ets.getScheme().equalsIgnoreCase("jar")) { + // jar:{url}!/{entry} + String[] jarPath = ets.getSchemeSpecificPart().split("!"); + File jarFile = new File(URI.create(jarPath[0])); + driver.setTestJar(jarFile.getAbsolutePath()); + driver.setXmlPathInJar(jarPath[1].substring(1)); + } + else { + List testSuites = new ArrayList<>(); + File tngFile = new File(ets); + if (tngFile.exists()) { + LOGR.log(Level.CONFIG, "Using TestNG config file {0}", tngFile.getAbsolutePath()); + testSuites.add(tngFile.getAbsolutePath()); + } + else { + throw new IllegalArgumentException("A valid TestNG config file reference is required."); + } + driver.setTestSuites(testSuites); + } + } + + private String parseMediaTypeFromTestRunArgs(Document testRunArgs) { + NodeList entries = testRunArgs.getElementsByTagName("entry"); + for (int i = 0; i < entries.getLength(); i++) { + Element entry = (Element) entries.item(i); + if (entry.getAttribute("key").equals("acceptMediaType")) { + return entry.getTextContent().trim(); + } + } + return null; + } + + /** + * Extracts test run arguments from an XML properties file. The arguments are added to + * the resulting HashMap object as key-value pairs". + * @param testRunArgs An XML representation of a properties file containing an + * {@literal } element for each supplied argument. + * @return The HashMap containing settings for a test run, including a list of + * parameters (which may be empty). + * + */ + Map extractTestRunArguments(Document testRunArgs) { + Map argsMap = new HashMap<>(); + if (null != testRunArgs) { + NodeList entries = testRunArgs.getElementsByTagName("entry"); + for (int i = 0; i < entries.getLength(); i++) { + Element entry = (Element) entries.item(i); + argsMap.put(entry.getAttribute("key"), entry.getTextContent().trim()); + } + } + return argsMap; + } + +} diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/TestRunSummary.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/TestRunSummary.java index 9caca262f..a0b45ab75 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/TestRunSummary.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/executors/testng/TestRunSummary.java @@ -7,6 +7,26 @@ */ package com.occamlab.te.spi.executors.testng; +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.time.Duration; import java.util.Date; import java.util.Map; diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/ApplicationComponents.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/ApplicationComponents.java index 46d3a54a0..978d096b7 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/ApplicationComponents.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/ApplicationComponents.java @@ -1,30 +1,50 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.occamlab.te.spi.jaxrs; - -import org.glassfish.jersey.server.ResourceConfig; - -/** - * Dynamically searches for root resource and provider classes. An instance of this class - * defines the components of a JAX-RS application and is used to configure a runtime - * environment such as a web container. - * - * @see org.glassfish.jersey.server.ResourceConfig - */ -public class ApplicationComponents extends ResourceConfig { - - /** - * Scans for root resource classes in the - * com.occamlab.te.spi.jaxrs.resources package (or a sub-package). - */ - public ApplicationComponents() { - packages("com.occamlab.te.spi.jaxrs.resources"); - property("jersey.config.server.redirect.servlet.extension", "false"); - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.occamlab.te.spi.jaxrs; + +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import org.glassfish.jersey.server.ResourceConfig; + +/** + * Dynamically searches for root resource and provider classes. An instance of this class + * defines the components of a JAX-RS application and is used to configure a runtime + * environment such as a web container. + * + * @see org.glassfish.jersey.server.ResourceConfig + */ +public class ApplicationComponents extends ResourceConfig { + + /** + * Scans for root resource classes in the + * com.occamlab.te.spi.jaxrs.resources package (or a sub-package). + */ + public ApplicationComponents() { + packages("com.occamlab.te.spi.jaxrs.resources"); + property("jersey.config.server.redirect.servlet.extension", "false"); + } + +} diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/ErrorResponseBuilder.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/ErrorResponseBuilder.java index 5b3eac4c3..b76219455 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/ErrorResponseBuilder.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/ErrorResponseBuilder.java @@ -1,48 +1,68 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.occamlab.te.spi.jaxrs; - -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.Response.ResponseBuilder; - -/** - * Creates an error response that includes an entity body describing the error condition. - * The entity conforms to the XHTML Basic 1.1 schema. - * - * @see XHTML Basic (W3C Recommendation) - */ -public class ErrorResponseBuilder { - - /** - * Builds a response message that indicates some kind of error has occurred. The error - * message is included as the content of the xhtml:body/xhtml:p element. - * @param statusCode The relevant HTTP error code (4xx, 5xx). - * @param msg A brief description of the error condition. - * @return A Response instance containing an XHTML entity. - */ - public Response buildErrorResponse(int statusCode, String msg) { - ResponseBuilder rspBuilder = Response.status(statusCode); - rspBuilder.type("application/xhtml+xml; charset=UTF-8"); - rspBuilder.entity(createErrorEntityAsString(statusCode, msg)); - return rspBuilder.build(); - } - - private String createErrorEntityAsString(int statusCode, String msg) { - StringBuilder doc = new StringBuilder(); - doc.append("\n"); - doc.append( - "\n"); - doc.append("\n"); - doc.append("").append("Status Code ").append(statusCode); - doc.append("\n"); - doc.append("

").append(msg).append("

\n"); - doc.append(""); - return doc.toString(); - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.occamlab.te.spi.jaxrs; + +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.ResponseBuilder; + +/** + * Creates an error response that includes an entity body describing the error condition. + * The entity conforms to the XHTML Basic 1.1 schema. + * + * @see XHTML Basic (W3C Recommendation) + */ +public class ErrorResponseBuilder { + + /** + * Builds a response message that indicates some kind of error has occurred. The error + * message is included as the content of the xhtml:body/xhtml:p element. + * @param statusCode The relevant HTTP error code (4xx, 5xx). + * @param msg A brief description of the error condition. + * @return A Response instance containing an XHTML entity. + */ + public Response buildErrorResponse(int statusCode, String msg) { + ResponseBuilder rspBuilder = Response.status(statusCode); + rspBuilder.type("application/xhtml+xml; charset=UTF-8"); + rspBuilder.entity(createErrorEntityAsString(statusCode, msg)); + return rspBuilder.build(); + } + + private String createErrorEntityAsString(int statusCode, String msg) { + StringBuilder doc = new StringBuilder(); + doc.append("\n"); + doc.append( + "\n"); + doc.append("\n"); + doc.append("").append("Status Code ").append(statusCode); + doc.append("\n"); + doc.append("

").append(msg).append("

\n"); + doc.append(""); + return doc.toString(); + } + +} diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/TestSuiteController.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/TestSuiteController.java index cb3109959..8e6db64e1 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/TestSuiteController.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/TestSuiteController.java @@ -1,48 +1,68 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.occamlab.te.spi.jaxrs; - -import javax.xml.transform.Source; -import org.w3c.dom.Document; - -/** - * Controls execution of a test suite. An executable test suite (ETS) is distinguished by - * an alphanumeric code and a version. - */ -public interface TestSuiteController { - - /** - * Returns the ETS code. - * @return A String containing an alphanumeric code value. It cannot start with a - * digit. - */ - String getCode(); - - /** - * Returns the version of this ETS. - * @return A String indicating the version; it complies with the Maven versioning - * scheme. - */ - String getVersion(); - - /** - * Returns the title of this ETS. - * @return A String denoting the title. - */ - String getTitle(); - - /** - * Executes a test run and returns the results. - * @param testRunArgs A DOM Document conveying the test run arguments. The content is - * implementation-specific. - * @return A Source object that supplies an XML representation of the test results. - * @throws Exception If the supplied test run arguments are invalid for any reason. - */ - Source doTestRun(Document testRunArgs) throws Exception; - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.occamlab.te.spi.jaxrs; + +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import javax.xml.transform.Source; +import org.w3c.dom.Document; + +/** + * Controls execution of a test suite. An executable test suite (ETS) is distinguished by + * an alphanumeric code and a version. + */ +public interface TestSuiteController { + + /** + * Returns the ETS code. + * @return A String containing an alphanumeric code value. It cannot start with a + * digit. + */ + String getCode(); + + /** + * Returns the version of this ETS. + * @return A String indicating the version; it complies with the Maven versioning + * scheme. + */ + String getVersion(); + + /** + * Returns the title of this ETS. + * @return A String denoting the title. + */ + String getTitle(); + + /** + * Executes a test run and returns the results. + * @param testRunArgs A DOM Document conveying the test run arguments. The content is + * implementation-specific. + * @return A Source object that supplies an XML representation of the test results. + * @throws Exception If the supplied test run arguments are invalid for any reason. + */ + Source doTestRun(Document testRunArgs) throws Exception; + +} diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/TestSuiteRegistry.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/TestSuiteRegistry.java index fdf974db0..c405c79c6 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/TestSuiteRegistry.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/TestSuiteRegistry.java @@ -1,98 +1,118 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.occamlab.te.spi.jaxrs; - -import java.util.HashSet; -import java.util.ServiceLoader; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * A registry of executable test suites that implements a discovery and instantiation - * mechanism for known TestSuiteController implementations. The service provider mechanism - * is used to discover test suites. Only one registry is created. - * - * @see java.util.ServiceLoader ServiceLoader - */ -public class TestSuiteRegistry { - - private static final Logger logger = Logger.getLogger(TestSuiteRegistry.class.getPackage().getName()); - - /** - * A singleton instance of the registry. - */ - private static volatile TestSuiteRegistry registry; - - /** - * The set of available TestSuiteController implementations. - */ - private Set controllers; - - /** - * Returns a singleton registry instance in a lazy (but thread-safe) manner. - * @return the {@code TestSuiteRegistry} instance. - */ - public static TestSuiteRegistry getInstance() { - - // Employ a "double-checked locking" strategy because a lock is only - // needed upon initialization; synchronize on the monitor belonging to - // the class itself. - if (null == registry) { - synchronized (TestSuiteRegistry.class) { - // check again, because the thread might have been preempted - // just after the outer if was processed but before the - // synchronized statement was executed - if (registry == null) { - registry = new TestSuiteRegistry(); - } - } - } - return registry; - } - - public Set getControllers() { - return controllers; - } - - /** - * Gets the controller for a specified executable test suite (ETS). - * @param etsCode The alphanumeric code for the ETS. - * @return A TestSuiteController, or {@code null} if one cannot be found. - */ - public TestSuiteController getController(String etsCode) { - if (etsCode.length() == 0 || etsCode == null) { - throw new IllegalArgumentException("ETS code not specified."); - } - TestSuiteController controller = null; - if (!controllers.isEmpty()) { - for (TestSuiteController ets : this.controllers) { - if (ets.getCode().equalsIgnoreCase(etsCode)) { - controller = ets; - break; - } - } - } - return controller; - } - - private TestSuiteRegistry() { - this.controllers = new HashSet<>(); - loadControllers(); - } - - private void loadControllers() { - ClassLoader loader = this.getClass().getClassLoader(); - ServiceLoader srvLoader = ServiceLoader.load(TestSuiteController.class, loader); - for (TestSuiteController controller : srvLoader) { - this.controllers.add(controller); - } - logger.log(Level.CONFIG, "Loaded {0} TestSuiteController implementations.", controllers.size()); - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.occamlab.te.spi.jaxrs; + +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.util.HashSet; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A registry of executable test suites that implements a discovery and instantiation + * mechanism for known TestSuiteController implementations. The service provider mechanism + * is used to discover test suites. Only one registry is created. + * + * @see java.util.ServiceLoader ServiceLoader + */ +public class TestSuiteRegistry { + + private static final Logger logger = Logger.getLogger(TestSuiteRegistry.class.getPackage().getName()); + + /** + * A singleton instance of the registry. + */ + private static volatile TestSuiteRegistry registry; + + /** + * The set of available TestSuiteController implementations. + */ + private Set controllers; + + /** + * Returns a singleton registry instance in a lazy (but thread-safe) manner. + * @return the {@code TestSuiteRegistry} instance. + */ + public static TestSuiteRegistry getInstance() { + + // Employ a "double-checked locking" strategy because a lock is only + // needed upon initialization; synchronize on the monitor belonging to + // the class itself. + if (null == registry) { + synchronized (TestSuiteRegistry.class) { + // check again, because the thread might have been preempted + // just after the outer if was processed but before the + // synchronized statement was executed + if (registry == null) { + registry = new TestSuiteRegistry(); + } + } + } + return registry; + } + + public Set getControllers() { + return controllers; + } + + /** + * Gets the controller for a specified executable test suite (ETS). + * @param etsCode The alphanumeric code for the ETS. + * @return A TestSuiteController, or {@code null} if one cannot be found. + */ + public TestSuiteController getController(String etsCode) { + if (etsCode.length() == 0 || etsCode == null) { + throw new IllegalArgumentException("ETS code not specified."); + } + TestSuiteController controller = null; + if (!controllers.isEmpty()) { + for (TestSuiteController ets : this.controllers) { + if (ets.getCode().equalsIgnoreCase(etsCode)) { + controller = ets; + break; + } + } + } + return controller; + } + + private TestSuiteRegistry() { + this.controllers = new HashSet<>(); + loadControllers(); + } + + private void loadControllers() { + ClassLoader loader = this.getClass().getClassLoader(); + ServiceLoader srvLoader = ServiceLoader.load(TestSuiteController.class, loader); + for (TestSuiteController controller : srvLoader) { + this.controllers.add(controller); + } + logger.log(Level.CONFIG, "Loaded {0} TestSuiteController implementations.", controllers.size()); + } + +} diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/ImageResource.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/ImageResource.java index a85dd6f2b..aa0e758a0 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/ImageResource.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/ImageResource.java @@ -1,50 +1,70 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.occamlab.te.spi.jaxrs.resources; - -import java.io.InputStream; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Response; - -import com.occamlab.te.spi.jaxrs.ErrorResponseBuilder; - -/** - * An image resource referenced by a test suite description. The expected image media type - * is "image/png". - */ -@Path("suites/{etsCode}/{etsVersion}/resources/{image}") -@Produces("image/png") -public class ImageResource { - - /** - * Returns an image resource from this classpath location: - * /doc/{etsCode}/{etsVersion}/resources/{image} - * @param etsCode The test suite code. - * @param etsVersion The test suite version. - * @param image The name of the image resource (e.g. figure-1.png). - * @return An InputStream for reading the image resource from the classpath. - */ - @GET - public Response getImage(@PathParam("etsCode") String etsCode, @PathParam("etsVersion") String etsVersion, - @PathParam("image") String image) { - StringBuilder imgClassPath = new StringBuilder("/doc/"); - imgClassPath.append(etsCode).append("/").append(etsVersion).append("/resources/").append(image); - InputStream imgStream = this.getClass().getResourceAsStream(imgClassPath.toString()); - if (null == imgStream) { - ErrorResponseBuilder builder = new ErrorResponseBuilder(); - Response rsp = builder.buildErrorResponse(404, "Image resource not found."); - throw new WebApplicationException(rsp); - } - return Response.ok(imgStream, "image/png").build(); - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.occamlab.te.spi.jaxrs.resources; + +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.InputStream; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; + +import com.occamlab.te.spi.jaxrs.ErrorResponseBuilder; + +/** + * An image resource referenced by a test suite description. The expected image media type + * is "image/png". + */ +@Path("suites/{etsCode}/{etsVersion}/resources/{image}") +@Produces("image/png") +public class ImageResource { + + /** + * Returns an image resource from this classpath location: + * /doc/{etsCode}/{etsVersion}/resources/{image} + * @param etsCode The test suite code. + * @param etsVersion The test suite version. + * @param image The name of the image resource (e.g. figure-1.png). + * @return An InputStream for reading the image resource from the classpath. + */ + @GET + public Response getImage(@PathParam("etsCode") String etsCode, @PathParam("etsVersion") String etsVersion, + @PathParam("image") String image) { + StringBuilder imgClassPath = new StringBuilder("/doc/"); + imgClassPath.append(etsCode).append("/").append(etsVersion).append("/resources/").append(image); + InputStream imgStream = this.getClass().getResourceAsStream(imgClassPath.toString()); + if (null == imgStream) { + ErrorResponseBuilder builder = new ErrorResponseBuilder(); + Response rsp = builder.buildErrorResponse(404, "Image resource not found."); + throw new WebApplicationException(rsp); + } + return Response.ok(imgStream, "image/png").build(); + } + +} diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/TEStatistics.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/TEStatistics.java index f237d3b8f..d53bd68e9 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/TEStatistics.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/TEStatistics.java @@ -1,5 +1,25 @@ package com.occamlab.te.spi.jaxrs.resources; +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -239,4 +259,4 @@ private Source generateStatisticsReports() { return results; } -} \ No newline at end of file +} diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/TestRunResource.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/TestRunResource.java index 44dd4667d..1dbac1e4c 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/TestRunResource.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/TestRunResource.java @@ -1,474 +1,494 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.occamlab.te.spi.jaxrs.resources; - -import java.io.File; -import java.io.IOException; -import java.nio.file.FileSystems; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Context; -import jakarta.ws.rs.core.HttpHeaders; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.MultivaluedHashMap; -import jakarta.ws.rs.core.MultivaluedMap; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.UriInfo; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.Source; - -import org.apache.commons.io.FileUtils; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import com.occamlab.te.spi.jaxrs.ErrorResponseBuilder; -import com.occamlab.te.spi.jaxrs.TestSuiteController; -import com.occamlab.te.spi.jaxrs.TestSuiteRegistry; -import com.occamlab.te.spi.util.TestRunUtils; -import com.occamlab.te.util.LogUtils; - -import org.glassfish.jersey.internal.util.collection.ImmutableMultivaluedMap; -import org.glassfish.jersey.media.multipart.FormDataParam; - -/** - * A controller resource that provides the results of a test run. An XML representation of - * the results is obtained using HTTP/1.1 methods in accord with the JAX-RS 1.1 - * specification (JSR 311). - * - * @see JSR 311 - */ -@Path("suites/{etsCode}/run") -public class TestRunResource { - - private static final Logger LOGR = Logger.getLogger(TestRunResource.class.getPackage().getName()); - - private static final String TEST_RUN_ARGUMENTS = "Test run arguments - "; - - private static final String ENTITY_MEDIA_TYPE = "Entity media type: "; - - private static final String FILE_LOCATION = "File location: "; - - private static final String APPLICATION_RDF_XML = "application/rdf+xml"; - - private static final String APPLICATION_ZIP = "application/zip"; - - private static final String APPLICATION_XML = "application/xml"; - - @Context - private UriInfo reqUriInfo; - - @Context - private HttpHeaders headers; - - /** - * Processes a request submitted using the GET method with. The test run arguments are - * specified in the query component of the Request-URI as a sequence of key-value - * pairs. - * @param etsCode A String that identifies the test suite to be run. - * @param etsVersion A String specifying the desired test suite version. - * @return An RDF (EARL) representation of the test results. - */ - @GET - @Produces("application/rdf+xml;qs=0.75;charset=utf-8") - public Source handleGetRdf(@PathParam("etsCode") String etsCode, @PathParam("etsVersion") String etsVersion) { - return handleGet(etsCode, etsVersion, APPLICATION_RDF_XML); - } - - /** - * Processes a request submitted using the GET method with. The test run arguments are - * specified in the query component of the Request-URI as a sequence of key-value - * pairs. - * @param etsCode A String that identifies the test suite to be run. - * @param etsVersion A String specifying the desired test suite version. - * @return An XML representation of the test results. - */ - @GET - @Produces("application/xml;qs=0.5;charset=utf-8") - public Source handleGetXml(@PathParam("etsCode") String etsCode, @PathParam("etsVersion") String etsVersion) { - return handleGet(etsCode, etsVersion, APPLICATION_XML); - } - - /** - * Processes a request submitted using the GET method with. The test run arguments are - * specified in the query component of the Request-URI as a sequence of key-value - * pairs. - * @param etsCode A String that identifies the test suite to be run. - * @param etsVersion A String specifying the desired test suite version. - * @return An zip archive containing the HTML representation of the test results. - */ - @GET - @Produces("application/zip;qs=0.25;charset=utf-8") - public Response handleGetZip(@PathParam("etsCode") String etsCode, @PathParam("etsVersion") String etsVersion) - throws IOException { - MultivaluedMap params = this.reqUriInfo.getQueryParameters(); - params = toMutableMultivaluedMap(params); - Source results = executeTestRun(etsCode, params, APPLICATION_ZIP); - - String htmlOutput = results.getSystemId().toString(); - int count = htmlOutput.split(":", -1).length - 1; - String zipFile = (count > 1) ? htmlOutput.split("file:/")[1] : htmlOutput.split("file:")[1]; - File fileOut = new File(zipFile); - if (!fileOut.exists()) { - throw new WebApplicationException(404); - } - return Response.ok(FileUtils.readFileToByteArray(fileOut)) - .type(APPLICATION_ZIP) - .header("Content-Disposition", "attachment; filename=\"result.zip\";") - .header("Cache-Control", "no-cache") - .build(); - } - - /** - * Processes a request submitted using the POST method. The request entity represents - * the test subject or provides metadata about it. The entity body is written to a - * local file, the location of which is set as the value of the {@code iut} parameter. - * @param etsCode A String that identifies the test suite to be run. - * @param etsVersion A String specifying the desired test suite version. - * @param entityBody A File containing the request entity body. - * @return An RDF (EARL) representation of the test results. - */ - @POST - @Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML }) - @Produces("application/rdf+xml;qs=0.75;charset=utf-8") - public Source handlePostRdf(@PathParam("etsCode") String etsCode, @PathParam("etsVersion") String etsVersion, - File entityBody) { - return handlePost(etsCode, etsVersion, entityBody, APPLICATION_RDF_XML); - } - - /** - * Processes a request submitted using the POST method. The request entity represents - * the test subject or provides metadata about it. The entity body is written to a - * local file, the location of which is set as the value of the {@code iut} parameter. - * @param etsCode A String that identifies the test suite to be run. - * @param etsVersion A String specifying the desired test suite version. - * @param entityBody A File containing the request entity body. - * @return An XML representation of the test results. - */ - @POST - @Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML }) - @Produces("application/xml;qs=0.5;charset=utf-8") - public Source handlePostXml(@PathParam("etsCode") String etsCode, @PathParam("etsVersion") String etsVersion, - File entityBody) { - return handlePost(etsCode, etsVersion, entityBody, APPLICATION_XML); - } - - /** - * Processes a request submitted using the POST method. The request entity represents - * the test subject or provides metadata about it. The entity body is written to a - * local file, the location of which is set as the value of the {@code iut} parameter. - * @param etsCode A String that identifies the test suite to be run. - * @param etsVersion A String specifying the desired test suite version. - * @param entityBody A File containing the request entity body. - * @return An zip archive containing the HTML representation of the test results. - */ - @POST - @Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML }) - @Produces("application/zip;qs=0.25;charset=utf-8") - public Source handlePostZip(@PathParam("etsCode") String etsCode, @PathParam("etsVersion") String etsVersion, - File entityBody) { - return handlePost(etsCode, etsVersion, entityBody, APPLICATION_ZIP); - } - - /** - * Processes a request containing a multipart (multipart/form-data) entity. The entity - * is expected to consist of two parts: - *
    - *
  1. The (required) "iut" part represents the test subject or provides metadata - * about it; the entity body is written to a local file, the location of which is set - * as the value of the {@code iut } argument.
  2. - *
  3. The "sch" part defines supplementary constraints defined in a Schematron - * schema; it is also written to a local file, the location of which is set as the - * value of the {@code sch} argument.
  4. - *
- * @param etsCode A String that identifies the test suite to be run. - * @param etsVersion A String specifying the desired test suite version. - * @param entityBody A File containing a representation of the test subject. - * @param schBody A File containing supplementary constraints (e.g. a Schematron - * schema). - * @return An RDF (EARL) representation of the test results. - * - * @see RFC 7578: - * Returning Values from Forms: multipart/form-data - * @see ISO 19757-3: Schematron - */ - @POST - @Consumes({ MediaType.MULTIPART_FORM_DATA }) - @Produces("application/rdf+xml;qs=0.75;charset=utf-8") - public Source handleMultipartFormDataRdf(@PathParam("etsCode") String etsCode, - @PathParam("etsVersion") String etsVersion, @FormDataParam("iut") File entityBody, - @FormDataParam("sch") File schBody) { - return handleMultipartFormDataPost(etsCode, etsVersion, entityBody, schBody, APPLICATION_RDF_XML); - } - - /** - * Processes a request containing a multipart (multipart/form-data) entity. The entity - * is expected to consist of two parts: - *
    - *
  1. The (required) "iut" part represents the test subject or provides metadata - * about it; the entity body is written to a local file, the location of which is set - * as the value of the {@code iut } argument.
  2. - *
  3. The "sch" part defines supplementary constraints defined in a Schematron - * schema; it is also written to a local file, the location of which is set as the - * value of the {@code sch} argument.
  4. - *
- * @param etsCode A String that identifies the test suite to be run. - * @param etsVersion A String specifying the desired test suite version. - * @param entityBody A File containing a representation of the test subject. - * @param schBody A File containing supplementary constraints (e.g. a Schematron - * schema). - * @return An XML representation of the test results. - * - * @see RFC 7578: - * Returning Values from Forms: multipart/form-data - * @see ISO 19757-3: Schematron - */ - @POST - @Consumes({ MediaType.MULTIPART_FORM_DATA }) - @Produces("application/xml;qs=0.5;charset=utf-8") - public Source handleMultipartFormDataXml(@PathParam("etsCode") String etsCode, - @PathParam("etsVersion") String etsVersion, @FormDataParam("iut") File entityBody, - @FormDataParam("sch") File schBody) { - return handleMultipartFormDataPost(etsCode, etsVersion, entityBody, schBody, APPLICATION_XML); - } - - /** - * Processes a request containing a multipart (multipart/form-data) entity. The entity - * is expected to consist of two parts: - *
    - *
  1. The (required) "iut" part represents the test subject or provides metadata - * about it; the entity body is written to a local file, the location of which is set - * as the value of the {@code iut } argument.
  2. - *
  3. The "sch" part defines supplementary constraints defined in a Schematron - * schema; it is also written to a local file, the location of which is set as the - * value of the {@code sch} argument.
  4. - *
- * @param etsCode A String that identifies the test suite to be run. - * @param etsVersion A String specifying the desired test suite version. - * @param entityBody A File containing a representation of the test subject. - * @param schBody A File containing supplementary constraints (e.g. a Schematron - * schema). - * @return An zip archive containing the HTML representation of the test results. - * - * @see RFC 7578: - * Returning Values from Forms: multipart/form-data - * @see ISO 19757-3: Schematron - */ - @POST - @Consumes({ MediaType.MULTIPART_FORM_DATA }) - @Produces("application/zip;qs=0.25;charset=utf-8") - public Source handleMultipartFormDataZip(@PathParam("etsCode") String etsCode, - @PathParam("etsVersion") String etsVersion, @FormDataParam("iut") File entityBody, - @FormDataParam("sch") File schBody) { - return handleMultipartFormDataPost(etsCode, etsVersion, entityBody, schBody, APPLICATION_ZIP); - } - - private Source handleGet(String etsCode, String etsVersion, String preferredMediaType) { - MultivaluedMap params = this.reqUriInfo.getQueryParameters(); - params = toMutableMultivaluedMap(params); - if (LOGR.isLoggable(Level.FINE)) { - StringBuilder msg = new StringBuilder(TEST_RUN_ARGUMENTS); - msg.append(etsCode).append("/").append(etsVersion).append("\n"); - msg.append(params.toString()); - LOGR.fine(msg.toString()); - } - return executeTestRun(etsCode, params, preferredMediaType); - } - - private Source handlePost(String etsCode, String etsVersion, File entityBody, String preferredMediaType) { - if (!entityBody.exists() || entityBody.length() == 0) { - throw new WebApplicationException(400); - } - if (LOGR.isLoggable(Level.FINE)) { - StringBuilder msg = new StringBuilder(TEST_RUN_ARGUMENTS); - msg.append(etsCode).append("/").append(etsVersion).append("\n"); - msg.append(ENTITY_MEDIA_TYPE + this.headers.getMediaType()); - msg.append(FILE_LOCATION + entityBody.getAbsolutePath()); - LOGR.fine(msg.toString()); - } - Map> args = new HashMap<>(); - args.put("iut", Collections.singletonList(entityBody.toURI().toString())); - return executeTestRun(etsCode, args, preferredMediaType); - } - - private Source handleMultipartFormDataPost(String etsCode, String etsVersion, File entityBody, File schBody, - String preferredMediaType) { - Map> args = new HashMap<>(); - if (!entityBody.exists() || entityBody.length() == 0) { - throw new WebApplicationException(400); - } - if (LOGR.isLoggable(Level.FINE)) { - StringBuilder msg = new StringBuilder(TEST_RUN_ARGUMENTS); - msg.append(etsCode).append("/").append(etsVersion).append("\n"); - msg.append(ENTITY_MEDIA_TYPE + this.headers.getMediaType()); - msg.append(FILE_LOCATION + entityBody.getAbsolutePath()); - LOGR.fine(msg.toString()); - } - args.put("iut", Collections.singletonList(entityBody.toURI().toString())); - if (null != schBody) { - if (!schBody.exists() || schBody.length() == 0) { - throw new WebApplicationException(400); - } - if (LOGR.isLoggable(Level.FINE)) { - StringBuilder msg = new StringBuilder(TEST_RUN_ARGUMENTS); - msg.append(etsCode).append("/").append(etsVersion).append("\n"); - msg.append(ENTITY_MEDIA_TYPE + this.headers.getMediaType()); - msg.append(FILE_LOCATION + schBody.getAbsolutePath()); - LOGR.fine(msg.toString()); - } - args.put("sch", Collections.singletonList(schBody.toURI().toString())); - } - return executeTestRun(etsCode, args, preferredMediaType); - } - - /** - * Executes a test run using the supplied arguments. - * @param etsCode A String that identifies the test suite to be run. - * @param testRunArgs A multi-valued Map containing the test run arguments. - * @return An XML representation of the test run results. - * @throws WebApplicationException If an error occurs while executing a test run. - */ - private Source executeTestRun(String etsCode, Map> testRunArgs, String preferredMediaType) { - - List authCredentials = this.headers.getRequestHeader("Authorization"); - String logDir = System.getProperty("TE_BASE") + FileSystems.getDefault().getSeparator() + "users" - + FileSystems.getDefault().getSeparator() + TestRunUtils.getUserName(authCredentials) - + FileSystems.getDefault().getSeparator() + "rest"; - - if (null != logDir) { - String sessionId = LogUtils.generateSessionId(new File(logDir)); - - testRunArgs.put("logDir", List.of(logDir)); - testRunArgs.put("sessionId", Collections.singletonList(sessionId)); - } - - testRunArgs.put("acceptMediaType", Collections.singletonList(preferredMediaType)); - if (LOGR.isLoggable(Level.FINE)) { - StringBuilder msg = new StringBuilder("Test run arguments - "); - msg.append(etsCode).append("/"); - msg.append(testRunArgs.toString()); - if (null != this.headers.getMediaType()) { - msg.append("Entity media type: " + this.headers.getMediaType()); - } - LOGR.fine(msg.toString()); - } - TestSuiteController controller = findController(etsCode); - - testRunArgs.put("sourcesId", List.of(TestRunUtils.getSourcesId(controller))); - Document xmlArgs = readTestRunArguments(testRunArgs); - Source testResults = null; - try { - testResults = controller.doTestRun(xmlArgs); - } - catch (IllegalArgumentException iae) { - ErrorResponseBuilder builder = new ErrorResponseBuilder(); - Response rsp = builder.buildErrorResponse(400, iae.getMessage()); - throw new WebApplicationException(rsp); - } - catch (Exception ex) { - LOGR.log(Level.WARNING, ex.getMessage(), ex); - ErrorResponseBuilder builder = new ErrorResponseBuilder(); - String error_msg = "Error executing test suite (" + etsCode + "): " + "Error message: " + ex.getMessage(); - Response rsp = builder.buildErrorResponse(500, error_msg); - throw new WebApplicationException(rsp); - } - LOGR.fine(String.format("Test results for suite %s: %s", etsCode, testResults.getSystemId())); - return testResults; - } - - /** - * Obtains a TestSuiteController for a particular executable test suite - * (ETS) identified by code and version. - * @param code A String identifying the ETS to execute. - * @return The TestSuiteController for the requested ETS. - * @throws WebApplicationException If a corresponding controller cannot be found. - */ - private TestSuiteController findController(String code) throws WebApplicationException { - TestSuiteRegistry registry = TestSuiteRegistry.getInstance(); - TestSuiteController controller = registry.getController(code); - if (null == controller) { - throw new WebApplicationException(404); - } - return controller; - } - - /** - * Extracts test run arguments from the given Map and inserts them into a DOM Document - * representing an XML properties file. - * @param requestParams A collection of key-value pairs. Each key can have zero or - * more values but only the first value is used. - * @return A DOM Document node. - * @see java.util.Properties - */ - private Document readTestRunArguments(Map> requestParams) { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - Document propsDoc = null; - try { - DocumentBuilder db = dbf.newDocumentBuilder(); - propsDoc = db.newDocument(); - } - catch (ParserConfigurationException ex) { - LOGR.log(Level.SEVERE, null, ex); - } - Element docElem = propsDoc.createElement("properties"); - docElem.setAttribute("version", "1.0"); - for (Map.Entry> param : requestParams.entrySet()) { - Element entry = propsDoc.createElement("entry"); - entry.setAttribute("key", param.getKey()); - StringBuilder values = new StringBuilder(); - for (Iterator itr = param.getValue().iterator(); itr.hasNext();) { - values.append(itr.next()); - if (itr.hasNext()) { - values.append(","); - } - } - entry.setTextContent(values.toString()); - docElem.appendChild(entry); - } - propsDoc.appendChild(docElem); - return propsDoc; - } - - /** - * Checks if the input MulivalueMap is immutable. If this is the case, a new mutable - * MultivaluedHashMap is created containing the values of the input map. - * @param multivaluedMap A MultivalueMap - * @return A mutable MultivalueMap - */ - private MultivaluedMap toMutableMultivaluedMap(MultivaluedMap multivaluedMap) { - if (multivaluedMap instanceof ImmutableMultivaluedMap) { - MultivaluedMap newMultivaluedMap = new MultivaluedHashMap<>(); - for (String key : multivaluedMap.keySet()) { - newMultivaluedMap.put(key, multivaluedMap.get(key)); - } - multivaluedMap = newMultivaluedMap; - } - return multivaluedMap; - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.occamlab.te.spi.jaxrs.resources; + +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileSystems; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedHashMap; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriInfo; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Source; + +import org.apache.commons.io.FileUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import com.occamlab.te.spi.jaxrs.ErrorResponseBuilder; +import com.occamlab.te.spi.jaxrs.TestSuiteController; +import com.occamlab.te.spi.jaxrs.TestSuiteRegistry; +import com.occamlab.te.spi.util.TestRunUtils; +import com.occamlab.te.util.LogUtils; + +import org.glassfish.jersey.internal.util.collection.ImmutableMultivaluedMap; +import org.glassfish.jersey.media.multipart.FormDataParam; + +/** + * A controller resource that provides the results of a test run. An XML representation of + * the results is obtained using HTTP/1.1 methods in accord with the JAX-RS 1.1 + * specification (JSR 311). + * + * @see JSR 311 + */ +@Path("suites/{etsCode}/run") +public class TestRunResource { + + private static final Logger LOGR = Logger.getLogger(TestRunResource.class.getPackage().getName()); + + private static final String TEST_RUN_ARGUMENTS = "Test run arguments - "; + + private static final String ENTITY_MEDIA_TYPE = "Entity media type: "; + + private static final String FILE_LOCATION = "File location: "; + + private static final String APPLICATION_RDF_XML = "application/rdf+xml"; + + private static final String APPLICATION_ZIP = "application/zip"; + + private static final String APPLICATION_XML = "application/xml"; + + @Context + private UriInfo reqUriInfo; + + @Context + private HttpHeaders headers; + + /** + * Processes a request submitted using the GET method with. The test run arguments are + * specified in the query component of the Request-URI as a sequence of key-value + * pairs. + * @param etsCode A String that identifies the test suite to be run. + * @param etsVersion A String specifying the desired test suite version. + * @return An RDF (EARL) representation of the test results. + */ + @GET + @Produces("application/rdf+xml;qs=0.75;charset=utf-8") + public Source handleGetRdf(@PathParam("etsCode") String etsCode, @PathParam("etsVersion") String etsVersion) { + return handleGet(etsCode, etsVersion, APPLICATION_RDF_XML); + } + + /** + * Processes a request submitted using the GET method with. The test run arguments are + * specified in the query component of the Request-URI as a sequence of key-value + * pairs. + * @param etsCode A String that identifies the test suite to be run. + * @param etsVersion A String specifying the desired test suite version. + * @return An XML representation of the test results. + */ + @GET + @Produces("application/xml;qs=0.5;charset=utf-8") + public Source handleGetXml(@PathParam("etsCode") String etsCode, @PathParam("etsVersion") String etsVersion) { + return handleGet(etsCode, etsVersion, APPLICATION_XML); + } + + /** + * Processes a request submitted using the GET method with. The test run arguments are + * specified in the query component of the Request-URI as a sequence of key-value + * pairs. + * @param etsCode A String that identifies the test suite to be run. + * @param etsVersion A String specifying the desired test suite version. + * @return An zip archive containing the HTML representation of the test results. + */ + @GET + @Produces("application/zip;qs=0.25;charset=utf-8") + public Response handleGetZip(@PathParam("etsCode") String etsCode, @PathParam("etsVersion") String etsVersion) + throws IOException { + MultivaluedMap params = this.reqUriInfo.getQueryParameters(); + params = toMutableMultivaluedMap(params); + Source results = executeTestRun(etsCode, params, APPLICATION_ZIP); + + String htmlOutput = results.getSystemId().toString(); + int count = htmlOutput.split(":", -1).length - 1; + String zipFile = (count > 1) ? htmlOutput.split("file:/")[1] : htmlOutput.split("file:")[1]; + File fileOut = new File(zipFile); + if (!fileOut.exists()) { + throw new WebApplicationException(404); + } + return Response.ok(FileUtils.readFileToByteArray(fileOut)) + .type(APPLICATION_ZIP) + .header("Content-Disposition", "attachment; filename=\"result.zip\";") + .header("Cache-Control", "no-cache") + .build(); + } + + /** + * Processes a request submitted using the POST method. The request entity represents + * the test subject or provides metadata about it. The entity body is written to a + * local file, the location of which is set as the value of the {@code iut} parameter. + * @param etsCode A String that identifies the test suite to be run. + * @param etsVersion A String specifying the desired test suite version. + * @param entityBody A File containing the request entity body. + * @return An RDF (EARL) representation of the test results. + */ + @POST + @Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML }) + @Produces("application/rdf+xml;qs=0.75;charset=utf-8") + public Source handlePostRdf(@PathParam("etsCode") String etsCode, @PathParam("etsVersion") String etsVersion, + File entityBody) { + return handlePost(etsCode, etsVersion, entityBody, APPLICATION_RDF_XML); + } + + /** + * Processes a request submitted using the POST method. The request entity represents + * the test subject or provides metadata about it. The entity body is written to a + * local file, the location of which is set as the value of the {@code iut} parameter. + * @param etsCode A String that identifies the test suite to be run. + * @param etsVersion A String specifying the desired test suite version. + * @param entityBody A File containing the request entity body. + * @return An XML representation of the test results. + */ + @POST + @Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML }) + @Produces("application/xml;qs=0.5;charset=utf-8") + public Source handlePostXml(@PathParam("etsCode") String etsCode, @PathParam("etsVersion") String etsVersion, + File entityBody) { + return handlePost(etsCode, etsVersion, entityBody, APPLICATION_XML); + } + + /** + * Processes a request submitted using the POST method. The request entity represents + * the test subject or provides metadata about it. The entity body is written to a + * local file, the location of which is set as the value of the {@code iut} parameter. + * @param etsCode A String that identifies the test suite to be run. + * @param etsVersion A String specifying the desired test suite version. + * @param entityBody A File containing the request entity body. + * @return An zip archive containing the HTML representation of the test results. + */ + @POST + @Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML }) + @Produces("application/zip;qs=0.25;charset=utf-8") + public Source handlePostZip(@PathParam("etsCode") String etsCode, @PathParam("etsVersion") String etsVersion, + File entityBody) { + return handlePost(etsCode, etsVersion, entityBody, APPLICATION_ZIP); + } + + /** + * Processes a request containing a multipart (multipart/form-data) entity. The entity + * is expected to consist of two parts: + *
    + *
  1. The (required) "iut" part represents the test subject or provides metadata + * about it; the entity body is written to a local file, the location of which is set + * as the value of the {@code iut } argument.
  2. + *
  3. The "sch" part defines supplementary constraints defined in a Schematron + * schema; it is also written to a local file, the location of which is set as the + * value of the {@code sch} argument.
  4. + *
+ * @param etsCode A String that identifies the test suite to be run. + * @param etsVersion A String specifying the desired test suite version. + * @param entityBody A File containing a representation of the test subject. + * @param schBody A File containing supplementary constraints (e.g. a Schematron + * schema). + * @return An RDF (EARL) representation of the test results. + * + * @see RFC 7578: + * Returning Values from Forms: multipart/form-data + * @see ISO 19757-3: Schematron + */ + @POST + @Consumes({ MediaType.MULTIPART_FORM_DATA }) + @Produces("application/rdf+xml;qs=0.75;charset=utf-8") + public Source handleMultipartFormDataRdf(@PathParam("etsCode") String etsCode, + @PathParam("etsVersion") String etsVersion, @FormDataParam("iut") File entityBody, + @FormDataParam("sch") File schBody) { + return handleMultipartFormDataPost(etsCode, etsVersion, entityBody, schBody, APPLICATION_RDF_XML); + } + + /** + * Processes a request containing a multipart (multipart/form-data) entity. The entity + * is expected to consist of two parts: + *
    + *
  1. The (required) "iut" part represents the test subject or provides metadata + * about it; the entity body is written to a local file, the location of which is set + * as the value of the {@code iut } argument.
  2. + *
  3. The "sch" part defines supplementary constraints defined in a Schematron + * schema; it is also written to a local file, the location of which is set as the + * value of the {@code sch} argument.
  4. + *
+ * @param etsCode A String that identifies the test suite to be run. + * @param etsVersion A String specifying the desired test suite version. + * @param entityBody A File containing a representation of the test subject. + * @param schBody A File containing supplementary constraints (e.g. a Schematron + * schema). + * @return An XML representation of the test results. + * + * @see RFC 7578: + * Returning Values from Forms: multipart/form-data + * @see ISO 19757-3: Schematron + */ + @POST + @Consumes({ MediaType.MULTIPART_FORM_DATA }) + @Produces("application/xml;qs=0.5;charset=utf-8") + public Source handleMultipartFormDataXml(@PathParam("etsCode") String etsCode, + @PathParam("etsVersion") String etsVersion, @FormDataParam("iut") File entityBody, + @FormDataParam("sch") File schBody) { + return handleMultipartFormDataPost(etsCode, etsVersion, entityBody, schBody, APPLICATION_XML); + } + + /** + * Processes a request containing a multipart (multipart/form-data) entity. The entity + * is expected to consist of two parts: + *
    + *
  1. The (required) "iut" part represents the test subject or provides metadata + * about it; the entity body is written to a local file, the location of which is set + * as the value of the {@code iut } argument.
  2. + *
  3. The "sch" part defines supplementary constraints defined in a Schematron + * schema; it is also written to a local file, the location of which is set as the + * value of the {@code sch} argument.
  4. + *
+ * @param etsCode A String that identifies the test suite to be run. + * @param etsVersion A String specifying the desired test suite version. + * @param entityBody A File containing a representation of the test subject. + * @param schBody A File containing supplementary constraints (e.g. a Schematron + * schema). + * @return An zip archive containing the HTML representation of the test results. + * + * @see RFC 7578: + * Returning Values from Forms: multipart/form-data + * @see ISO 19757-3: Schematron + */ + @POST + @Consumes({ MediaType.MULTIPART_FORM_DATA }) + @Produces("application/zip;qs=0.25;charset=utf-8") + public Source handleMultipartFormDataZip(@PathParam("etsCode") String etsCode, + @PathParam("etsVersion") String etsVersion, @FormDataParam("iut") File entityBody, + @FormDataParam("sch") File schBody) { + return handleMultipartFormDataPost(etsCode, etsVersion, entityBody, schBody, APPLICATION_ZIP); + } + + private Source handleGet(String etsCode, String etsVersion, String preferredMediaType) { + MultivaluedMap params = this.reqUriInfo.getQueryParameters(); + params = toMutableMultivaluedMap(params); + if (LOGR.isLoggable(Level.FINE)) { + StringBuilder msg = new StringBuilder(TEST_RUN_ARGUMENTS); + msg.append(etsCode).append("/").append(etsVersion).append("\n"); + msg.append(params.toString()); + LOGR.fine(msg.toString()); + } + return executeTestRun(etsCode, params, preferredMediaType); + } + + private Source handlePost(String etsCode, String etsVersion, File entityBody, String preferredMediaType) { + if (!entityBody.exists() || entityBody.length() == 0) { + throw new WebApplicationException(400); + } + if (LOGR.isLoggable(Level.FINE)) { + StringBuilder msg = new StringBuilder(TEST_RUN_ARGUMENTS); + msg.append(etsCode).append("/").append(etsVersion).append("\n"); + msg.append(ENTITY_MEDIA_TYPE + this.headers.getMediaType()); + msg.append(FILE_LOCATION + entityBody.getAbsolutePath()); + LOGR.fine(msg.toString()); + } + Map> args = new HashMap<>(); + args.put("iut", Collections.singletonList(entityBody.toURI().toString())); + return executeTestRun(etsCode, args, preferredMediaType); + } + + private Source handleMultipartFormDataPost(String etsCode, String etsVersion, File entityBody, File schBody, + String preferredMediaType) { + Map> args = new HashMap<>(); + if (!entityBody.exists() || entityBody.length() == 0) { + throw new WebApplicationException(400); + } + if (LOGR.isLoggable(Level.FINE)) { + StringBuilder msg = new StringBuilder(TEST_RUN_ARGUMENTS); + msg.append(etsCode).append("/").append(etsVersion).append("\n"); + msg.append(ENTITY_MEDIA_TYPE + this.headers.getMediaType()); + msg.append(FILE_LOCATION + entityBody.getAbsolutePath()); + LOGR.fine(msg.toString()); + } + args.put("iut", Collections.singletonList(entityBody.toURI().toString())); + if (null != schBody) { + if (!schBody.exists() || schBody.length() == 0) { + throw new WebApplicationException(400); + } + if (LOGR.isLoggable(Level.FINE)) { + StringBuilder msg = new StringBuilder(TEST_RUN_ARGUMENTS); + msg.append(etsCode).append("/").append(etsVersion).append("\n"); + msg.append(ENTITY_MEDIA_TYPE + this.headers.getMediaType()); + msg.append(FILE_LOCATION + schBody.getAbsolutePath()); + LOGR.fine(msg.toString()); + } + args.put("sch", Collections.singletonList(schBody.toURI().toString())); + } + return executeTestRun(etsCode, args, preferredMediaType); + } + + /** + * Executes a test run using the supplied arguments. + * @param etsCode A String that identifies the test suite to be run. + * @param testRunArgs A multi-valued Map containing the test run arguments. + * @return An XML representation of the test run results. + * @throws WebApplicationException If an error occurs while executing a test run. + */ + private Source executeTestRun(String etsCode, Map> testRunArgs, String preferredMediaType) { + + List authCredentials = this.headers.getRequestHeader("Authorization"); + String logDir = System.getProperty("TE_BASE") + FileSystems.getDefault().getSeparator() + "users" + + FileSystems.getDefault().getSeparator() + TestRunUtils.getUserName(authCredentials) + + FileSystems.getDefault().getSeparator() + "rest"; + + if (null != logDir) { + String sessionId = LogUtils.generateSessionId(new File(logDir)); + + testRunArgs.put("logDir", List.of(logDir)); + testRunArgs.put("sessionId", Collections.singletonList(sessionId)); + } + + testRunArgs.put("acceptMediaType", Collections.singletonList(preferredMediaType)); + if (LOGR.isLoggable(Level.FINE)) { + StringBuilder msg = new StringBuilder("Test run arguments - "); + msg.append(etsCode).append("/"); + msg.append(testRunArgs.toString()); + if (null != this.headers.getMediaType()) { + msg.append("Entity media type: " + this.headers.getMediaType()); + } + LOGR.fine(msg.toString()); + } + TestSuiteController controller = findController(etsCode); + + testRunArgs.put("sourcesId", List.of(TestRunUtils.getSourcesId(controller))); + Document xmlArgs = readTestRunArguments(testRunArgs); + Source testResults = null; + try { + testResults = controller.doTestRun(xmlArgs); + } + catch (IllegalArgumentException iae) { + ErrorResponseBuilder builder = new ErrorResponseBuilder(); + Response rsp = builder.buildErrorResponse(400, iae.getMessage()); + throw new WebApplicationException(rsp); + } + catch (Exception ex) { + LOGR.log(Level.WARNING, ex.getMessage(), ex); + ErrorResponseBuilder builder = new ErrorResponseBuilder(); + String error_msg = "Error executing test suite (" + etsCode + "): " + "Error message: " + ex.getMessage(); + Response rsp = builder.buildErrorResponse(500, error_msg); + throw new WebApplicationException(rsp); + } + LOGR.fine(String.format("Test results for suite %s: %s", etsCode, testResults.getSystemId())); + return testResults; + } + + /** + * Obtains a TestSuiteController for a particular executable test suite + * (ETS) identified by code and version. + * @param code A String identifying the ETS to execute. + * @return The TestSuiteController for the requested ETS. + * @throws WebApplicationException If a corresponding controller cannot be found. + */ + private TestSuiteController findController(String code) throws WebApplicationException { + TestSuiteRegistry registry = TestSuiteRegistry.getInstance(); + TestSuiteController controller = registry.getController(code); + if (null == controller) { + throw new WebApplicationException(404); + } + return controller; + } + + /** + * Extracts test run arguments from the given Map and inserts them into a DOM Document + * representing an XML properties file. + * @param requestParams A collection of key-value pairs. Each key can have zero or + * more values but only the first value is used. + * @return A DOM Document node. + * @see java.util.Properties + */ + private Document readTestRunArguments(Map> requestParams) { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + Document propsDoc = null; + try { + DocumentBuilder db = dbf.newDocumentBuilder(); + propsDoc = db.newDocument(); + } + catch (ParserConfigurationException ex) { + LOGR.log(Level.SEVERE, null, ex); + } + Element docElem = propsDoc.createElement("properties"); + docElem.setAttribute("version", "1.0"); + for (Map.Entry> param : requestParams.entrySet()) { + Element entry = propsDoc.createElement("entry"); + entry.setAttribute("key", param.getKey()); + StringBuilder values = new StringBuilder(); + for (Iterator itr = param.getValue().iterator(); itr.hasNext();) { + values.append(itr.next()); + if (itr.hasNext()) { + values.append(","); + } + } + entry.setTextContent(values.toString()); + docElem.appendChild(entry); + } + propsDoc.appendChild(docElem); + return propsDoc; + } + + /** + * Checks if the input MulivalueMap is immutable. If this is the case, a new mutable + * MultivaluedHashMap is created containing the values of the input map. + * @param multivaluedMap A MultivalueMap + * @return A mutable MultivalueMap + */ + private MultivaluedMap toMutableMultivaluedMap(MultivaluedMap multivaluedMap) { + if (multivaluedMap instanceof ImmutableMultivaluedMap) { + MultivaluedMap newMultivaluedMap = new MultivaluedHashMap<>(); + for (String key : multivaluedMap.keySet()) { + newMultivaluedMap.put(key, multivaluedMap.get(key)); + } + multivaluedMap = newMultivaluedMap; + } + return multivaluedMap; + } + +} diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/TestSuiteOverviewResource.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/TestSuiteOverviewResource.java index 6f17b1e5c..f4d8e9504 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/TestSuiteOverviewResource.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/TestSuiteOverviewResource.java @@ -7,6 +7,26 @@ */ package com.occamlab.te.spi.jaxrs.resources; +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/TestSuiteSetResource.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/TestSuiteSetResource.java index 7c56e2e43..36c448d6c 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/TestSuiteSetResource.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/jaxrs/resources/TestSuiteSetResource.java @@ -1,213 +1,233 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * ********************************************************************************* - * - * Version Date January 6, 2018 - * - * Contributor(s): - * C. Heazel (WiSC) MOdifications to address Fortify issues - * - * ********************************************************************************* - */ - -package com.occamlab.te.spi.jaxrs.resources; - -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Context; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.UriBuilder; -import jakarta.ws.rs.core.UriInfo; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.Source; -import javax.xml.transform.dom.DOMSource; -import com.occamlab.te.spi.jaxrs.TestSuiteController; -import com.occamlab.te.spi.jaxrs.TestSuiteRegistry; - -import org.json.simple.JSONObject; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Text; - -/** - * A collection resource that provides a listing of all available test suites. - */ -@Path("suites") -public class TestSuiteSetResource { - - @Context - private UriInfo reqUriInfo; - - private static final String HTML_NS = "http://www.w3.org/1999/xhtml"; - - private DocumentBuilder docBuilder; - - public TestSuiteSetResource() { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - try { - this.docBuilder = factory.newDocumentBuilder(); - } - catch (ParserConfigurationException ex) { - Logger.getLogger(TestSuiteSetResource.class.getName()).log(Level.WARNING, null, ex); - } - } - - /** - * Presents an XHTML representation containing a listing of registered test suites - * with links to each. - * @return A Source object containing the information needed to read the collection - * (an HTML5 document represented using the XHTML syntax). - */ - @GET - @Produces("application/xhtml+xml; charset=utf-8") - public Source listTestSuites() { - Document xhtmlDoc = readTemplate(); - if (null == xhtmlDoc) { - throw new WebApplicationException(Response.serverError() - .entity("Failed to parse test-suites.html") - .type(MediaType.TEXT_PLAIN) - .build()); - } - Element listElem = (Element) xhtmlDoc.getElementsByTagNameNS(HTML_NS, "ul").item(0); - TestSuiteRegistry registry = TestSuiteRegistry.getInstance(); - Set etsControllers = registry.getControllers(); - StringBuilder etsURI = new StringBuilder(); - for (TestSuiteController etsController : etsControllers) { - Element li = xhtmlDoc.createElementNS(HTML_NS, "li"); - listElem.appendChild(li); - Element link = xhtmlDoc.createElementNS(HTML_NS, "a"); - li.appendChild(link); - Text title = xhtmlDoc.createTextNode(etsController.getTitle()); - link.appendChild(title); - link.setAttribute("type", "text/html"); - if (!reqUriInfo.getPath().endsWith("/")) { - etsURI.append(this.reqUriInfo.getPath()).append("/"); - } - etsURI.append(etsController.getCode()).append("/"); - link.setAttribute("href", etsURI.toString()); - link.setAttribute("id", etsController.getCode()); - etsURI.setLength(0); - } - return new DOMSource(xhtmlDoc); - } - - /** - * Presents an XML representation containing a listing of registered test suites with - * links to each. - * @return A Source object containing the information needed to read the collection - * (an XML document). - */ - @GET - @Produces("application/xml; charset=utf-8") - public Source listTestSuitesAsXML() { - Document xmlDoc = this.docBuilder.newDocument(); - - Element testSuites = xmlDoc.createElement("testSuites"); - xmlDoc.appendChild(testSuites); - - TestSuiteRegistry registry = TestSuiteRegistry.getInstance(); - Set etsControllers = registry.getControllers(); - - for (TestSuiteController etsController : etsControllers) { - - Element testSuite = xmlDoc.createElement("testSuite"); - testSuites.appendChild(testSuite); - - Element testSuiteTitle = xmlDoc.createElement("title"); - testSuiteTitle.setTextContent(etsController.getTitle()); - testSuite.appendChild(testSuiteTitle); - - Element testSuiteVersion = xmlDoc.createElement("version"); - testSuiteVersion.setTextContent(etsController.getVersion()); - testSuite.appendChild(testSuiteVersion); - - Element testSuiteRestUri = xmlDoc.createElement("endpoint"); - - UriBuilder etsURI = reqUriInfo.getRequestUriBuilder(); - etsURI.path(etsController.getCode()); - testSuiteRestUri.setTextContent(etsURI.build().toString()); - testSuite.appendChild(testSuiteRestUri); - - Element testSuiteEtsCode = xmlDoc.createElement("etscode"); - testSuiteEtsCode.setTextContent(etsController.getCode()); - testSuite.appendChild(testSuiteEtsCode); - } - return new DOMSource(xmlDoc); - } - - /** - * Presents an JSON representation containing a listing of registered test suites with - * links to each. - * @return A Response with object containing the information. - */ - @GET - @Produces("application/json") - public Response listTestSuitesAsJSON() { - List testSuiteList = new ArrayList<>(); - - TestSuiteRegistry registry = TestSuiteRegistry.getInstance(); - Set etsControllers = registry.getControllers(); - - for (TestSuiteController etsController : etsControllers) { - StringBuilder etsURI = new StringBuilder(); - etsURI.append(reqUriInfo.getBaseUri()); - etsURI.append(this.reqUriInfo.getPath()); - etsURI.append(etsController.getCode()).append("/"); - - Map testSuiteInfoMap = new HashMap<>(); - testSuiteInfoMap.put("title", etsController.getTitle()); - testSuiteInfoMap.put("version", etsController.getVersion()); - testSuiteInfoMap.put("etsCode", etsController.getCode()); - testSuiteInfoMap.put("endpoint", etsURI.toString()); - - JSONObject testSuiteInfo = new JSONObject(testSuiteInfoMap); - - testSuiteList.add(testSuiteInfo); - } - Map> testSuitesMap = new HashMap<>(); - testSuitesMap.put("testSuites", testSuiteList); - - JSONObject testSuites = new JSONObject(testSuitesMap); - - return Response.status(200).entity(testSuites.toString()).build(); - } - - /** - * Reads the template document from the classpath. It contains an empty list. - * @return A DOM Document node. - */ - Document readTemplate() { - InputStream inStream = this.getClass().getResourceAsStream("test-suites.html"); - Document doc = null; - try { - doc = this.docBuilder.parse(inStream); - // Fortify Mod: Close the InputStream and release its resources - inStream.close(); - } - catch (Exception ex) { - Logger.getLogger(TestSuiteSetResource.class.getName()) - .log(Level.WARNING, "Failed to parse test-suites.html", ex); - } - return doc; - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ********************************************************************************* + * + * Version Date January 6, 2018 + * + * Contributor(s): + * C. Heazel (WiSC) MOdifications to address Fortify issues + * + * ********************************************************************************* + */ + +package com.occamlab.te.spi.jaxrs.resources; + +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriBuilder; +import jakarta.ws.rs.core.UriInfo; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Source; +import javax.xml.transform.dom.DOMSource; +import com.occamlab.te.spi.jaxrs.TestSuiteController; +import com.occamlab.te.spi.jaxrs.TestSuiteRegistry; + +import org.json.simple.JSONObject; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Text; + +/** + * A collection resource that provides a listing of all available test suites. + */ +@Path("suites") +public class TestSuiteSetResource { + + @Context + private UriInfo reqUriInfo; + + private static final String HTML_NS = "http://www.w3.org/1999/xhtml"; + + private DocumentBuilder docBuilder; + + public TestSuiteSetResource() { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + try { + this.docBuilder = factory.newDocumentBuilder(); + } + catch (ParserConfigurationException ex) { + Logger.getLogger(TestSuiteSetResource.class.getName()).log(Level.WARNING, null, ex); + } + } + + /** + * Presents an XHTML representation containing a listing of registered test suites + * with links to each. + * @return A Source object containing the information needed to read the collection + * (an HTML5 document represented using the XHTML syntax). + */ + @GET + @Produces("application/xhtml+xml; charset=utf-8") + public Source listTestSuites() { + Document xhtmlDoc = readTemplate(); + if (null == xhtmlDoc) { + throw new WebApplicationException(Response.serverError() + .entity("Failed to parse test-suites.html") + .type(MediaType.TEXT_PLAIN) + .build()); + } + Element listElem = (Element) xhtmlDoc.getElementsByTagNameNS(HTML_NS, "ul").item(0); + TestSuiteRegistry registry = TestSuiteRegistry.getInstance(); + Set etsControllers = registry.getControllers(); + StringBuilder etsURI = new StringBuilder(); + for (TestSuiteController etsController : etsControllers) { + Element li = xhtmlDoc.createElementNS(HTML_NS, "li"); + listElem.appendChild(li); + Element link = xhtmlDoc.createElementNS(HTML_NS, "a"); + li.appendChild(link); + Text title = xhtmlDoc.createTextNode(etsController.getTitle()); + link.appendChild(title); + link.setAttribute("type", "text/html"); + if (!reqUriInfo.getPath().endsWith("/")) { + etsURI.append(this.reqUriInfo.getPath()).append("/"); + } + etsURI.append(etsController.getCode()).append("/"); + link.setAttribute("href", etsURI.toString()); + link.setAttribute("id", etsController.getCode()); + etsURI.setLength(0); + } + return new DOMSource(xhtmlDoc); + } + + /** + * Presents an XML representation containing a listing of registered test suites with + * links to each. + * @return A Source object containing the information needed to read the collection + * (an XML document). + */ + @GET + @Produces("application/xml; charset=utf-8") + public Source listTestSuitesAsXML() { + Document xmlDoc = this.docBuilder.newDocument(); + + Element testSuites = xmlDoc.createElement("testSuites"); + xmlDoc.appendChild(testSuites); + + TestSuiteRegistry registry = TestSuiteRegistry.getInstance(); + Set etsControllers = registry.getControllers(); + + for (TestSuiteController etsController : etsControllers) { + + Element testSuite = xmlDoc.createElement("testSuite"); + testSuites.appendChild(testSuite); + + Element testSuiteTitle = xmlDoc.createElement("title"); + testSuiteTitle.setTextContent(etsController.getTitle()); + testSuite.appendChild(testSuiteTitle); + + Element testSuiteVersion = xmlDoc.createElement("version"); + testSuiteVersion.setTextContent(etsController.getVersion()); + testSuite.appendChild(testSuiteVersion); + + Element testSuiteRestUri = xmlDoc.createElement("endpoint"); + + UriBuilder etsURI = reqUriInfo.getRequestUriBuilder(); + etsURI.path(etsController.getCode()); + testSuiteRestUri.setTextContent(etsURI.build().toString()); + testSuite.appendChild(testSuiteRestUri); + + Element testSuiteEtsCode = xmlDoc.createElement("etscode"); + testSuiteEtsCode.setTextContent(etsController.getCode()); + testSuite.appendChild(testSuiteEtsCode); + } + return new DOMSource(xmlDoc); + } + + /** + * Presents an JSON representation containing a listing of registered test suites with + * links to each. + * @return A Response with object containing the information. + */ + @GET + @Produces("application/json") + public Response listTestSuitesAsJSON() { + List testSuiteList = new ArrayList<>(); + + TestSuiteRegistry registry = TestSuiteRegistry.getInstance(); + Set etsControllers = registry.getControllers(); + + for (TestSuiteController etsController : etsControllers) { + StringBuilder etsURI = new StringBuilder(); + etsURI.append(reqUriInfo.getBaseUri()); + etsURI.append(this.reqUriInfo.getPath()); + etsURI.append(etsController.getCode()).append("/"); + + Map testSuiteInfoMap = new HashMap<>(); + testSuiteInfoMap.put("title", etsController.getTitle()); + testSuiteInfoMap.put("version", etsController.getVersion()); + testSuiteInfoMap.put("etsCode", etsController.getCode()); + testSuiteInfoMap.put("endpoint", etsURI.toString()); + + JSONObject testSuiteInfo = new JSONObject(testSuiteInfoMap); + + testSuiteList.add(testSuiteInfo); + } + Map> testSuitesMap = new HashMap<>(); + testSuitesMap.put("testSuites", testSuiteList); + + JSONObject testSuites = new JSONObject(testSuitesMap); + + return Response.status(200).entity(testSuites.toString()).build(); + } + + /** + * Reads the template document from the classpath. It contains an empty list. + * @return A DOM Document node. + */ + Document readTemplate() { + InputStream inStream = this.getClass().getResourceAsStream("test-suites.html"); + Document doc = null; + try { + doc = this.docBuilder.parse(inStream); + // Fortify Mod: Close the InputStream and release its resources + inStream.close(); + } + catch (Exception ex) { + Logger.getLogger(TestSuiteSetResource.class.getName()) + .log(Level.WARNING, "Failed to parse test-suites.html", ex); + } + return doc; + } + +} diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/report/ReportLog.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/report/ReportLog.java index 3b7ca6c42..e214be1d8 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/report/ReportLog.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/report/ReportLog.java @@ -7,6 +7,26 @@ */ package com.occamlab.te.spi.report; +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/stats/SessionDetails.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/stats/SessionDetails.java index dea9fa645..05ee8c83b 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/stats/SessionDetails.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/stats/SessionDetails.java @@ -1,5 +1,25 @@ package com.occamlab.te.spi.stats; +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.util.List; /** diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/stats/TEStatisticsErrorHandler.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/stats/TEStatisticsErrorHandler.java index 30ace4857..b2abdf8cc 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/stats/TEStatisticsErrorHandler.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/stats/TEStatisticsErrorHandler.java @@ -1,5 +1,25 @@ package com.occamlab.te.spi.stats; +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.util.logging.Level; import java.util.logging.Logger; diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/util/HtmlReport.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/util/HtmlReport.java index 41e486918..4ff0294ae 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/util/HtmlReport.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/util/HtmlReport.java @@ -1,174 +1,194 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * ******************************************************************** - * - * Version Date: March 26, 2018 - * - * Contributor(s): - * C. Heazel (WiSC): Reversed Fortify mods. Since the input EARL report - * is generated by TeamEngine, there is no external entity injection - * threat. Retained breakout of the individual steps in setting up - * the transform within the try block at line 84. - * - * ******************************************************************** - */ - -package com.occamlab.te.spi.util; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; - -import com.occamlab.te.util.Utils; - -/** - * - * This class is used to process HTML result. It will transform EARL result into HTML - * report and return the HTML result with zip file. - * - * Contributor(s): C. Heazel (WiSC) Modifications to address Fortify issues - * - */ -public class HtmlReport { - - private static final Logger LOGR = Logger.getLogger(HtmlReport.class.getPackage().getName()); - - /** - * This method will return the HTML result with zip file. - * @param outputDirectory - * @return - * @throws FileNotFoundException - */ - public static File getHtmlResultZip(String outputDirectory) throws FileNotFoundException { - File htmlResult = earlHtmlReport(outputDirectory); - File htmlResultFile = new File(outputDirectory, "result.zip"); - try { - zipDir(htmlResultFile, htmlResult); - } - catch (Exception e) { - LOGR.log(Level.SEVERE, "Could not create zip file with html results.", e); - } - return htmlResultFile; - - } - - /** - * Convert EARL result into HTML report. - * @param outputDir Location of the test result. - * @return Return the output file. - * @throws FileNotFoundException Throws exception if file is not available. - */ - public static File earlHtmlReport(String outputDir) throws FileNotFoundException { - - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - URL resourceDirUrl = cl.getResource("com/occamlab/te/earl/lib"); - String earlXsl = cl.getResource("com/occamlab/te/earl_html_report.xsl").toString(); - - File htmlOutput = new File(outputDir, "result"); - htmlOutput.mkdir(); - LOGR.fine("HTML output is written to directory " + htmlOutput); - File earlResult = new File(outputDir, "earl-results.rdf"); - - try { - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer transformer = tf.newTransformer(new StreamSource(earlXsl)); - transformer.setParameter("outputDir", htmlOutput); - File indexHtml = new File(htmlOutput, "index.html"); - indexHtml.createNewFile(); - FileOutputStream outputStream = new FileOutputStream(indexHtml); - transformer.transform(new StreamSource(earlResult), new StreamResult(outputStream)); - // Foritfy Mod: Close the outputStream releasing its resources - outputStream.close(); - Utils.copyResourceDir(resourceDirUrl, htmlOutput); - } - catch (Exception e) { - LOGR.log(Level.SEVERE, "Transformation of EARL to HTML failed.", e); - throw new RuntimeException(e); - } - if (!htmlOutput.exists()) { - throw new FileNotFoundException("HTML results not found at " + htmlOutput.getAbsolutePath()); - } - return htmlOutput; - } - - /** - * Zips the directory and all of it's sub directories - * @param zipFile Path of zip file. - * @param dirObj Location of test result - * @throws Exception It will throw this exception if file not found. - */ - public static void zipDir(File zipFile, File dirObj) throws Exception { - // File dirObj = new File(dir); - if (!dirObj.isDirectory()) { - LOGR.severe(dirObj.getName() + " is not a directory"); - System.exit(1); - } - - try { - - ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile)); - - LOGR.fine("Creating : " + zipFile); - - addDir(dirObj, out); - // Complete the ZIP file - out.close(); - - } - catch (IOException e) { - throw new Exception(e.getMessage()); - } - - } - - /** - * Add directory to zip file - * @param dirObj - * @param out - * @throws IOException - */ - private static void addDir(File dirObj, ZipOutputStream out) throws IOException { - File[] dirList = dirObj.listFiles(); - byte[] tmpBuf = new byte[1024]; - - for (int i = 0; i < dirList.length; i++) { - if (dirList[i].isDirectory()) { - addDir(dirList[i], out); - continue; - } - - FileInputStream in = new FileInputStream(dirList[i].getAbsolutePath()); - LOGR.fine(" Adding: " + dirList[i].getAbsolutePath()); - - out.putNextEntry(new ZipEntry(dirList[i].getName())); - - // Transfer from the file to the ZIP file - int len; - while ((len = in.read(tmpBuf)) > 0) { - out.write(tmpBuf, 0, len); - } - - // Complete the entry - out.closeEntry(); - in.close(); - } - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ******************************************************************** + * + * Version Date: March 26, 2018 + * + * Contributor(s): + * C. Heazel (WiSC): Reversed Fortify mods. Since the input EARL report + * is generated by TeamEngine, there is no external entity injection + * threat. Retained breakout of the individual steps in setting up + * the transform within the try block at line 84. + * + * ******************************************************************** + */ + +package com.occamlab.te.spi.util; + +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import com.occamlab.te.util.Utils; + +/** + * + * This class is used to process HTML result. It will transform EARL result into HTML + * report and return the HTML result with zip file. + * + * Contributor(s): C. Heazel (WiSC) Modifications to address Fortify issues + * + */ +public class HtmlReport { + + private static final Logger LOGR = Logger.getLogger(HtmlReport.class.getPackage().getName()); + + /** + * This method will return the HTML result with zip file. + * @param outputDirectory + * @return + * @throws FileNotFoundException + */ + public static File getHtmlResultZip(String outputDirectory) throws FileNotFoundException { + File htmlResult = earlHtmlReport(outputDirectory); + File htmlResultFile = new File(outputDirectory, "result.zip"); + try { + zipDir(htmlResultFile, htmlResult); + } + catch (Exception e) { + LOGR.log(Level.SEVERE, "Could not create zip file with html results.", e); + } + return htmlResultFile; + + } + + /** + * Convert EARL result into HTML report. + * @param outputDir Location of the test result. + * @return Return the output file. + * @throws FileNotFoundException Throws exception if file is not available. + */ + public static File earlHtmlReport(String outputDir) throws FileNotFoundException { + + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + URL resourceDirUrl = cl.getResource("com/occamlab/te/earl/lib"); + String earlXsl = cl.getResource("com/occamlab/te/earl_html_report.xsl").toString(); + + File htmlOutput = new File(outputDir, "result"); + htmlOutput.mkdir(); + LOGR.fine("HTML output is written to directory " + htmlOutput); + File earlResult = new File(outputDir, "earl-results.rdf"); + + try { + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer = tf.newTransformer(new StreamSource(earlXsl)); + transformer.setParameter("outputDir", htmlOutput); + File indexHtml = new File(htmlOutput, "index.html"); + indexHtml.createNewFile(); + FileOutputStream outputStream = new FileOutputStream(indexHtml); + transformer.transform(new StreamSource(earlResult), new StreamResult(outputStream)); + // Foritfy Mod: Close the outputStream releasing its resources + outputStream.close(); + Utils.copyResourceDir(resourceDirUrl, htmlOutput); + } + catch (Exception e) { + LOGR.log(Level.SEVERE, "Transformation of EARL to HTML failed.", e); + throw new RuntimeException(e); + } + if (!htmlOutput.exists()) { + throw new FileNotFoundException("HTML results not found at " + htmlOutput.getAbsolutePath()); + } + return htmlOutput; + } + + /** + * Zips the directory and all of it's sub directories + * @param zipFile Path of zip file. + * @param dirObj Location of test result + * @throws Exception It will throw this exception if file not found. + */ + public static void zipDir(File zipFile, File dirObj) throws Exception { + // File dirObj = new File(dir); + if (!dirObj.isDirectory()) { + LOGR.severe(dirObj.getName() + " is not a directory"); + System.exit(1); + } + + try { + + ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile)); + + LOGR.fine("Creating : " + zipFile); + + addDir(dirObj, out); + // Complete the ZIP file + out.close(); + + } + catch (IOException e) { + throw new Exception(e.getMessage()); + } + + } + + /** + * Add directory to zip file + * @param dirObj + * @param out + * @throws IOException + */ + private static void addDir(File dirObj, ZipOutputStream out) throws IOException { + File[] dirList = dirObj.listFiles(); + byte[] tmpBuf = new byte[1024]; + + for (int i = 0; i < dirList.length; i++) { + if (dirList[i].isDirectory()) { + addDir(dirList[i], out); + continue; + } + + FileInputStream in = new FileInputStream(dirList[i].getAbsolutePath()); + LOGR.fine(" Adding: " + dirList[i].getAbsolutePath()); + + out.putNextEntry(new ZipEntry(dirList[i].getName())); + + // Transfer from the file to the ZIP file + int len; + while ((len = in.read(tmpBuf)) > 0) { + out.write(tmpBuf, 0, len); + } + + // Complete the entry + out.closeEntry(); + in.close(); + } + } + +} diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/util/TEStatisticsUtil.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/util/TEStatisticsUtil.java index 558ba4eb5..ca80d370d 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/util/TEStatisticsUtil.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/util/TEStatisticsUtil.java @@ -1,5 +1,25 @@ package com.occamlab.te.spi.util; +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; @@ -894,4 +914,4 @@ private static void addDir(File dirPath, ZipOutputStream out) throws IOException } } -} \ No newline at end of file +} diff --git a/teamengine-spi/src/main/java/com/occamlab/te/spi/util/TestRunUtils.java b/teamengine-spi/src/main/java/com/occamlab/te/spi/util/TestRunUtils.java index 2bf2a0927..a02ccc50c 100644 --- a/teamengine-spi/src/main/java/com/occamlab/te/spi/util/TestRunUtils.java +++ b/teamengine-spi/src/main/java/com/occamlab/te/spi/util/TestRunUtils.java @@ -1,5 +1,25 @@ package com.occamlab.te.spi.util; +/*- + * #%L + * TEAM Engine - Service Providers + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; diff --git a/teamengine-spi/src/main/resources/com/occamlab/te/spi/jaxrs/resources/test-suites.html b/teamengine-spi/src/main/resources/com/occamlab/te/spi/jaxrs/resources/test-suites.html index 14a33a059..9dad5d7c6 100644 --- a/teamengine-spi/src/main/resources/com/occamlab/te/spi/jaxrs/resources/test-suites.html +++ b/teamengine-spi/src/main/resources/com/occamlab/te/spi/jaxrs/resources/test-suites.html @@ -1,11 +1,31 @@ - - - - - Available test suites - - -

Available test suites

-
    - - + + + + + + + Available test suites + + +

    Available test suites

    +
      + + diff --git a/teamengine-spi/src/main/resources/testng-report.xsl b/teamengine-spi/src/main/resources/testng-report.xsl index 1e9409dfb..266fb83a2 100644 --- a/teamengine-spi/src/main/resources/testng-report.xsl +++ b/teamengine-spi/src/main/resources/testng-report.xsl @@ -1,4 +1,24 @@ + + - - - Produces a simple text summary from the output of a TestNG XML reporter. - - - - - - Test suite: - - - ======== Test groups ======== - - - - - Passed: - - | Failed: - - | Skipped: - - - - - - \ No newline at end of file + + + + + Produces a simple text summary from the output of a TestNG XML reporter. + + + + + + Test suite: + + + ======== Test groups ======== + + + + + Passed: + + | Failed: + + | Skipped: + + + + + + diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/AuthorizeTestngReportFilter.java b/teamengine-web/src/main/java/com/occamlab/te/web/AuthorizeTestngReportFilter.java index 7810aca82..c1961d2d0 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/AuthorizeTestngReportFilter.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/AuthorizeTestngReportFilter.java @@ -1,5 +1,25 @@ package com.occamlab.te.web; +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.IOException; import jakarta.servlet.Filter; diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/CachedHttpURLConnection.java b/teamengine-web/src/main/java/com/occamlab/te/web/CachedHttpURLConnection.java index 538ba91e7..829c23abb 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/CachedHttpURLConnection.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/CachedHttpURLConnection.java @@ -1,57 +1,77 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.occamlab.te.web; - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; - -public class CachedHttpURLConnection extends HttpURLConnectionCopy { - - byte[] content = null; - - public CachedHttpURLConnection(HttpURLConnectionCopy uc) { - super(uc); - } - - public CachedHttpURLConnection(HttpURLConnection uc) { - this(new HttpURLConnectionCopy(uc)); - } - - public void connect() throws IOException { - super.connect(); - BufferedInputStream bis = new BufferedInputStream(uc.getInputStream()); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - int i = bis.read(); - while (i >= 0) { - baos.write(i); - i = bis.read(); - } - bis.close(); - baos.close(); - content = baos.toByteArray(); - } - - public InputStream getInputStream() throws IOException { - if (content == null) { - connect(); - } - return new ByteArrayInputStream(content); - } - - public int getLength() throws IOException { - if (content == null) { - connect(); - } - return content.length; - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.occamlab.te.web; + +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; + +public class CachedHttpURLConnection extends HttpURLConnectionCopy { + + byte[] content = null; + + public CachedHttpURLConnection(HttpURLConnectionCopy uc) { + super(uc); + } + + public CachedHttpURLConnection(HttpURLConnection uc) { + this(new HttpURLConnectionCopy(uc)); + } + + public void connect() throws IOException { + super.connect(); + BufferedInputStream bis = new BufferedInputStream(uc.getInputStream()); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int i = bis.read(); + while (i >= 0) { + baos.write(i); + i = bis.read(); + } + bis.close(); + baos.close(); + content = baos.toByteArray(); + } + + public InputStream getInputStream() throws IOException { + if (content == null) { + connect(); + } + return new ByteArrayInputStream(content); + } + + public int getLength() throws IOException { + if (content == null) { + connect(); + } + return content.length; + } + +} diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/CoverageMonitor.java b/teamengine-web/src/main/java/com/occamlab/te/web/CoverageMonitor.java index 989353010..a2e5653f3 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/CoverageMonitor.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/CoverageMonitor.java @@ -1,254 +1,274 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * ************************************************************************** - * - * Contributor(s): - * C. Heazel (WiSC): Added Fortify adjudication changes - * - *************************************************************************** - */ -package com.occamlab.te.web; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URI; -import java.util.HashMap; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.w3c.dom.bootstrap.DOMImplementationRegistry; -import org.w3c.dom.ls.DOMImplementationLS; -import org.w3c.dom.ls.LSOutput; -import org.w3c.dom.ls.LSSerializer; - -/** - * Monitors which service capabilities are exercised by a client request. A representation - * of a service implementation conformance statement (ICS) is updated according to the - * content of a request message; that is, any supplied parameter options are pruned from - * the initial tree. - *

      - * When the test session is terminated the residual tree includes only those request - * parameter values that did not appear in any request, thus indicating - * which implemented options were not covered. - *

      - * - *

      - * A sample representation of an ICS for the GetCapabilities request is shown in the - * listing below. - *

      - * - *
      - * {@code
      - * 
      - *   
      - *     text/xml
      - *   
      - *   
      - *     0
      - *   
      - * 
      - * }
      - * 
      - * - */ -public class CoverageMonitor { - - private static final Logger LOGR = Logger.getLogger(CoverageMonitor.class.getPackage().getName()); - - private static final Map ICS_MAP = createICSMap(); - - private URI requestId; - - private Document coverageDoc; - - private File testSessionDir; - - /** - * Creates a CoverageMonitor for a given service request. - * @param uri A URI value that identifies a service request message. - */ - public CoverageMonitor(String uri) { - this.requestId = URI.create(uri); - String icsPath = "/coverage/" + ICS_MAP.get(this.requestId); - try { - // Fortify Mod: Disable entity expansion to foil External Entity Injections - DocumentBuilderFactory df = DocumentBuilderFactory.newInstance(); - df.setNamespaceAware(true); - df.setExpandEntityReferences(false); - DocumentBuilder docBuilder = df.newDocumentBuilder(); - // DocumentBuilder docBuilder = - // DocumentBuilderFactory.newInstance().newDocumentBuilder(); - // Fortify Mod: make sure the input stream is closed - // this.coverageDoc = docBuilder.parse( - // getClass().getResourceAsStream(icsPath), null); - InputStream is = getClass().getResourceAsStream(icsPath); - this.coverageDoc = docBuilder.parse(is, null); - is.close(); - // End Fortify Mods - } - catch (Exception e) { - LOGR.warning(e.getMessage()); - } - LOGR.config("Created coverage monitor using ICS at " + icsPath); - } - - private static Map createICSMap() { - HashMap icsMap = new HashMap<>(); - icsMap.put(URI.create("urn:wms_client_test_suite/GetCapabilities"), "WMS-GetCapabilities.xml"); - icsMap.put(URI.create("urn:wms_client_test_suite/GetMap"), "WMS-GetMap.xml"); - icsMap.put(URI.create("urn:wms_client_test_suite/GetFeatureInfo"), "WMS-GetFeatureInfo.xml"); - return icsMap; - } - - /** - * Returns the location of the test session directory. - * @return A File object denoting a directory in the local file system. - */ - public File getTestSessionDir() { - return testSessionDir; - } - - /** - * Sets the location of the test session directory where the coverage results will be - * written to. - * @param sessionDir A File object (it should correspond to a directory). - */ - public void setTestSessionDir(File sessionDir) { - if (!sessionDir.isDirectory()) { - throw new IllegalArgumentException("Not a directory: " + testSessionDir); - } - this.testSessionDir = sessionDir; - } - - /** - * Inspects the query part of a GET request URI and updates the ICS document by - * removing parameter values that occur in the request. The initial coverage report is - * modified over the course of the test run as requests are received; the residual - * document includes only those parameter values that were not requested. - * @param query The (decoded) query component of a GET request. - */ - void inspectQuery(String query) { - Map qryParams = new HashMap<>(); - for (String param : query.split("&")) { - String[] nvp = param.split("="); - if (nvp.length > 1) { - qryParams.put(nvp[0].toLowerCase(), nvp[1]); - } - else { - qryParams.put(nvp[0].toLowerCase(), ""); - } - } - String reqType = qryParams.get("request"); - XPath xpath = XPathFactory.newInstance().newXPath(); - for (Map.Entry paramEntry : qryParams.entrySet()) { - String[] paramValues = paramEntry.getValue().split(","); - for (int i = 0; i < paramValues.length; i++) { - String expr = String.format("//request[@name='%s']/param[@name='%s']/value[text() = '%s']", reqType, - paramEntry.getKey(), paramValues[i]); - NodeList result = null; - try { - result = (NodeList) xpath.evaluate(expr, this.coverageDoc, XPathConstants.NODESET); - } - catch (XPathExpressionException xpe) { - LOGR.log(Level.WARNING, "Failed to evaluate expression " + expr, xpe); - } - if ((null != result) && (result.getLength() > 0)) { - for (int j = 0; j < result.getLength(); j++) { - Node value = result.item(j); - Element param = (Element) value.getParentNode(); - param.removeChild(value); - // remove empty param element - if (param.getElementsByTagName("value").getLength() == 0) { - Node request = param.getParentNode(); - request.removeChild(param); - } - } - } - } - } - } - - /** - * Writes the residual ICS document to a file in the test session directory. - */ - public void writeCoverageResults() { - File coverageFile = new File(this.testSessionDir, ICS_MAP.get(this.requestId)); - if (coverageFile.exists()) { - return; - } - OutputStream fos = null; - try { - fos = new FileOutputStream(coverageFile, false); - writeDocument(fos, this.coverageDoc); - } - catch (FileNotFoundException e) { - } - finally { - try { - // Fortify Mod: If fos is null, then nothing was written - if (fos != null) { - fos.close(); - LOGR.config("Wrote coverage results to " + coverageFile.getCanonicalPath()); - } - else { - // If nothing was written, then there should be an exception message. - // If an additional message is desired, then add it here. - } - } - catch (IOException ioe) { - LOGR.warning(ioe.getMessage()); - } - } - - } - - /** - * Writes a DOM Document to the given OutputStream using the "UTF-8" encoding. The XML - * declaration is omitted. - * @param outStream The destination OutputStream object. - * @param doc A Document node. - */ - void writeDocument(OutputStream outStream, Document doc) { - DOMImplementationRegistry domRegistry = null; - try { - domRegistry = DOMImplementationRegistry.newInstance(); - // Fortify Mod: Broaden try block to capture all potential exceptions - // } catch (Exception e) { - // LOGR.warning(e.getMessage()); - // } - DOMImplementationLS impl = (DOMImplementationLS) domRegistry.getDOMImplementation("LS"); - LSSerializer writer = impl.createLSSerializer(); - writer.getDomConfig().setParameter("xml-declaration", false); - writer.getDomConfig().setParameter("format-pretty-print", true); - LSOutput output = impl.createLSOutput(); - output.setEncoding("UTF-8"); - output.setByteStream(outStream); - writer.write(doc, output); - } - catch (Exception e) { - LOGR.warning(e.getMessage()); - } - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ************************************************************************** + * + * Contributor(s): + * C. Heazel (WiSC): Added Fortify adjudication changes + * + *************************************************************************** + */ +package com.occamlab.te.web; + +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.bootstrap.DOMImplementationRegistry; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSOutput; +import org.w3c.dom.ls.LSSerializer; + +/** + * Monitors which service capabilities are exercised by a client request. A representation + * of a service implementation conformance statement (ICS) is updated according to the + * content of a request message; that is, any supplied parameter options are pruned from + * the initial tree. + *

      + * When the test session is terminated the residual tree includes only those request + * parameter values that did not appear in any request, thus indicating + * which implemented options were not covered. + *

      + * + *

      + * A sample representation of an ICS for the GetCapabilities request is shown in the + * listing below. + *

      + * + *
      + * {@code
      + * 
      + *   
      + *     text/xml
      + *   
      + *   
      + *     0
      + *   
      + * 
      + * }
      + * 
      + * + */ +public class CoverageMonitor { + + private static final Logger LOGR = Logger.getLogger(CoverageMonitor.class.getPackage().getName()); + + private static final Map ICS_MAP = createICSMap(); + + private URI requestId; + + private Document coverageDoc; + + private File testSessionDir; + + /** + * Creates a CoverageMonitor for a given service request. + * @param uri A URI value that identifies a service request message. + */ + public CoverageMonitor(String uri) { + this.requestId = URI.create(uri); + String icsPath = "/coverage/" + ICS_MAP.get(this.requestId); + try { + // Fortify Mod: Disable entity expansion to foil External Entity Injections + DocumentBuilderFactory df = DocumentBuilderFactory.newInstance(); + df.setNamespaceAware(true); + df.setExpandEntityReferences(false); + DocumentBuilder docBuilder = df.newDocumentBuilder(); + // DocumentBuilder docBuilder = + // DocumentBuilderFactory.newInstance().newDocumentBuilder(); + // Fortify Mod: make sure the input stream is closed + // this.coverageDoc = docBuilder.parse( + // getClass().getResourceAsStream(icsPath), null); + InputStream is = getClass().getResourceAsStream(icsPath); + this.coverageDoc = docBuilder.parse(is, null); + is.close(); + // End Fortify Mods + } + catch (Exception e) { + LOGR.warning(e.getMessage()); + } + LOGR.config("Created coverage monitor using ICS at " + icsPath); + } + + private static Map createICSMap() { + HashMap icsMap = new HashMap<>(); + icsMap.put(URI.create("urn:wms_client_test_suite/GetCapabilities"), "WMS-GetCapabilities.xml"); + icsMap.put(URI.create("urn:wms_client_test_suite/GetMap"), "WMS-GetMap.xml"); + icsMap.put(URI.create("urn:wms_client_test_suite/GetFeatureInfo"), "WMS-GetFeatureInfo.xml"); + return icsMap; + } + + /** + * Returns the location of the test session directory. + * @return A File object denoting a directory in the local file system. + */ + public File getTestSessionDir() { + return testSessionDir; + } + + /** + * Sets the location of the test session directory where the coverage results will be + * written to. + * @param sessionDir A File object (it should correspond to a directory). + */ + public void setTestSessionDir(File sessionDir) { + if (!sessionDir.isDirectory()) { + throw new IllegalArgumentException("Not a directory: " + testSessionDir); + } + this.testSessionDir = sessionDir; + } + + /** + * Inspects the query part of a GET request URI and updates the ICS document by + * removing parameter values that occur in the request. The initial coverage report is + * modified over the course of the test run as requests are received; the residual + * document includes only those parameter values that were not requested. + * @param query The (decoded) query component of a GET request. + */ + void inspectQuery(String query) { + Map qryParams = new HashMap<>(); + for (String param : query.split("&")) { + String[] nvp = param.split("="); + if (nvp.length > 1) { + qryParams.put(nvp[0].toLowerCase(), nvp[1]); + } + else { + qryParams.put(nvp[0].toLowerCase(), ""); + } + } + String reqType = qryParams.get("request"); + XPath xpath = XPathFactory.newInstance().newXPath(); + for (Map.Entry paramEntry : qryParams.entrySet()) { + String[] paramValues = paramEntry.getValue().split(","); + for (int i = 0; i < paramValues.length; i++) { + String expr = String.format("//request[@name='%s']/param[@name='%s']/value[text() = '%s']", reqType, + paramEntry.getKey(), paramValues[i]); + NodeList result = null; + try { + result = (NodeList) xpath.evaluate(expr, this.coverageDoc, XPathConstants.NODESET); + } + catch (XPathExpressionException xpe) { + LOGR.log(Level.WARNING, "Failed to evaluate expression " + expr, xpe); + } + if ((null != result) && (result.getLength() > 0)) { + for (int j = 0; j < result.getLength(); j++) { + Node value = result.item(j); + Element param = (Element) value.getParentNode(); + param.removeChild(value); + // remove empty param element + if (param.getElementsByTagName("value").getLength() == 0) { + Node request = param.getParentNode(); + request.removeChild(param); + } + } + } + } + } + } + + /** + * Writes the residual ICS document to a file in the test session directory. + */ + public void writeCoverageResults() { + File coverageFile = new File(this.testSessionDir, ICS_MAP.get(this.requestId)); + if (coverageFile.exists()) { + return; + } + OutputStream fos = null; + try { + fos = new FileOutputStream(coverageFile, false); + writeDocument(fos, this.coverageDoc); + } + catch (FileNotFoundException e) { + } + finally { + try { + // Fortify Mod: If fos is null, then nothing was written + if (fos != null) { + fos.close(); + LOGR.config("Wrote coverage results to " + coverageFile.getCanonicalPath()); + } + else { + // If nothing was written, then there should be an exception message. + // If an additional message is desired, then add it here. + } + } + catch (IOException ioe) { + LOGR.warning(ioe.getMessage()); + } + } + + } + + /** + * Writes a DOM Document to the given OutputStream using the "UTF-8" encoding. The XML + * declaration is omitted. + * @param outStream The destination OutputStream object. + * @param doc A Document node. + */ + void writeDocument(OutputStream outStream, Document doc) { + DOMImplementationRegistry domRegistry = null; + try { + domRegistry = DOMImplementationRegistry.newInstance(); + // Fortify Mod: Broaden try block to capture all potential exceptions + // } catch (Exception e) { + // LOGR.warning(e.getMessage()); + // } + DOMImplementationLS impl = (DOMImplementationLS) domRegistry.getDOMImplementation("LS"); + LSSerializer writer = impl.createLSSerializer(); + writer.getDomConfig().setParameter("xml-declaration", false); + writer.getDomConfig().setParameter("format-pretty-print", true); + LSOutput output = impl.createLSOutput(); + output.setEncoding("UTF-8"); + output.setByteStream(outStream); + writer.write(doc, output); + } + catch (Exception e) { + LOGR.warning(e.getMessage()); + } + } + +} diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/DeleteSessionServlet.java b/teamengine-web/src/main/java/com/occamlab/te/web/DeleteSessionServlet.java index 42a7869dc..bb2387ca7 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/DeleteSessionServlet.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/DeleteSessionServlet.java @@ -1,59 +1,79 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - ***************************************************************************** - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): No additional contributors to date - - *************************************************************************** - */ -package com.occamlab.te.web; - -import java.io.File; - -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -import com.occamlab.te.config.Config; -import com.occamlab.te.util.Misc; - -/** - * Processes a request to delete an existing test session. - * - */ -public class DeleteSessionServlet extends HttpServlet { - - private static final long serialVersionUID = 7544788524756976408L; - - Config Conf; - - public void init() throws ServletException { - Conf = new Config(); - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { - try { - String sessionId = request.getParameter("session"); - File userdir = new File(Conf.getUsersDir(), request.getRemoteUser()); - File sessiondir = new File(userdir, sessionId); - Misc.deleteDir(sessiondir); - response.sendRedirect("sessionDeleted.jsp"); - } - catch (Exception e) { - throw new ServletException(e); - } - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + ***************************************************************************** + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): No additional contributors to date + + *************************************************************************** + */ +package com.occamlab.te.web; + +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import com.occamlab.te.config.Config; +import com.occamlab.te.util.Misc; + +/** + * Processes a request to delete an existing test session. + * + */ +public class DeleteSessionServlet extends HttpServlet { + + private static final long serialVersionUID = 7544788524756976408L; + + Config Conf; + + public void init() throws ServletException { + Conf = new Config(); + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { + try { + String sessionId = request.getParameter("session"); + File userdir = new File(Conf.getUsersDir(), request.getRemoteUser()); + File sessiondir = new File(userdir, sessionId); + Misc.deleteDir(sessiondir); + response.sendRedirect("sessionDeleted.jsp"); + } + catch (Exception e) { + throw new ServletException(e); + } + } + +} diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/DownloadLogServlet.java b/teamengine-web/src/main/java/com/occamlab/te/web/DownloadLogServlet.java index e8ac84ed7..2a86ff709 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/DownloadLogServlet.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/DownloadLogServlet.java @@ -1,72 +1,92 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * ************************************************************************** - * - * Version Date: January 5, 2018 - * - * Contributor(s): - * C. Heazel (WiSC): Changes to address Fortity issues - * - * ************************************************************************** - */ - -package com.occamlab.te.web; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.OutputStream; - -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -import com.occamlab.te.config.Config; -import com.occamlab.te.util.ZipUtils; - -/** - * Servlet implementation class for Servlet: DownloadLogServlet - * - */ -public class DownloadLogServlet extends jakarta.servlet.http.HttpServlet implements jakarta.servlet.Servlet { - - Config Conf; - - public void init() throws ServletException { - Conf = new Config(); - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { - try { - String sessionId = request.getParameter("session"); - String zipFileName = sessionId + ".zip"; - File userdir = new File(Conf.getUsersDir(), request.getRemoteUser()); - File sessiondir = new File(userdir, sessionId); - File zipFile = new File(userdir, zipFileName); - ZipUtils.zipDir(zipFile, sessiondir); - response.setContentType("application/zip"); - response.setHeader("Content-Disposition", "attachment; filename=" + zipFileName + ";"); - response.setHeader("Cache-Control", "no-cache"); - byte[] buf = new byte[response.getBufferSize()]; - response.setContentLength((int) zipFile.length()); - System.out.println("file length : " + (int) zipFile.length()); - int length; - BufferedInputStream fileInBuf = new BufferedInputStream(new FileInputStream(zipFile)); - OutputStream out = response.getOutputStream(); - while ((length = fileInBuf.read(buf)) > 0) { - out.write(buf, 0, length); - } - // Fortify Mod: close the input stream - fileInBuf.close(); - } - catch (Exception e) { - System.out.println(e.getMessage()); - } - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ************************************************************************** + * + * Version Date: January 5, 2018 + * + * Contributor(s): + * C. Heazel (WiSC): Changes to address Fortity issues + * + * ************************************************************************** + */ + +package com.occamlab.te.web; + +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.OutputStream; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import com.occamlab.te.config.Config; +import com.occamlab.te.util.ZipUtils; + +/** + * Servlet implementation class for Servlet: DownloadLogServlet + * + */ +public class DownloadLogServlet extends jakarta.servlet.http.HttpServlet implements jakarta.servlet.Servlet { + + Config Conf; + + public void init() throws ServletException { + Conf = new Config(); + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { + try { + String sessionId = request.getParameter("session"); + String zipFileName = sessionId + ".zip"; + File userdir = new File(Conf.getUsersDir(), request.getRemoteUser()); + File sessiondir = new File(userdir, sessionId); + File zipFile = new File(userdir, zipFileName); + ZipUtils.zipDir(zipFile, sessiondir); + response.setContentType("application/zip"); + response.setHeader("Content-Disposition", "attachment; filename=" + zipFileName + ";"); + response.setHeader("Cache-Control", "no-cache"); + byte[] buf = new byte[response.getBufferSize()]; + response.setContentLength((int) zipFile.length()); + System.out.println("file length : " + (int) zipFile.length()); + int length; + BufferedInputStream fileInBuf = new BufferedInputStream(new FileInputStream(zipFile)); + OutputStream out = response.getOutputStream(); + while ((length = fileInBuf.read(buf)) > 0) { + out.write(buf, 0, length); + } + // Fortify Mod: close the input stream + fileInBuf.close(); + } + catch (Exception e) { + System.out.println(e.getMessage()); + } + } + +} diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/EmailLogServlet.java b/teamengine-web/src/main/java/com/occamlab/te/web/EmailLogServlet.java index 8b685dfc4..594237cbd 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/EmailLogServlet.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/EmailLogServlet.java @@ -1,171 +1,191 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * ************************************************************************** - * - * Contributor(s): - * C. Heazel (WiSC): Added Fortify adjudication changes - * - *************************************************************************** - */ - -package com.occamlab.te.web; - -import java.io.File; -import java.util.Date; -import java.util.Properties; - -import javax.activation.DataHandler; -import javax.activation.FileDataSource; -import javax.mail.Message; -import javax.mail.MessagingException; -import javax.mail.Multipart; -import javax.mail.Session; -import javax.mail.Transport; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeBodyPart; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeMultipart; -import jakarta.servlet.RequestDispatcher; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -import com.occamlab.te.config.Config; -import com.occamlab.te.util.ZipUtils; - -/** - * Servlet implementation class for Servlet: EmailLogServlet - * - */ -public class EmailLogServlet extends jakarta.servlet.http.HttpServlet implements jakarta.servlet.Servlet { - - Config Conf; - - public void init() throws ServletException { - Conf = new Config(); - } - - public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException { - try { - File userdir = new File(Conf.getUsersDir(), request.getParameter("userId")); - File zipFile = new File(userdir, request.getParameter("zipFileName")); - - if (sendLog(getServletConfig().getInitParameter("mail.smtp.host"), - getServletConfig().getInitParameter("mail.smtp.userid"), - getServletConfig().getInitParameter("mail.smtp.passwd"), request.getParameter("to"), - request.getParameter("from"), request.getParameter("subject"), request.getParameter("message"), - zipFile)) { - request.setAttribute("emailStatus", "Email sent Succesfully"); - } - else { - request.setAttribute("emailStatus", "Email failed"); - } - - RequestDispatcher rd = request.getRequestDispatcher("emailSent.jsp"); - rd.forward(request, response); - } - catch (Exception e) { - System.out.println(e.getMessage()); - } - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { - try { - String sessionId = request.getParameter("session"); - String zipFileName = sessionId + ".zip"; - File userdir = new File(Conf.getUsersDir(), request.getRemoteUser()); - File sessiondir = new File(userdir, sessionId); - File zipFile = new File(userdir, zipFileName); - ZipUtils.zipDir(zipFile, sessiondir); - request.setAttribute("zipFileName", zipFileName); - request.setAttribute("to", getServletConfig().getInitParameter("mail.to")); - RequestDispatcher rd = request.getRequestDispatcher("emailLog.jsp"); - rd.forward(request, response); - - } - catch (Exception e) { - System.out.println(e.getMessage()); - } - } - - public boolean sendLog(String host, String userId, String password, String to, String from, String subject, - String message, File filename) { - boolean success = true; - System.out.println("host: " + host); - System.out.println("userId: " + userId); - // Fortify Mod: commented out clear text password. - // System.out.println("password: " + password); - System.out.println("to: " + to); - System.out.println("from: " + from); - System.out.println("subject: " + subject); - System.out.println("message: " + message); - System.out.println("filename: " + filename.getName()); - System.out.println("filename: " + filename.getAbsolutePath()); - - // create some properties and get the default Session - Properties props = System.getProperties(); - props.put("mail.smtp.host", host); - props.put("mail.smtp.auth", "true"); - - Session session = Session.getInstance(props, null); - session.setDebug(true); - - try { - // create a message - MimeMessage msg = new MimeMessage(session); - msg.setFrom(new InternetAddress(from)); - InternetAddress[] address = { new InternetAddress(to) }; - msg.setRecipients(Message.RecipientType.TO, address); - msg.setSubject(subject); - - // create and fill the first message part - MimeBodyPart mbp1 = new MimeBodyPart(); - mbp1.setText(message); - - // create the second message part - MimeBodyPart mbp2 = new MimeBodyPart(); - - // attach the file to the message - FileDataSource fds = new FileDataSource(filename); - mbp2.setDataHandler(new DataHandler(fds)); - mbp2.setFileName(fds.getName()); - - // create the Multipart and add its parts to it - Multipart mp = new MimeMultipart(); - mp.addBodyPart(mbp1); - mp.addBodyPart(mbp2); - - // add the Multipart to the message - msg.setContent(mp); - - // set the Date: header - msg.setSentDate(new Date()); - - // connect to the transport - Transport trans = session.getTransport("smtp"); - trans.connect(host, userId, password); - - // send the message - trans.sendMessage(msg, msg.getAllRecipients()); - - // smtphost - trans.close(); - - } - catch (MessagingException mex) { - success = false; - mex.printStackTrace(); - Exception ex = null; - if ((ex = mex.getNextException()) != null) { - ex.printStackTrace(); - } - } - return success; - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ************************************************************************** + * + * Contributor(s): + * C. Heazel (WiSC): Added Fortify adjudication changes + * + *************************************************************************** + */ + +package com.occamlab.te.web; + +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.util.Date; +import java.util.Properties; + +import javax.activation.DataHandler; +import javax.activation.FileDataSource; +import javax.mail.Message; +import javax.mail.MessagingException; +import javax.mail.Multipart; +import javax.mail.Session; +import javax.mail.Transport; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import com.occamlab.te.config.Config; +import com.occamlab.te.util.ZipUtils; + +/** + * Servlet implementation class for Servlet: EmailLogServlet + * + */ +public class EmailLogServlet extends jakarta.servlet.http.HttpServlet implements jakarta.servlet.Servlet { + + Config Conf; + + public void init() throws ServletException { + Conf = new Config(); + } + + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException { + try { + File userdir = new File(Conf.getUsersDir(), request.getParameter("userId")); + File zipFile = new File(userdir, request.getParameter("zipFileName")); + + if (sendLog(getServletConfig().getInitParameter("mail.smtp.host"), + getServletConfig().getInitParameter("mail.smtp.userid"), + getServletConfig().getInitParameter("mail.smtp.passwd"), request.getParameter("to"), + request.getParameter("from"), request.getParameter("subject"), request.getParameter("message"), + zipFile)) { + request.setAttribute("emailStatus", "Email sent Succesfully"); + } + else { + request.setAttribute("emailStatus", "Email failed"); + } + + RequestDispatcher rd = request.getRequestDispatcher("emailSent.jsp"); + rd.forward(request, response); + } + catch (Exception e) { + System.out.println(e.getMessage()); + } + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { + try { + String sessionId = request.getParameter("session"); + String zipFileName = sessionId + ".zip"; + File userdir = new File(Conf.getUsersDir(), request.getRemoteUser()); + File sessiondir = new File(userdir, sessionId); + File zipFile = new File(userdir, zipFileName); + ZipUtils.zipDir(zipFile, sessiondir); + request.setAttribute("zipFileName", zipFileName); + request.setAttribute("to", getServletConfig().getInitParameter("mail.to")); + RequestDispatcher rd = request.getRequestDispatcher("emailLog.jsp"); + rd.forward(request, response); + + } + catch (Exception e) { + System.out.println(e.getMessage()); + } + } + + public boolean sendLog(String host, String userId, String password, String to, String from, String subject, + String message, File filename) { + boolean success = true; + System.out.println("host: " + host); + System.out.println("userId: " + userId); + // Fortify Mod: commented out clear text password. + // System.out.println("password: " + password); + System.out.println("to: " + to); + System.out.println("from: " + from); + System.out.println("subject: " + subject); + System.out.println("message: " + message); + System.out.println("filename: " + filename.getName()); + System.out.println("filename: " + filename.getAbsolutePath()); + + // create some properties and get the default Session + Properties props = System.getProperties(); + props.put("mail.smtp.host", host); + props.put("mail.smtp.auth", "true"); + + Session session = Session.getInstance(props, null); + session.setDebug(true); + + try { + // create a message + MimeMessage msg = new MimeMessage(session); + msg.setFrom(new InternetAddress(from)); + InternetAddress[] address = { new InternetAddress(to) }; + msg.setRecipients(Message.RecipientType.TO, address); + msg.setSubject(subject); + + // create and fill the first message part + MimeBodyPart mbp1 = new MimeBodyPart(); + mbp1.setText(message); + + // create the second message part + MimeBodyPart mbp2 = new MimeBodyPart(); + + // attach the file to the message + FileDataSource fds = new FileDataSource(filename); + mbp2.setDataHandler(new DataHandler(fds)); + mbp2.setFileName(fds.getName()); + + // create the Multipart and add its parts to it + Multipart mp = new MimeMultipart(); + mp.addBodyPart(mbp1); + mp.addBodyPart(mbp2); + + // add the Multipart to the message + msg.setContent(mp); + + // set the Date: header + msg.setSentDate(new Date()); + + // connect to the transport + Transport trans = session.getTransport("smtp"); + trans.connect(host, userId, password); + + // send the message + trans.sendMessage(msg, msg.getAllRecipients()); + + // smtphost + trans.close(); + + } + catch (MessagingException mex) { + success = false; + mex.printStackTrace(); + Exception ex = null; + if ((ex = mex.getNextException()) != null) { + ex.printStackTrace(); + } + } + return success; + } + +} diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/HttpURLConnectionCopy.java b/teamengine-web/src/main/java/com/occamlab/te/web/HttpURLConnectionCopy.java index c625f03dc..ffde8497a 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/HttpURLConnectionCopy.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/HttpURLConnectionCopy.java @@ -1,295 +1,315 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.occamlab.te.web; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.ProtocolException; -import java.net.URL; -import java.security.Permission; -import java.util.List; -import java.util.Map; - -public class HttpURLConnectionCopy extends HttpURLConnection { - - HttpURLConnection uc = null; - - public HttpURLConnectionCopy(HttpURLConnection uc) { - super(null); - this.uc = uc; - } - - @Override - public InputStream getErrorStream() { - return uc.getErrorStream(); - } - - @Override - public String getHeaderField(int n) { - return uc.getHeaderField(n); - } - - @Override - public long getHeaderFieldDate(String name, long Default) { - return uc.getHeaderFieldDate(name, Default); - } - - @Override - public String getHeaderFieldKey(int n) { - return uc.getHeaderFieldKey(n); - } - - @Override - public boolean getInstanceFollowRedirects() { - return uc.getInstanceFollowRedirects(); - } - - @Override - public Permission getPermission() throws IOException { - return uc.getPermission(); - } - - @Override - public String getRequestMethod() { - return uc.getRequestMethod(); - } - - @Override - public int getResponseCode() throws IOException { - return uc.getResponseCode(); - } - - @Override - public String getResponseMessage() throws IOException { - return uc.getResponseMessage(); - } - - @Override - public void setChunkedStreamingMode(int chunklen) { - uc.setChunkedStreamingMode(chunklen); - } - - @Override - public void setFixedLengthStreamingMode(int contentLength) { - uc.setFixedLengthStreamingMode(contentLength); - } - - @Override - public void setInstanceFollowRedirects(boolean followRedirects) { - uc.setInstanceFollowRedirects(followRedirects); - } - - @Override - public void setRequestMethod(String method) throws ProtocolException { - uc.setRequestMethod(method); - } - - @Override - public void addRequestProperty(String key, String value) { - uc.addRequestProperty(key, value); - } - - @Override - public boolean getAllowUserInteraction() { - return uc.getAllowUserInteraction(); - } - - @Override - public int getConnectTimeout() { - return uc.getConnectTimeout(); - } - - @Override - public Object getContent() throws IOException { - return uc.getContent(); - } - - @Override - public Object getContent(@SuppressWarnings("rawtypes") Class[] classes) throws IOException { - return uc.getContent(classes); - } - - @Override - public String getContentEncoding() { - return uc.getContentEncoding(); - } - - @Override - public int getContentLength() { - return uc.getContentLength(); - } - - @Override - public String getContentType() { - return uc.getContentType(); - } - - @Override - public long getDate() { - return uc.getDate(); - } - - @Override - public boolean getDefaultUseCaches() { - return uc.getDefaultUseCaches(); - } - - @Override - public boolean getDoInput() { - return uc.getDoInput(); - } - - @Override - public boolean getDoOutput() { - return uc.getDoOutput(); - } - - @Override - public long getExpiration() { - return uc.getExpiration(); - } - - @Override - public String getHeaderField(String name) { - return uc.getHeaderField(name); - } - - @Override - public int getHeaderFieldInt(String name, int Default) { - return uc.getHeaderFieldInt(name, Default); - } - - @Override - public Map> getHeaderFields() { - return uc.getHeaderFields(); - } - - @Override - public long getIfModifiedSince() { - return uc.getIfModifiedSince(); - } - - @Override - public InputStream getInputStream() throws IOException { - return uc.getInputStream(); - } - - @Override - public long getLastModified() { - return uc.getLastModified(); - } - - @Override - public OutputStream getOutputStream() throws IOException { - return uc.getOutputStream(); - - } - - @Override - public int getReadTimeout() { - return uc.getReadTimeout(); - } - - @Override - public Map> getRequestProperties() { - return uc.getRequestProperties(); - } - - @Override - public String getRequestProperty(String key) { - return uc.getRequestProperty(key); - } - - @Override - public URL getURL() { - return uc.getURL(); - } - - @Override - public boolean getUseCaches() { - return uc.getUseCaches(); - } - - @Override - public void setAllowUserInteraction(boolean allowuserinteraction) { - uc.setAllowUserInteraction(allowuserinteraction); - } - - @Override - public void setConnectTimeout(int timeout) { - uc.setConnectTimeout(timeout); - } - - @Override - public void setDefaultUseCaches(boolean defaultusecaches) { - uc.setDefaultUseCaches(defaultusecaches); - } - - @Override - public void setDoInput(boolean doinput) { - uc.setDoInput(doinput); - } - - @Override - public void setDoOutput(boolean dooutput) { - uc.setDoOutput(dooutput); - } - - @Override - public void setIfModifiedSince(long ifmodifiedsince) { - uc.setIfModifiedSince(ifmodifiedsince); - } - - @Override - public void setReadTimeout(int timeout) { - uc.setReadTimeout(timeout); - } - - @Override - public void setRequestProperty(String key, String value) { - uc.setRequestProperty(key, value); - } - - @Override - public void setUseCaches(boolean usecaches) { - uc.setUseCaches(usecaches); - } - - @Override - public String toString() { - return uc.toString(); - } - - @Override - public boolean equals(Object obj) { - return uc.equals(obj); - } - - @Override - public int hashCode() { - return uc.hashCode(); - } - - @Override - public void disconnect() { - uc.disconnect(); - } - - @Override - public boolean usingProxy() { - return uc.usingProxy(); - } - - @Override - public void connect() throws IOException { - uc.connect(); - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.occamlab.te.web; + +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.ProtocolException; +import java.net.URL; +import java.security.Permission; +import java.util.List; +import java.util.Map; + +public class HttpURLConnectionCopy extends HttpURLConnection { + + HttpURLConnection uc = null; + + public HttpURLConnectionCopy(HttpURLConnection uc) { + super(null); + this.uc = uc; + } + + @Override + public InputStream getErrorStream() { + return uc.getErrorStream(); + } + + @Override + public String getHeaderField(int n) { + return uc.getHeaderField(n); + } + + @Override + public long getHeaderFieldDate(String name, long Default) { + return uc.getHeaderFieldDate(name, Default); + } + + @Override + public String getHeaderFieldKey(int n) { + return uc.getHeaderFieldKey(n); + } + + @Override + public boolean getInstanceFollowRedirects() { + return uc.getInstanceFollowRedirects(); + } + + @Override + public Permission getPermission() throws IOException { + return uc.getPermission(); + } + + @Override + public String getRequestMethod() { + return uc.getRequestMethod(); + } + + @Override + public int getResponseCode() throws IOException { + return uc.getResponseCode(); + } + + @Override + public String getResponseMessage() throws IOException { + return uc.getResponseMessage(); + } + + @Override + public void setChunkedStreamingMode(int chunklen) { + uc.setChunkedStreamingMode(chunklen); + } + + @Override + public void setFixedLengthStreamingMode(int contentLength) { + uc.setFixedLengthStreamingMode(contentLength); + } + + @Override + public void setInstanceFollowRedirects(boolean followRedirects) { + uc.setInstanceFollowRedirects(followRedirects); + } + + @Override + public void setRequestMethod(String method) throws ProtocolException { + uc.setRequestMethod(method); + } + + @Override + public void addRequestProperty(String key, String value) { + uc.addRequestProperty(key, value); + } + + @Override + public boolean getAllowUserInteraction() { + return uc.getAllowUserInteraction(); + } + + @Override + public int getConnectTimeout() { + return uc.getConnectTimeout(); + } + + @Override + public Object getContent() throws IOException { + return uc.getContent(); + } + + @Override + public Object getContent(@SuppressWarnings("rawtypes") Class[] classes) throws IOException { + return uc.getContent(classes); + } + + @Override + public String getContentEncoding() { + return uc.getContentEncoding(); + } + + @Override + public int getContentLength() { + return uc.getContentLength(); + } + + @Override + public String getContentType() { + return uc.getContentType(); + } + + @Override + public long getDate() { + return uc.getDate(); + } + + @Override + public boolean getDefaultUseCaches() { + return uc.getDefaultUseCaches(); + } + + @Override + public boolean getDoInput() { + return uc.getDoInput(); + } + + @Override + public boolean getDoOutput() { + return uc.getDoOutput(); + } + + @Override + public long getExpiration() { + return uc.getExpiration(); + } + + @Override + public String getHeaderField(String name) { + return uc.getHeaderField(name); + } + + @Override + public int getHeaderFieldInt(String name, int Default) { + return uc.getHeaderFieldInt(name, Default); + } + + @Override + public Map> getHeaderFields() { + return uc.getHeaderFields(); + } + + @Override + public long getIfModifiedSince() { + return uc.getIfModifiedSince(); + } + + @Override + public InputStream getInputStream() throws IOException { + return uc.getInputStream(); + } + + @Override + public long getLastModified() { + return uc.getLastModified(); + } + + @Override + public OutputStream getOutputStream() throws IOException { + return uc.getOutputStream(); + + } + + @Override + public int getReadTimeout() { + return uc.getReadTimeout(); + } + + @Override + public Map> getRequestProperties() { + return uc.getRequestProperties(); + } + + @Override + public String getRequestProperty(String key) { + return uc.getRequestProperty(key); + } + + @Override + public URL getURL() { + return uc.getURL(); + } + + @Override + public boolean getUseCaches() { + return uc.getUseCaches(); + } + + @Override + public void setAllowUserInteraction(boolean allowuserinteraction) { + uc.setAllowUserInteraction(allowuserinteraction); + } + + @Override + public void setConnectTimeout(int timeout) { + uc.setConnectTimeout(timeout); + } + + @Override + public void setDefaultUseCaches(boolean defaultusecaches) { + uc.setDefaultUseCaches(defaultusecaches); + } + + @Override + public void setDoInput(boolean doinput) { + uc.setDoInput(doinput); + } + + @Override + public void setDoOutput(boolean dooutput) { + uc.setDoOutput(dooutput); + } + + @Override + public void setIfModifiedSince(long ifmodifiedsince) { + uc.setIfModifiedSince(ifmodifiedsince); + } + + @Override + public void setReadTimeout(int timeout) { + uc.setReadTimeout(timeout); + } + + @Override + public void setRequestProperty(String key, String value) { + uc.setRequestProperty(key, value); + } + + @Override + public void setUseCaches(boolean usecaches) { + uc.setUseCaches(usecaches); + } + + @Override + public String toString() { + return uc.toString(); + } + + @Override + public boolean equals(Object obj) { + return uc.equals(obj); + } + + @Override + public int hashCode() { + return uc.hashCode(); + } + + @Override + public void disconnect() { + uc.disconnect(); + } + + @Override + public boolean usingProxy() { + return uc.usingProxy(); + } + + @Override + public void connect() throws IOException { + uc.connect(); + } + +} diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/LogoutServlet.java b/teamengine-web/src/main/java/com/occamlab/te/web/LogoutServlet.java index 85c34b510..957748331 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/LogoutServlet.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/LogoutServlet.java @@ -1,36 +1,56 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.occamlab.te.web; - -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -/** - * Handles (GET) requests to log out and terminate a test session. - * - */ -public class LogoutServlet extends HttpServlet { - - private static final long serialVersionUID = 2713575227560756943L; - - public void init() throws ServletException { - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { - try { - request.getSession().invalidate(); - response.sendRedirect(request.getContextPath()); - } - catch (Exception e) { - throw new ServletException(e); - } - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.occamlab.te.web; + +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * Handles (GET) requests to log out and terminate a test session. + * + */ +public class LogoutServlet extends HttpServlet { + + private static final long serialVersionUID = 2713575227560756943L; + + public void init() throws ServletException { + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { + try { + request.getSession().invalidate(); + response.sendRedirect(request.getContextPath()); + } + catch (Exception e) { + throw new ServletException(e); + } + } + +} diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/MonitorCall.java b/teamengine-web/src/main/java/com/occamlab/te/web/MonitorCall.java index 4b2b522dc..ac2817394 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/MonitorCall.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/MonitorCall.java @@ -1,169 +1,189 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.occamlab.te.web; - -import java.io.File; - -import org.w3c.dom.Element; - -import com.occamlab.te.TECore; -import com.occamlab.te.util.DomUtils; - -import net.sf.saxon.expr.XPathContext; - -/** - * A monitor that examines the content of a service request. It may be configured to - * modify the response before forwarding it to the requester. A monitor may also perform - * simple coverage reporting by keeping track of which service capabilities were invoked - * by the client (for GET requests only). - * - */ -public class MonitorCall { - - XPathContext context; - - String url; - - String localName; - - String namespaceURI; - - Element params; - - String callId; - - Element parserConfig; - - boolean modifiesResponse; - - TECore core; - - String testPath; - - private CoverageMonitor coverageMonitor; - - MonitorCall(String url) { - setUrl(url); - } - - public XPathContext getContext() { - return context; - } - - public void setContext(XPathContext context) { - this.context = context; - } - - public String getCallId() { - return callId; - } - - public void setCallId(String callId) { - this.callId = callId; - } - - public String getLocalName() { - return localName; - } - - public void setLocalName(String localName) { - this.localName = localName; - } - - public String getNamespaceURI() { - return namespaceURI; - } - - public void setNamespaceURI(String namespaceURI) { - this.namespaceURI = namespaceURI; - } - - public Element getParams() { - return params; - } - - public void setParams(Element params) { - this.params = params; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public Element getParserInstruction() { - return parserConfig; - } - - public void setParserInstruction(Element parserInstruction) { - this.parserConfig = parserInstruction; - } - - public boolean getModifiesResponse() { - return modifiesResponse; - } - - public void setModifiesResponse(boolean modifiesResponse) { - this.modifiesResponse = modifiesResponse; - } - - public TECore getCore() { - return core; - } - - public void setCore(TECore core) { - this.core = core; - this.testPath = core.getTestPath(); - if (null == this.namespaceURI) { - throw new RuntimeException("Cannot create coverage monitor: namespaceURI is null."); - } - this.coverageMonitor = new CoverageMonitor(this.namespaceURI); - this.coverageMonitor.setTestSessionDir(new File(core.getLogDir(), core.getTestPath())); - } - - public String getTestPath() { - return testPath; - } - - /** - * Determines which server capabilities are invoked by this query. - * @param query The (decoded) query string extracted from the request URI. - */ - public void checkCoverage(String query) { - this.coverageMonitor.inspectQuery(query); - } - - /** - * Ensures that any resources used by this monitor are cleaned up in an orderly - * manner. - */ - public void destroy() { - if (null != this.coverageMonitor) { - this.coverageMonitor.writeCoverageResults(); - } - } - - @Override - public String toString() { - StringBuilder str = new StringBuilder("MonitorCall {\n"); - str.append(" url: ").append(url).append(",\n"); - str.append(" localName: ").append(localName).append(",\n"); - str.append(" NamespaceURI: ").append(namespaceURI).append(",\n"); - str.append(" callId: ").append(callId).append(",\n"); - str.append(" modifiesResponse: ").append(modifiesResponse).append(",\n"); - str.append(" testPath: ").append(testPath).append(",\n"); - str.append(" params: ").append(DomUtils.serializeNode(params)).append(",\n"); - str.append(" parserConfig: ").append(DomUtils.serializeNode(parserConfig)).append(",\n"); - str.append("}"); - return str.toString(); - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.occamlab.te.web; + +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; + +import org.w3c.dom.Element; + +import com.occamlab.te.TECore; +import com.occamlab.te.util.DomUtils; + +import net.sf.saxon.expr.XPathContext; + +/** + * A monitor that examines the content of a service request. It may be configured to + * modify the response before forwarding it to the requester. A monitor may also perform + * simple coverage reporting by keeping track of which service capabilities were invoked + * by the client (for GET requests only). + * + */ +public class MonitorCall { + + XPathContext context; + + String url; + + String localName; + + String namespaceURI; + + Element params; + + String callId; + + Element parserConfig; + + boolean modifiesResponse; + + TECore core; + + String testPath; + + private CoverageMonitor coverageMonitor; + + MonitorCall(String url) { + setUrl(url); + } + + public XPathContext getContext() { + return context; + } + + public void setContext(XPathContext context) { + this.context = context; + } + + public String getCallId() { + return callId; + } + + public void setCallId(String callId) { + this.callId = callId; + } + + public String getLocalName() { + return localName; + } + + public void setLocalName(String localName) { + this.localName = localName; + } + + public String getNamespaceURI() { + return namespaceURI; + } + + public void setNamespaceURI(String namespaceURI) { + this.namespaceURI = namespaceURI; + } + + public Element getParams() { + return params; + } + + public void setParams(Element params) { + this.params = params; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Element getParserInstruction() { + return parserConfig; + } + + public void setParserInstruction(Element parserInstruction) { + this.parserConfig = parserInstruction; + } + + public boolean getModifiesResponse() { + return modifiesResponse; + } + + public void setModifiesResponse(boolean modifiesResponse) { + this.modifiesResponse = modifiesResponse; + } + + public TECore getCore() { + return core; + } + + public void setCore(TECore core) { + this.core = core; + this.testPath = core.getTestPath(); + if (null == this.namespaceURI) { + throw new RuntimeException("Cannot create coverage monitor: namespaceURI is null."); + } + this.coverageMonitor = new CoverageMonitor(this.namespaceURI); + this.coverageMonitor.setTestSessionDir(new File(core.getLogDir(), core.getTestPath())); + } + + public String getTestPath() { + return testPath; + } + + /** + * Determines which server capabilities are invoked by this query. + * @param query The (decoded) query string extracted from the request URI. + */ + public void checkCoverage(String query) { + this.coverageMonitor.inspectQuery(query); + } + + /** + * Ensures that any resources used by this monitor are cleaned up in an orderly + * manner. + */ + public void destroy() { + if (null != this.coverageMonitor) { + this.coverageMonitor.writeCoverageResults(); + } + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder("MonitorCall {\n"); + str.append(" url: ").append(url).append(",\n"); + str.append(" localName: ").append(localName).append(",\n"); + str.append(" NamespaceURI: ").append(namespaceURI).append(",\n"); + str.append(" callId: ").append(callId).append(",\n"); + str.append(" modifiesResponse: ").append(modifiesResponse).append(",\n"); + str.append(" testPath: ").append(testPath).append(",\n"); + str.append(" params: ").append(DomUtils.serializeNode(params)).append(",\n"); + str.append(" parserConfig: ").append(DomUtils.serializeNode(parserConfig)).append(",\n"); + str.append("}"); + return str.toString(); + } + +} diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/MonitorServlet.java b/teamengine-web/src/main/java/com/occamlab/te/web/MonitorServlet.java index 9395845ac..7d7ecd5e6 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/MonitorServlet.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/MonitorServlet.java @@ -1,372 +1,392 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * ************************************************************************** - * - * Contributor(s): - * C. Heazel (WiSC): Added Fortify adjudication changes - * - *************************************************************************** - */ -package com.occamlab.te.web; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.logging.Level; -import java.util.logging.Logger; - -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMResult; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; -import javax.xml.XMLConstants; // Addition for Fortify modifications - -import net.sf.saxon.dom.NodeOverNodeInfo; -import net.sf.saxon.expr.XPathContext; -import net.sf.saxon.om.NodeInfo; -import net.sf.saxon.s9api.XdmNode; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -import com.occamlab.te.TECore; -import com.occamlab.te.util.DomUtils; - -/** - * A servlet that intercepts a client request and validates it with a registered - * MonitorCall object. Each MonitorCall object is associated with a service endpoint. - * - */ -@SuppressWarnings("serial") -public class MonitorServlet extends HttpServlet { - - private static final Logger LOGR = Logger.getLogger(MonitorServlet.class.getPackage().getName()); - - public static final String CTL_NS = "http://www.occamlab.com/ctl"; - - static DocumentBuilder DB; - static Transformer identityTransformer; - - static String baseServletURL; - static String servletName; - static int monitorCallSeq = 0; - static int monitorUrlSeq = 0; - static Map monitors = new HashMap<>(); - - static public String allocateMonitorUrl(String url) { - String monitorUrl = baseServletURL + "/" + servletName + "/" + monitorUrlSeq; - monitorUrlSeq++; - MonitorCall mc = new MonitorCall(url); - monitors.put(monitorUrl, mc); - return monitorUrl; - } - - // Monitor without parser that doesn't trigger a test - static public String createMonitor(String monitorUrl, TECore core) { - return createMonitor(monitorUrl, null, "", core); - } - - // Monitor that doesn't trigger a test - static public String createMonitor(String monitorUrl, Node parserInstruction, String modifiesResponse, - TECore core) { - MonitorCall mc = monitors.get(monitorUrl); - mc.setCore(core); - if (parserInstruction != null) { - mc.setParserInstruction(DomUtils.getElement(parserInstruction)); - mc.setModifiesResponse(Boolean.parseBoolean(modifiesResponse)); - } - LOGR.log(Level.CONFIG, "Configured monitor without test:\n {0}", mc); - return ""; - } - - // Monitor without parser that triggers a test - static public String createMonitor(XPathContext context, String url, String localName, String namespaceURI, - NodeInfo params, String callId, TECore core) throws Exception { - return createMonitor(context, url, localName, namespaceURI, params, null, "", callId, core); - } - - // Monitor that triggers a test - static public String createMonitor(XPathContext context, String monitorUrl, String localName, String namespaceURI, - NodeInfo params, NodeInfo parserInstruction, String modifiesResponse, String callId, TECore core) - throws Exception { - MonitorCall mc = monitors.get(monitorUrl); - mc.setContext(context); - mc.setLocalName(localName); - mc.setNamespaceURI(namespaceURI); - mc.setCore(core); - if (params != null) { - Node node = (Node) NodeOverNodeInfo.wrap(params); - if (node.getNodeType() == Node.DOCUMENT_NODE) { - mc.setParams(((Document) node).getDocumentElement()); - } - else { - mc.setParams((Element) node); - } - } - if (parserInstruction != null) { - Node node = (Node) NodeOverNodeInfo.wrap(parserInstruction); - if (node.getNodeType() == Node.DOCUMENT_NODE) { - mc.setParserInstruction(((Document) node).getDocumentElement()); - } - else { - mc.setParserInstruction((Element) node); - } - mc.setModifiesResponse(Boolean.parseBoolean(modifiesResponse)); - } - mc.setCallId(callId); - LOGR.log(Level.CONFIG, "Configured monitor with test:\n {0}", mc); - return ""; - } - - public static String destroyMonitors(TECore core) { - ArrayList keysToDelete = new ArrayList<>(); - for (Entry entry : monitors.entrySet()) { - MonitorCall mc = entry.getValue(); - if (mc.getCore() == core) { - if (mc.getTestPath().equals(core.getTestPath())) { - keysToDelete.add(entry.getKey()); - mc.destroy(); - } - } - } - for (String key : keysToDelete) { - monitors.remove(key); - } - return ""; - } - - public void process(HttpServletRequest request, HttpServletResponse response, boolean post) - throws ServletException { - try { - String uri = request.getRequestURL().toString(); - MonitorCall mc = monitors.get(uri); - if (mc == null) { - response.sendError(410, "This URL is no longer valid"); - return; - } - if (null == request.getContentType()) { - // check GET requests only - String query = null; - query = URLDecoder.decode(request.getQueryString(), StandardCharsets.UTF_8); - mc.checkCoverage(query); - } - TECore core = mc.getCore(); - String url = mc.getUrl(); - String queryString = request.getQueryString(); - if (queryString != null) { - if (url.contains("?")) { - url += queryString; - } - else { - url += "?" + queryString; - } - } - - LOGR.log(Level.FINE, "Opening connection to " + url); - HttpURLConnection huc = (HttpURLConnection) (new URL(url).openConnection()); - CachedHttpURLConnection uc = new CachedHttpURLConnection(huc); - - String method = request.getMethod(); - uc.setRequestMethod(method); - uc.setDoInput(true); - uc.setDoOutput(post); - byte[] data = null; - if (post) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - copy_stream(request.getInputStream(), baos); - data = baos.toByteArray(); - ByteArrayInputStream bais = new ByteArrayInputStream(data); - copy_stream(bais, uc.getOutputStream()); - } - - Document doc = DB.newDocument(); - Element eRequest = encodeRequest(request, doc, data); - Element parserInstruction = mc.getParserInstruction(); - Element eResponse = core.parse(uc, parserInstruction); - - Map> responseHeaders = uc.getHeaderFields(); - for (Entry> entry : responseHeaders.entrySet()) { - String key = entry.getKey(); - if (key != null) { - if (key.isEmpty()) { - // do nothing - } - else if (key.equalsIgnoreCase("Transfer-Encoding")) { - // do nothing - } - else { - for (String value : entry.getValue()) { - response.setHeader(key, value); - } - } - } - } - - // Support of CORS: Allow requests from all domains. - response.setHeader("Access-Control-Allow-Origin", "*"); - - if (mc.getModifiesResponse()) { - LOGR.log(Level.FINE, DomUtils.serializeNode(eResponse)); - Element content = DomUtils.getElementByTagName(eResponse, "content"); - Element root = DomUtils.getChildElement(content); - identityTransformer.transform(new DOMSource(root), new StreamResult(response.getOutputStream())); - } - else { - response.setContentLength(uc.getLength()); - copy_stream(uc.getInputStream(), response.getOutputStream()); - } - - if (mc.getCallId() != null) { - identityTransformer.transform(new DOMSource(mc.getParams()), new DOMResult(doc)); - Element eParams = DomUtils.getElementByTagName(doc, "params"); - Element eReqParam = doc.createElement("param"); - eReqParam.setAttribute("local-name", "request"); - eReqParam.setAttribute("namespace-uri", ""); - eReqParam.setAttribute("prefix", ""); - eReqParam.setAttribute("type", "node()"); - Element eReqValue = doc.createElement("value"); - eReqValue.appendChild(eRequest); - eReqParam.appendChild(eReqValue); - eParams.appendChild(eReqParam); - Element eRespParam = doc.createElement("param"); - eRespParam.setAttribute("local-name", "response"); - eRespParam.setAttribute("namespace-uri", ""); - eRespParam.setAttribute("prefix", ""); - eRespParam.setAttribute("type", "node()"); - Element eRespValue = doc.createElement("value"); - identityTransformer.transform(new DOMSource(eResponse), new DOMResult(eRespValue)); - eRespParam.appendChild(eRespValue); - eParams.appendChild(eRespParam); - net.sf.saxon.s9api.DocumentBuilder builder = core.getEngine().getBuilder(); - XdmNode paramsNode = builder.build(new DOMSource(doc)); - monitorCallSeq++; - String callId = mc.getCallId() + "_" + monitorCallSeq; - core.callTest(mc.getContext(), mc.getLocalName(), mc.getNamespaceURI(), paramsNode.getUnderlyingNode(), - callId); - } - } - catch (Throwable t) { - throw new ServletException(t); - } - } - - public void init() throws ServletException { - try { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - // Fortify Mod: prevent external entity injection - dbf.setExpandEntityReferences(false); - DB = dbf.newDocumentBuilder(); - // Fortify Mod: prevent external entity injection - TransformerFactory tf = TransformerFactory.newInstance(); - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - identityTransformer = tf.newTransformer(); - // identityTransformer = TransformerFactory.newInstance().newTransformer(); - // End Fortify Mod - - servletName = this.getServletName(); - } - catch (Exception e) { - throw new ServletException(e); - } - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { - process(request, response, false); - } - - public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException { - process(request, response, true); - } - - @SuppressWarnings("unchecked") - Element encodeRequest(HttpServletRequest request, Document doc, byte[] data) throws Exception { - Element eRequest = doc.createElementNS(CTL_NS, "ctl:request"); - Element eURL = doc.createElementNS(CTL_NS, "ctl:url"); - eURL.setTextContent(request.getRequestURL().toString()); - eRequest.appendChild(eURL); - Element eMethod = doc.createElementNS(CTL_NS, "ctl:method"); - eMethod.setTextContent(request.getMethod()); - eRequest.appendChild(eMethod); - Enumeration requestHeaders = request.getHeaderNames(); - while (requestHeaders.hasMoreElements()) { - String key = (String) requestHeaders.nextElement(); - Element eHeader = doc.createElementNS(CTL_NS, "ctl:header"); - eHeader.setAttribute("name", key); - eHeader.setTextContent(request.getHeader(key)); - eRequest.appendChild(eHeader); - } - Enumeration params = request.getParameterNames(); - while (params.hasMoreElements()) { - String key = (String) params.nextElement(); - Element eParam = doc.createElementNS(CTL_NS, "ctl:param"); - eParam.setAttribute("name", key); - eParam.setTextContent(request.getParameter(key)); - eRequest.appendChild(eParam); - } - if (data != null) { - String mime = request.getContentType(); - if (mime.indexOf("text/xml") == 0 || mime.indexOf("application/xml") == 0) { - ByteArrayInputStream bais = new ByteArrayInputStream(data); - Element eBody = doc.createElementNS(CTL_NS, "ctl:body"); - // Fortify Mod: prevent external entity injection - TransformerFactory tf = TransformerFactory.newInstance(); - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - Transformer t = tf.newTransformer(); - // Transformer t = TransformerFactory.newInstance().newTransformer(); - // End Fortify Mod - t.transform(new StreamSource(bais), new DOMResult(eBody)); - eRequest.appendChild(eBody); - } - else if (mime.indexOf("text/") == 0) { - Element eBody = doc.createElementNS(CTL_NS, "ctl:body"); - eBody.appendChild(doc.createCDATASection(data.toString())); - eRequest.appendChild(eBody); - } - } - return eRequest; - } - - static void copy_stream(InputStream in, OutputStream out) throws IOException { - int i = in.read(); - while (i >= 0) { - out.write(i); - i = in.read(); - } - } - - public static String getBaseServletURL() { - return baseServletURL; - } - - public static void setBaseServletURL(String baseServletURL) { - MonitorServlet.baseServletURL = baseServletURL; - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ************************************************************************** + * + * Contributor(s): + * C. Heazel (WiSC): Added Fortify adjudication changes + * + *************************************************************************** + */ +package com.occamlab.te.web; + +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import javax.xml.XMLConstants; // Addition for Fortify modifications + +import net.sf.saxon.dom.NodeOverNodeInfo; +import net.sf.saxon.expr.XPathContext; +import net.sf.saxon.om.NodeInfo; +import net.sf.saxon.s9api.XdmNode; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import com.occamlab.te.TECore; +import com.occamlab.te.util.DomUtils; + +/** + * A servlet that intercepts a client request and validates it with a registered + * MonitorCall object. Each MonitorCall object is associated with a service endpoint. + * + */ +@SuppressWarnings("serial") +public class MonitorServlet extends HttpServlet { + + private static final Logger LOGR = Logger.getLogger(MonitorServlet.class.getPackage().getName()); + + public static final String CTL_NS = "http://www.occamlab.com/ctl"; + + static DocumentBuilder DB; + static Transformer identityTransformer; + + static String baseServletURL; + static String servletName; + static int monitorCallSeq = 0; + static int monitorUrlSeq = 0; + static Map monitors = new HashMap<>(); + + static public String allocateMonitorUrl(String url) { + String monitorUrl = baseServletURL + "/" + servletName + "/" + monitorUrlSeq; + monitorUrlSeq++; + MonitorCall mc = new MonitorCall(url); + monitors.put(monitorUrl, mc); + return monitorUrl; + } + + // Monitor without parser that doesn't trigger a test + static public String createMonitor(String monitorUrl, TECore core) { + return createMonitor(monitorUrl, null, "", core); + } + + // Monitor that doesn't trigger a test + static public String createMonitor(String monitorUrl, Node parserInstruction, String modifiesResponse, + TECore core) { + MonitorCall mc = monitors.get(monitorUrl); + mc.setCore(core); + if (parserInstruction != null) { + mc.setParserInstruction(DomUtils.getElement(parserInstruction)); + mc.setModifiesResponse(Boolean.parseBoolean(modifiesResponse)); + } + LOGR.log(Level.CONFIG, "Configured monitor without test:\n {0}", mc); + return ""; + } + + // Monitor without parser that triggers a test + static public String createMonitor(XPathContext context, String url, String localName, String namespaceURI, + NodeInfo params, String callId, TECore core) throws Exception { + return createMonitor(context, url, localName, namespaceURI, params, null, "", callId, core); + } + + // Monitor that triggers a test + static public String createMonitor(XPathContext context, String monitorUrl, String localName, String namespaceURI, + NodeInfo params, NodeInfo parserInstruction, String modifiesResponse, String callId, TECore core) + throws Exception { + MonitorCall mc = monitors.get(monitorUrl); + mc.setContext(context); + mc.setLocalName(localName); + mc.setNamespaceURI(namespaceURI); + mc.setCore(core); + if (params != null) { + Node node = (Node) NodeOverNodeInfo.wrap(params); + if (node.getNodeType() == Node.DOCUMENT_NODE) { + mc.setParams(((Document) node).getDocumentElement()); + } + else { + mc.setParams((Element) node); + } + } + if (parserInstruction != null) { + Node node = (Node) NodeOverNodeInfo.wrap(parserInstruction); + if (node.getNodeType() == Node.DOCUMENT_NODE) { + mc.setParserInstruction(((Document) node).getDocumentElement()); + } + else { + mc.setParserInstruction((Element) node); + } + mc.setModifiesResponse(Boolean.parseBoolean(modifiesResponse)); + } + mc.setCallId(callId); + LOGR.log(Level.CONFIG, "Configured monitor with test:\n {0}", mc); + return ""; + } + + public static String destroyMonitors(TECore core) { + ArrayList keysToDelete = new ArrayList<>(); + for (Entry entry : monitors.entrySet()) { + MonitorCall mc = entry.getValue(); + if (mc.getCore() == core) { + if (mc.getTestPath().equals(core.getTestPath())) { + keysToDelete.add(entry.getKey()); + mc.destroy(); + } + } + } + for (String key : keysToDelete) { + monitors.remove(key); + } + return ""; + } + + public void process(HttpServletRequest request, HttpServletResponse response, boolean post) + throws ServletException { + try { + String uri = request.getRequestURL().toString(); + MonitorCall mc = monitors.get(uri); + if (mc == null) { + response.sendError(410, "This URL is no longer valid"); + return; + } + if (null == request.getContentType()) { + // check GET requests only + String query = null; + query = URLDecoder.decode(request.getQueryString(), StandardCharsets.UTF_8); + mc.checkCoverage(query); + } + TECore core = mc.getCore(); + String url = mc.getUrl(); + String queryString = request.getQueryString(); + if (queryString != null) { + if (url.contains("?")) { + url += queryString; + } + else { + url += "?" + queryString; + } + } + + LOGR.log(Level.FINE, "Opening connection to " + url); + HttpURLConnection huc = (HttpURLConnection) (new URL(url).openConnection()); + CachedHttpURLConnection uc = new CachedHttpURLConnection(huc); + + String method = request.getMethod(); + uc.setRequestMethod(method); + uc.setDoInput(true); + uc.setDoOutput(post); + byte[] data = null; + if (post) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + copy_stream(request.getInputStream(), baos); + data = baos.toByteArray(); + ByteArrayInputStream bais = new ByteArrayInputStream(data); + copy_stream(bais, uc.getOutputStream()); + } + + Document doc = DB.newDocument(); + Element eRequest = encodeRequest(request, doc, data); + Element parserInstruction = mc.getParserInstruction(); + Element eResponse = core.parse(uc, parserInstruction); + + Map> responseHeaders = uc.getHeaderFields(); + for (Entry> entry : responseHeaders.entrySet()) { + String key = entry.getKey(); + if (key != null) { + if (key.isEmpty()) { + // do nothing + } + else if (key.equalsIgnoreCase("Transfer-Encoding")) { + // do nothing + } + else { + for (String value : entry.getValue()) { + response.setHeader(key, value); + } + } + } + } + + // Support of CORS: Allow requests from all domains. + response.setHeader("Access-Control-Allow-Origin", "*"); + + if (mc.getModifiesResponse()) { + LOGR.log(Level.FINE, DomUtils.serializeNode(eResponse)); + Element content = DomUtils.getElementByTagName(eResponse, "content"); + Element root = DomUtils.getChildElement(content); + identityTransformer.transform(new DOMSource(root), new StreamResult(response.getOutputStream())); + } + else { + response.setContentLength(uc.getLength()); + copy_stream(uc.getInputStream(), response.getOutputStream()); + } + + if (mc.getCallId() != null) { + identityTransformer.transform(new DOMSource(mc.getParams()), new DOMResult(doc)); + Element eParams = DomUtils.getElementByTagName(doc, "params"); + Element eReqParam = doc.createElement("param"); + eReqParam.setAttribute("local-name", "request"); + eReqParam.setAttribute("namespace-uri", ""); + eReqParam.setAttribute("prefix", ""); + eReqParam.setAttribute("type", "node()"); + Element eReqValue = doc.createElement("value"); + eReqValue.appendChild(eRequest); + eReqParam.appendChild(eReqValue); + eParams.appendChild(eReqParam); + Element eRespParam = doc.createElement("param"); + eRespParam.setAttribute("local-name", "response"); + eRespParam.setAttribute("namespace-uri", ""); + eRespParam.setAttribute("prefix", ""); + eRespParam.setAttribute("type", "node()"); + Element eRespValue = doc.createElement("value"); + identityTransformer.transform(new DOMSource(eResponse), new DOMResult(eRespValue)); + eRespParam.appendChild(eRespValue); + eParams.appendChild(eRespParam); + net.sf.saxon.s9api.DocumentBuilder builder = core.getEngine().getBuilder(); + XdmNode paramsNode = builder.build(new DOMSource(doc)); + monitorCallSeq++; + String callId = mc.getCallId() + "_" + monitorCallSeq; + core.callTest(mc.getContext(), mc.getLocalName(), mc.getNamespaceURI(), paramsNode.getUnderlyingNode(), + callId); + } + } + catch (Throwable t) { + throw new ServletException(t); + } + } + + public void init() throws ServletException { + try { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + // Fortify Mod: prevent external entity injection + dbf.setExpandEntityReferences(false); + DB = dbf.newDocumentBuilder(); + // Fortify Mod: prevent external entity injection + TransformerFactory tf = TransformerFactory.newInstance(); + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + identityTransformer = tf.newTransformer(); + // identityTransformer = TransformerFactory.newInstance().newTransformer(); + // End Fortify Mod + + servletName = this.getServletName(); + } + catch (Exception e) { + throw new ServletException(e); + } + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { + process(request, response, false); + } + + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException { + process(request, response, true); + } + + @SuppressWarnings("unchecked") + Element encodeRequest(HttpServletRequest request, Document doc, byte[] data) throws Exception { + Element eRequest = doc.createElementNS(CTL_NS, "ctl:request"); + Element eURL = doc.createElementNS(CTL_NS, "ctl:url"); + eURL.setTextContent(request.getRequestURL().toString()); + eRequest.appendChild(eURL); + Element eMethod = doc.createElementNS(CTL_NS, "ctl:method"); + eMethod.setTextContent(request.getMethod()); + eRequest.appendChild(eMethod); + Enumeration requestHeaders = request.getHeaderNames(); + while (requestHeaders.hasMoreElements()) { + String key = (String) requestHeaders.nextElement(); + Element eHeader = doc.createElementNS(CTL_NS, "ctl:header"); + eHeader.setAttribute("name", key); + eHeader.setTextContent(request.getHeader(key)); + eRequest.appendChild(eHeader); + } + Enumeration params = request.getParameterNames(); + while (params.hasMoreElements()) { + String key = (String) params.nextElement(); + Element eParam = doc.createElementNS(CTL_NS, "ctl:param"); + eParam.setAttribute("name", key); + eParam.setTextContent(request.getParameter(key)); + eRequest.appendChild(eParam); + } + if (data != null) { + String mime = request.getContentType(); + if (mime.indexOf("text/xml") == 0 || mime.indexOf("application/xml") == 0) { + ByteArrayInputStream bais = new ByteArrayInputStream(data); + Element eBody = doc.createElementNS(CTL_NS, "ctl:body"); + // Fortify Mod: prevent external entity injection + TransformerFactory tf = TransformerFactory.newInstance(); + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + Transformer t = tf.newTransformer(); + // Transformer t = TransformerFactory.newInstance().newTransformer(); + // End Fortify Mod + t.transform(new StreamSource(bais), new DOMResult(eBody)); + eRequest.appendChild(eBody); + } + else if (mime.indexOf("text/") == 0) { + Element eBody = doc.createElementNS(CTL_NS, "ctl:body"); + eBody.appendChild(doc.createCDATASection(data.toString())); + eRequest.appendChild(eBody); + } + } + return eRequest; + } + + static void copy_stream(InputStream in, OutputStream out) throws IOException { + int i = in.read(); + while (i >= 0) { + out.write(i); + i = in.read(); + } + } + + public static String getBaseServletURL() { + return baseServletURL; + } + + public static void setBaseServletURL(String baseServletURL) { + MonitorServlet.baseServletURL = baseServletURL; + } + +} diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/PrettyPrintLogsServlet.java b/teamengine-web/src/main/java/com/occamlab/te/web/PrettyPrintLogsServlet.java index cef6ac543..b9cba3644 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/PrettyPrintLogsServlet.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/PrettyPrintLogsServlet.java @@ -1,82 +1,102 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.occamlab.te.web; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.OutputStream; -import java.util.logging.Level; -import java.util.logging.Logger; - -import jakarta.servlet.Servlet; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -import com.occamlab.te.config.Config; -import com.occamlab.te.util.DocumentationHelper; -import com.occamlab.te.util.Misc; - -/** - * A servlet that generates an HTML report from the contents of a test session log. The - * report is placed at the root of the user's work directory (in TE_BASE/users/) and is - * named after the session identifier (e.g. s0001.html). - */ -public class PrettyPrintLogsServlet extends HttpServlet implements Servlet { - - private static Logger LOGR = Logger.getLogger(PrettyPrintLogsServlet.class.getName()); - - private static final long serialVersionUID = 4555573278222613701L; - - Config Conf; - - DocumentationHelper docHelper; - - public void init() throws ServletException { - Conf = new Config(); - File stylesheet = Misc.getResourceAsFile("/com/occamlab/te/test_report_html.xsl"); - docHelper = new DocumentationHelper(stylesheet); - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { - - try { - String sessionId = request.getParameter("session"); - String reportFileName = sessionId + ".html"; - File userdir = new File(Conf.getUsersDir(), request.getRemoteUser()); - File sessiondir = new File(userdir, sessionId); - File prettyPrintReportFile = new File(userdir, reportFileName); - docHelper.prettyPrintsReport(sessiondir, prettyPrintReportFile); - response.setContentType("text/html"); - response.setHeader("Content-Disposition", "attachment; filename=" + reportFileName + ";"); - response.setHeader("Cache-Control", "no-cache"); - byte[] buf = new byte[response.getBufferSize()]; - response.setContentLength((int) prettyPrintReportFile.length()); - System.out.println("file length : " + (int) prettyPrintReportFile.length()); - int length; - BufferedInputStream fileInBuf = null; - try { - fileInBuf = new BufferedInputStream(new FileInputStream(prettyPrintReportFile)); - OutputStream out = response.getOutputStream(); - while ((length = fileInBuf.read(buf)) > 0) { - out.write(buf, 0, length); - } - } - finally { - if (null != fileInBuf) - fileInBuf.close(); - } - } - catch (Exception e) { - LOGR.log(Level.WARNING, "Failed to generate HTML test report.", e); - } - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.occamlab.te.web; + +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.OutputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jakarta.servlet.Servlet; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import com.occamlab.te.config.Config; +import com.occamlab.te.util.DocumentationHelper; +import com.occamlab.te.util.Misc; + +/** + * A servlet that generates an HTML report from the contents of a test session log. The + * report is placed at the root of the user's work directory (in TE_BASE/users/) and is + * named after the session identifier (e.g. s0001.html). + */ +public class PrettyPrintLogsServlet extends HttpServlet implements Servlet { + + private static Logger LOGR = Logger.getLogger(PrettyPrintLogsServlet.class.getName()); + + private static final long serialVersionUID = 4555573278222613701L; + + Config Conf; + + DocumentationHelper docHelper; + + public void init() throws ServletException { + Conf = new Config(); + File stylesheet = Misc.getResourceAsFile("/com/occamlab/te/test_report_html.xsl"); + docHelper = new DocumentationHelper(stylesheet); + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { + + try { + String sessionId = request.getParameter("session"); + String reportFileName = sessionId + ".html"; + File userdir = new File(Conf.getUsersDir(), request.getRemoteUser()); + File sessiondir = new File(userdir, sessionId); + File prettyPrintReportFile = new File(userdir, reportFileName); + docHelper.prettyPrintsReport(sessiondir, prettyPrintReportFile); + response.setContentType("text/html"); + response.setHeader("Content-Disposition", "attachment; filename=" + reportFileName + ";"); + response.setHeader("Cache-Control", "no-cache"); + byte[] buf = new byte[response.getBufferSize()]; + response.setContentLength((int) prettyPrintReportFile.length()); + System.out.println("file length : " + (int) prettyPrintReportFile.length()); + int length; + BufferedInputStream fileInBuf = null; + try { + fileInBuf = new BufferedInputStream(new FileInputStream(prettyPrintReportFile)); + OutputStream out = response.getOutputStream(); + while ((length = fileInBuf.read(buf)) > 0) { + out.write(buf, 0, length); + } + } + finally { + if (null != fileInBuf) + fileInBuf.close(); + } + } + catch (Exception e) { + LOGR.log(Level.WARNING, "Failed to generate HTML test report.", e); + } + } + +} diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/RegistrationHandlerServlet.java b/teamengine-web/src/main/java/com/occamlab/te/web/RegistrationHandlerServlet.java index 9257972e9..418872d16 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/RegistrationHandlerServlet.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/RegistrationHandlerServlet.java @@ -1,88 +1,108 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - ***************************************************************************** - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): No additional contributors to date - - ****************************************************************************/ -package com.occamlab.te.web; - -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -import com.occamlab.te.config.Config; -import com.occamlab.te.realm.PasswordStorage; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.PrintStream; - -/** - * Handles requests to register new users. - * - */ -public class RegistrationHandlerServlet extends HttpServlet { - - private static final long serialVersionUID = 7428127065308163495L; - - Config conf; - - public void init() throws ServletException { - conf = new Config(); - } - - public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException { - try { - String username = request.getParameter("username"); - String password = request.getParameter("password"); - String hashedPassword = PasswordStorage.createHash(password); - String email = request.getParameter("email"); - String firstName = request.getParameter("firstName"); - String lastName = request.getParameter("lastName"); - String organization = request.getParameter("organization"); - File userDir = new File(conf.getUsersDir(), username); - if (userDir.exists()) { - String url = "register.jsp?error=duplicate&username=" + username; - if (email != null) { - url += "&email=" + email; - } - response.sendRedirect(url); - } - else { - userDir.mkdirs(); - File xmlfile = new File(userDir, "user.xml"); - PrintStream out = new PrintStream(new FileOutputStream(xmlfile)); - out.println(""); - out.println(" " + username + ""); - out.println(" "); - out.println(" user"); - out.println(" "); - out.println(" " + hashedPassword + ""); - out.println(" " + email + ""); - out.println(" " + firstName + ""); - out.println(" " + lastName + ""); - out.println(" " + organization + ""); - out.println(""); - out.close(); - response.sendRedirect("registered.jsp"); - } - } - catch (Exception e) { - throw new ServletException(e); - } - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + ***************************************************************************** + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): No additional contributors to date + + ****************************************************************************/ +package com.occamlab.te.web; + +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import com.occamlab.te.config.Config; +import com.occamlab.te.realm.PasswordStorage; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintStream; + +/** + * Handles requests to register new users. + * + */ +public class RegistrationHandlerServlet extends HttpServlet { + + private static final long serialVersionUID = 7428127065308163495L; + + Config conf; + + public void init() throws ServletException { + conf = new Config(); + } + + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException { + try { + String username = request.getParameter("username"); + String password = request.getParameter("password"); + String hashedPassword = PasswordStorage.createHash(password); + String email = request.getParameter("email"); + String firstName = request.getParameter("firstName"); + String lastName = request.getParameter("lastName"); + String organization = request.getParameter("organization"); + File userDir = new File(conf.getUsersDir(), username); + if (userDir.exists()) { + String url = "register.jsp?error=duplicate&username=" + username; + if (email != null) { + url += "&email=" + email; + } + response.sendRedirect(url); + } + else { + userDir.mkdirs(); + File xmlfile = new File(userDir, "user.xml"); + PrintStream out = new PrintStream(new FileOutputStream(xmlfile)); + out.println(""); + out.println(" " + username + ""); + out.println(" "); + out.println(" user"); + out.println(" "); + out.println(" " + hashedPassword + ""); + out.println(" " + email + ""); + out.println(" " + firstName + ""); + out.println(" " + lastName + ""); + out.println(" " + organization + ""); + out.println(""); + out.close(); + response.sendRedirect("registered.jsp"); + } + } + catch (Exception e) { + throw new ServletException(e); + } + } + +} diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/TestServlet.java b/teamengine-web/src/main/java/com/occamlab/te/web/TestServlet.java index 9008bea86..9847abef7 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/TestServlet.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/TestServlet.java @@ -1,466 +1,486 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - ***************************************************************************** - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): - C. Heazel (WiSC): Added Fortify adjudication changes - - ****************************************************************************/ -package com.occamlab.te.web; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.PrintStream; -import java.net.URI; -import java.net.URL; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.logging.Logger; - -import jakarta.servlet.ServletException; -import jakarta.servlet.ServletOutputStream; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.servlet.http.HttpSession; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.stream.StreamSource; -import javax.xml.XMLConstants; // Addition for Fortify modifications - -import net.sf.saxon.FeatureKeys; -import net.sf.saxon.s9api.Processor; -import net.sf.saxon.s9api.Serializer; -import net.sf.saxon.s9api.XsltCompiler; -import net.sf.saxon.s9api.XsltExecutable; -import net.sf.saxon.s9api.XsltTransformer; - -import org.apache.commons.fileupload2.core.FileItem; -import org.apache.commons.fileupload2.core.FileItemFactory; -import org.apache.commons.fileupload2.core.DiskFileItemFactory; -import org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload; -import org.apache.commons.io.FileUtils; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import com.occamlab.te.Engine; -import com.occamlab.te.Generator; -import com.occamlab.te.RuntimeOptions; -import com.occamlab.te.SetupOptions; -import com.occamlab.te.TEClassLoader; -import com.occamlab.te.TECore; -import com.occamlab.te.Test; -import com.occamlab.te.config.Config; -import com.occamlab.te.config.ConfigFileCreator; -import com.occamlab.te.index.Index; -import com.occamlab.te.index.SuiteEntry; -import com.occamlab.te.util.DomUtils; -import com.occamlab.te.util.LogUtils; -import com.occamlab.te.util.Misc; -import com.occamlab.te.util.StringUtils; - -/** - * Main request handler. - * - */ -public class TestServlet extends HttpServlet { - - public static final String CTL_NS = "http://www.occamlab.com/ctl"; - - /** Alias is declared in the web app Context element. */ - private static final String ABOUT_ALIAS = "about/"; - - private static Logger LOGR = Logger.getLogger("com.occamlab.te.web.TestServlet"); - - DocumentBuilder DB; - - Transformer identityTransformer; - - Engine engine; - - Map indexes; - - Config conf; - - SetupOptions setupOpts; - - /** - * Generates executable test suites from available CTL sources. - */ - public void init() throws ServletException { - try { - - String path = getServletContext().getInitParameter("teConfigFile"); - - // create main config file when TE restarts - String tebase = path.split("config")[0]; - File teBasePath = new File(tebase); - File resorcePath = null; - if (teBasePath.exists()) { - resorcePath = new File((new File(teBasePath, "resources")), "docs"); - if (resorcePath.exists()) { - LOGR.info("TE_BASE is located at:" + tebase); - } - else { - LOGR.warning("TE_BASE exists but '${TE_BASE}/resources/docs' doesn't"); - } - } - else { - LOGR.warning("The variable TE_BASE has not been setup"); - } - ConfigFileCreator creator = new ConfigFileCreator(); - if (null != resorcePath && resorcePath.exists()) { - creator.create(tebase); - // delete workdir when TE restarts - - String workDir = path.split("config")[0] + "work"; - FileUtils.deleteDirectory(new File(workDir)); - LOGR.info("Deleting the work dir at:" + workDir); - } - conf = new Config(); - this.setupOpts = new SetupOptions(); - // Fortify Mod: prevent external entity injection - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - dbf.setExpandEntityReferences(false); - DB = dbf.newDocumentBuilder(); - // DB = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - // End Fortify Mod - - // Forify Mod: prevent external entity injection - TransformerFactory tf = TransformerFactory.newInstance(); - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - identityTransformer = tf.newTransformer(); - // identityTransformer = TransformerFactory.newInstance().newTransformer(); - - indexes = new HashMap<>(); - - HashMap classLoaders = new HashMap<>(); - - Processor processor = new Processor(false); - processor.setConfigurationProperty(FeatureKeys.XINCLUDE, Boolean.TRUE); - XsltCompiler sourceGeneratorCompiler = processor.newXsltCompiler(); - File sourceGeneratorStylesheet = Misc.getResourceAsFile("com/occamlab/te/generate_source_html.xsl"); - XsltExecutable sourceGeneratorXsltExecutable = sourceGeneratorCompiler - .compile(new StreamSource(sourceGeneratorStylesheet)); - XsltTransformer sourceGeneratorTransformer = sourceGeneratorXsltExecutable.load(); - // Generate simple HTML representation of CTL scripts referenced in - // test report; use real location of web app context (e.g. - // CATALINA_BASE/webapps/teamengine/) - File listingsBaseDir = new File(getServletConfig().getServletContext().getRealPath("/")); - File listings = new File(listingsBaseDir, "listings"); - if (!listings.mkdir() && !listings.exists()) { - LOGR.warning("Failed to create directory at " + listings.getAbsolutePath()); - } - for (Entry> sourceEntry : conf.getSources().entrySet()) { - String sourcesName = sourceEntry.getKey(); - LOGR.fine("TestServlet - Processing Test Suite: " + sourcesName); - setupOpts.setSourcesName(sourcesName); - // Fortify Mod: addSource now validated its arguments. - // Added a boolean to hold the returened status. - for (File source : sourceEntry.getValue()) { - boolean b = setupOpts.addSourceWithValidation(source); - } - Index index = Generator.generateXsl(setupOpts); - indexes.put(sourcesName, index); - - for (File ctlFile : index.getDependencies()) { - String encodedName = Generator.createEncodedName(ctlFile); - String basename = encodedName; - int i = basename.lastIndexOf('.'); - if (i > 0) { - basename = basename.substring(0, i); - } - File indexFile = new File(new File(setupOpts.getWorkDir(), encodedName), "index.xml"); - File htmlFile = new File(listings, basename + ".html"); - boolean needsGenerating = true; - if (htmlFile.exists()) { - needsGenerating = (indexFile.lastModified() > htmlFile.lastModified()); - } - if (needsGenerating) { - sourceGeneratorTransformer.setSource(new StreamSource(ctlFile)); - Serializer sourceGeneratorSerializer = new Serializer(); - sourceGeneratorSerializer.setOutputFile(htmlFile); - sourceGeneratorTransformer.setDestination(sourceGeneratorSerializer); - sourceGeneratorTransformer.transform(); - } - } - File resourcesDir = conf.getResources().get(sourcesName); - LOGR.config(String.format("Adding resources directory for %s: %s", sourcesName, resourcesDir)); - classLoaders.put(sourcesName, new TEClassLoader(resourcesDir)); - } - int cacheSize = 0; - String s = getServletConfig().getInitParameter("cacheSize"); - if (s != null) { - cacheSize = Integer.parseInt(s); - LOGR.fine("Set cacheSize to " + s); - } - engine = new Engine(indexes.values(), classLoaders, cacheSize); - } - catch (ServletException e) { - throw e; - } - catch (Exception e) { - throw new ServletException(e); - } - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { - process(request, response); - } - - public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException { - process(request, response); - } - - public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException { - try { - FileItemFactory ffactory; - JakartaServletFileUpload upload; - List items = null; - HashMap params = new HashMap<>(); - boolean multipart = JakartaServletFileUpload.isMultipartContent(request); - if (multipart) { - ffactory = new DiskFileItemFactory.Builder().get(); - upload = new JakartaServletFileUpload(ffactory); - items = upload.parseRequest(request); - Iterator iter = items.iterator(); - while (iter.hasNext()) { - FileItem item = iter.next(); - if (item.isFormField()) { - params.put(item.getFieldName(), item.getString()); - } - } - } - else { - Enumeration paramNames = request.getParameterNames(); - while (paramNames.hasMoreElements()) { - String name = (String) paramNames.nextElement(); - params.put(name, request.getParameter(name)); - } - } - HttpSession session = request.getSession(); - ServletOutputStream out = response.getOutputStream(); - String operation = params.get("te-operation"); - if (operation.equals("Test")) { - TestSession s = new TestSession(); - String user = request.getRemoteUser(); - File logdir = new File(conf.getUsersDir(), user); - LOGR.info("Creating test session in " + logdir.getAbsolutePath()); - String mode = params.get("mode"); - RuntimeOptions opts = new RuntimeOptions(); - opts.setWorkDir(setupOpts.getWorkDir()); - opts.setLogDir(logdir); - if (mode.equals("retest")) { - opts.setMode(Test.RETEST_MODE); - String sessionid = params.get("session"); - String test = params.get("test"); - if (sessionid == null) { - int i = test.indexOf("/"); - sessionid = i > 0 ? test.substring(0, i) : test; - } - opts.setSessionId(sessionid); - if (test == null) { - opts.addTestPath(sessionid); - } - else { - opts.addTestPath(test); - } - for (String key : new java.util.TreeSet<>(params.keySet())) { - if (key.startsWith("profile_")) { - String profileId = params.get(key); - int i = profileId.indexOf("}"); - opts.addTestPath(sessionid + "/" + profileId.substring(i + 1)); - } - } - s.load(logdir, sessionid); - opts.setSourcesName(s.getSourcesName()); - } - else if (mode.equals("resume")) { - opts.setMode(Test.RESUME_MODE); - String sessionid = params.get("session"); - opts.setSessionId(sessionid); - s.load(logdir, sessionid); - opts.setSourcesName(s.getSourcesName()); - } - else if (mode.equals("cache")) { - opts.setMode(Test.REDO_FROM_CACHE_MODE); - String sessionid = params.get("session"); - opts.setSessionId(sessionid); - s.load(logdir, sessionid); - opts.setSourcesName(s.getSourcesName()); - ArrayList profiles = new ArrayList<>(); - for (String key : new java.util.TreeSet<>(params.keySet())) { - if (key.startsWith("profile_")) { - String profileId = params.get(key); - profiles.add(profileId); - opts.addProfile(profileId); - } - } - s.setProfiles(profiles); - } - else { - opts.setMode(Test.TEST_MODE); - String sessionid = LogUtils.generateSessionId(logdir); - s.setSessionId(sessionid); - String sources = params.get("sources"); - s.setSourcesName(sources); - SuiteEntry suite = conf.getSuites().get(sources); - s.setSuiteName(suite.getId()); - String description = params.get("description"); - s.setDescription(description); - opts.setSessionId(sessionid); - opts.setSourcesName(sources); - opts.setSuiteName(suite.getId()); - ArrayList profiles = new ArrayList<>(); - for (String key : new java.util.TreeSet<>(params.keySet())) { - if (key.startsWith("profile_")) { - String profileId = params.get(key); - profiles.add(profileId); - opts.addProfile(profileId); - } - } - s.setProfiles(profiles); - s.save(logdir); - } - String webdir = conf.getWebDirs().get(s.getSourcesName()); - URI contextURI = new URI(request.getScheme(), null, request.getServerName(), request.getServerPort(), - request.getRequestURI(), null, null); - if (webdir == null) { - webdir = "."; - } - URL baseURL = new URL(contextURI.toURL(), ABOUT_ALIAS + webdir + "/"); - LOGR.fine("Base URL is " + baseURL); - opts.setBaseURI(baseURL.toString()); - TECore core = new TECore(engine, indexes.get(opts.getSourcesName()), opts); - String servletURL = request.getRequestURL().toString(); - LOGR.fine("Request URL is " + servletURL); - core.setTestServletURL(servletURL); - MonitorServlet.setBaseServletURL(servletURL.substring(0, servletURL.lastIndexOf('/'))); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); - core.setOut(ps); - core.setWeb(true); - Thread thread = new Thread(core); - session.setAttribute("testsession", core); - thread.start(); - response.setContentType("text/xml"); - out.println(""); - } - else if (operation.equals("Stop")) { - response.setContentType("text/xml"); - TECore core = (TECore) session.getAttribute("testsession"); - if (core != null) { - core.stopThread(); - session.removeAttribute("testsession"); - out.println(""); - } - else { - out.println("Could not retrieve core object"); - } - } - else if (operation.equals("GetStatus")) { - TECore core = (TECore) session.getAttribute("testsession"); - response.setContentType("text/xml"); - out.print(""); - out.print(""); - out.println(""); - } - else if (operation.equals("GetForm")) { - TECore core = (TECore) session.getAttribute("testsession"); - String html = core.getFormHtml(); - core.setFormHtml(null); - response.setContentType("text/html"); - out.print(html); - } - else if (operation.equals("SubmitForm")) { - TECore core = (TECore) session.getAttribute("testsession"); - Document doc = DB.newDocument(); - Element root = doc.createElement("values"); - doc.appendChild(root); - for (String key : params.keySet()) { - if (!key.startsWith("te-")) { - Element valueElement = doc.createElement("value"); - valueElement.setAttribute("key", key); - valueElement.appendChild(doc.createTextNode(params.get(key))); - root.appendChild(valueElement); - } - } - if (multipart) { - Iterator iter = items.iterator(); - while (iter.hasNext()) { - FileItem item = (FileItem) iter.next(); - if (!item.isFormField() && !item.getName().isEmpty()) { - File tempDir = new File(URI.create(core.getTestRunDirectory())); - File uploadedFile = new File(tempDir, StringUtils.getFilenameFromString(item.getName())); - item.write(uploadedFile.toPath()); - Element valueElement = doc.createElement("value"); - String key = item.getFieldName(); - valueElement.setAttribute("key", key); - if (core.getFormParsers().containsKey(key)) { - Element parser = core.getFormParsers().get(key); - URL url = uploadedFile.toURI().toURL(); - Element resp = core.parse(url.openConnection(), parser, doc); - Element content = DomUtils.getElementByTagName(resp, "content"); - if (content != null) { - Element child = DomUtils.getChildElement(content); - if (child != null) { - valueElement.appendChild(child); - } - } - } - else { - Element fileEntry = doc.createElementNS(CTL_NS, "file-entry"); - fileEntry.setAttribute("full-path", uploadedFile.getAbsolutePath().replace('\\', '/')); - fileEntry.setAttribute("media-type", item.getContentType()); - fileEntry.setAttribute("size", String.valueOf(item.getSize())); - valueElement.appendChild(fileEntry); - } - root.appendChild(valueElement); - } - } - } - core.setFormResults(doc); - response.setContentType("text/html"); - out.println(""); - out.println("Form Submitted"); - out.print(""); - out.println(""); - } - } - catch (Throwable t) { - throw new ServletException(t); - } - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + ***************************************************************************** + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): + C. Heazel (WiSC): Added Fortify adjudication changes + + ****************************************************************************/ +package com.occamlab.te.web; + +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.PrintStream; +import java.net.URI; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Logger; + +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamSource; +import javax.xml.XMLConstants; // Addition for Fortify modifications + +import net.sf.saxon.FeatureKeys; +import net.sf.saxon.s9api.Processor; +import net.sf.saxon.s9api.Serializer; +import net.sf.saxon.s9api.XsltCompiler; +import net.sf.saxon.s9api.XsltExecutable; +import net.sf.saxon.s9api.XsltTransformer; + +import org.apache.commons.fileupload2.core.FileItem; +import org.apache.commons.fileupload2.core.FileItemFactory; +import org.apache.commons.fileupload2.core.DiskFileItemFactory; +import org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload; +import org.apache.commons.io.FileUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import com.occamlab.te.Engine; +import com.occamlab.te.Generator; +import com.occamlab.te.RuntimeOptions; +import com.occamlab.te.SetupOptions; +import com.occamlab.te.TEClassLoader; +import com.occamlab.te.TECore; +import com.occamlab.te.Test; +import com.occamlab.te.config.Config; +import com.occamlab.te.config.ConfigFileCreator; +import com.occamlab.te.index.Index; +import com.occamlab.te.index.SuiteEntry; +import com.occamlab.te.util.DomUtils; +import com.occamlab.te.util.LogUtils; +import com.occamlab.te.util.Misc; +import com.occamlab.te.util.StringUtils; + +/** + * Main request handler. + * + */ +public class TestServlet extends HttpServlet { + + public static final String CTL_NS = "http://www.occamlab.com/ctl"; + + /** Alias is declared in the web app Context element. */ + private static final String ABOUT_ALIAS = "about/"; + + private static Logger LOGR = Logger.getLogger("com.occamlab.te.web.TestServlet"); + + DocumentBuilder DB; + + Transformer identityTransformer; + + Engine engine; + + Map indexes; + + Config conf; + + SetupOptions setupOpts; + + /** + * Generates executable test suites from available CTL sources. + */ + public void init() throws ServletException { + try { + + String path = getServletContext().getInitParameter("teConfigFile"); + + // create main config file when TE restarts + String tebase = path.split("config")[0]; + File teBasePath = new File(tebase); + File resorcePath = null; + if (teBasePath.exists()) { + resorcePath = new File((new File(teBasePath, "resources")), "docs"); + if (resorcePath.exists()) { + LOGR.info("TE_BASE is located at:" + tebase); + } + else { + LOGR.warning("TE_BASE exists but '${TE_BASE}/resources/docs' doesn't"); + } + } + else { + LOGR.warning("The variable TE_BASE has not been setup"); + } + ConfigFileCreator creator = new ConfigFileCreator(); + if (null != resorcePath && resorcePath.exists()) { + creator.create(tebase); + // delete workdir when TE restarts + + String workDir = path.split("config")[0] + "work"; + FileUtils.deleteDirectory(new File(workDir)); + LOGR.info("Deleting the work dir at:" + workDir); + } + conf = new Config(); + this.setupOpts = new SetupOptions(); + // Fortify Mod: prevent external entity injection + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + dbf.setExpandEntityReferences(false); + DB = dbf.newDocumentBuilder(); + // DB = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + // End Fortify Mod + + // Forify Mod: prevent external entity injection + TransformerFactory tf = TransformerFactory.newInstance(); + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + identityTransformer = tf.newTransformer(); + // identityTransformer = TransformerFactory.newInstance().newTransformer(); + + indexes = new HashMap<>(); + + HashMap classLoaders = new HashMap<>(); + + Processor processor = new Processor(false); + processor.setConfigurationProperty(FeatureKeys.XINCLUDE, Boolean.TRUE); + XsltCompiler sourceGeneratorCompiler = processor.newXsltCompiler(); + File sourceGeneratorStylesheet = Misc.getResourceAsFile("com/occamlab/te/generate_source_html.xsl"); + XsltExecutable sourceGeneratorXsltExecutable = sourceGeneratorCompiler + .compile(new StreamSource(sourceGeneratorStylesheet)); + XsltTransformer sourceGeneratorTransformer = sourceGeneratorXsltExecutable.load(); + // Generate simple HTML representation of CTL scripts referenced in + // test report; use real location of web app context (e.g. + // CATALINA_BASE/webapps/teamengine/) + File listingsBaseDir = new File(getServletConfig().getServletContext().getRealPath("/")); + File listings = new File(listingsBaseDir, "listings"); + if (!listings.mkdir() && !listings.exists()) { + LOGR.warning("Failed to create directory at " + listings.getAbsolutePath()); + } + for (Entry> sourceEntry : conf.getSources().entrySet()) { + String sourcesName = sourceEntry.getKey(); + LOGR.fine("TestServlet - Processing Test Suite: " + sourcesName); + setupOpts.setSourcesName(sourcesName); + // Fortify Mod: addSource now validated its arguments. + // Added a boolean to hold the returened status. + for (File source : sourceEntry.getValue()) { + boolean b = setupOpts.addSourceWithValidation(source); + } + Index index = Generator.generateXsl(setupOpts); + indexes.put(sourcesName, index); + + for (File ctlFile : index.getDependencies()) { + String encodedName = Generator.createEncodedName(ctlFile); + String basename = encodedName; + int i = basename.lastIndexOf('.'); + if (i > 0) { + basename = basename.substring(0, i); + } + File indexFile = new File(new File(setupOpts.getWorkDir(), encodedName), "index.xml"); + File htmlFile = new File(listings, basename + ".html"); + boolean needsGenerating = true; + if (htmlFile.exists()) { + needsGenerating = (indexFile.lastModified() > htmlFile.lastModified()); + } + if (needsGenerating) { + sourceGeneratorTransformer.setSource(new StreamSource(ctlFile)); + Serializer sourceGeneratorSerializer = new Serializer(); + sourceGeneratorSerializer.setOutputFile(htmlFile); + sourceGeneratorTransformer.setDestination(sourceGeneratorSerializer); + sourceGeneratorTransformer.transform(); + } + } + File resourcesDir = conf.getResources().get(sourcesName); + LOGR.config(String.format("Adding resources directory for %s: %s", sourcesName, resourcesDir)); + classLoaders.put(sourcesName, new TEClassLoader(resourcesDir)); + } + int cacheSize = 0; + String s = getServletConfig().getInitParameter("cacheSize"); + if (s != null) { + cacheSize = Integer.parseInt(s); + LOGR.fine("Set cacheSize to " + s); + } + engine = new Engine(indexes.values(), classLoaders, cacheSize); + } + catch (ServletException e) { + throw e; + } + catch (Exception e) { + throw new ServletException(e); + } + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { + process(request, response); + } + + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException { + process(request, response); + } + + public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException { + try { + FileItemFactory ffactory; + JakartaServletFileUpload upload; + List items = null; + HashMap params = new HashMap<>(); + boolean multipart = JakartaServletFileUpload.isMultipartContent(request); + if (multipart) { + ffactory = new DiskFileItemFactory.Builder().get(); + upload = new JakartaServletFileUpload(ffactory); + items = upload.parseRequest(request); + Iterator iter = items.iterator(); + while (iter.hasNext()) { + FileItem item = iter.next(); + if (item.isFormField()) { + params.put(item.getFieldName(), item.getString()); + } + } + } + else { + Enumeration paramNames = request.getParameterNames(); + while (paramNames.hasMoreElements()) { + String name = (String) paramNames.nextElement(); + params.put(name, request.getParameter(name)); + } + } + HttpSession session = request.getSession(); + ServletOutputStream out = response.getOutputStream(); + String operation = params.get("te-operation"); + if (operation.equals("Test")) { + TestSession s = new TestSession(); + String user = request.getRemoteUser(); + File logdir = new File(conf.getUsersDir(), user); + LOGR.info("Creating test session in " + logdir.getAbsolutePath()); + String mode = params.get("mode"); + RuntimeOptions opts = new RuntimeOptions(); + opts.setWorkDir(setupOpts.getWorkDir()); + opts.setLogDir(logdir); + if (mode.equals("retest")) { + opts.setMode(Test.RETEST_MODE); + String sessionid = params.get("session"); + String test = params.get("test"); + if (sessionid == null) { + int i = test.indexOf("/"); + sessionid = i > 0 ? test.substring(0, i) : test; + } + opts.setSessionId(sessionid); + if (test == null) { + opts.addTestPath(sessionid); + } + else { + opts.addTestPath(test); + } + for (String key : new java.util.TreeSet<>(params.keySet())) { + if (key.startsWith("profile_")) { + String profileId = params.get(key); + int i = profileId.indexOf("}"); + opts.addTestPath(sessionid + "/" + profileId.substring(i + 1)); + } + } + s.load(logdir, sessionid); + opts.setSourcesName(s.getSourcesName()); + } + else if (mode.equals("resume")) { + opts.setMode(Test.RESUME_MODE); + String sessionid = params.get("session"); + opts.setSessionId(sessionid); + s.load(logdir, sessionid); + opts.setSourcesName(s.getSourcesName()); + } + else if (mode.equals("cache")) { + opts.setMode(Test.REDO_FROM_CACHE_MODE); + String sessionid = params.get("session"); + opts.setSessionId(sessionid); + s.load(logdir, sessionid); + opts.setSourcesName(s.getSourcesName()); + ArrayList profiles = new ArrayList<>(); + for (String key : new java.util.TreeSet<>(params.keySet())) { + if (key.startsWith("profile_")) { + String profileId = params.get(key); + profiles.add(profileId); + opts.addProfile(profileId); + } + } + s.setProfiles(profiles); + } + else { + opts.setMode(Test.TEST_MODE); + String sessionid = LogUtils.generateSessionId(logdir); + s.setSessionId(sessionid); + String sources = params.get("sources"); + s.setSourcesName(sources); + SuiteEntry suite = conf.getSuites().get(sources); + s.setSuiteName(suite.getId()); + String description = params.get("description"); + s.setDescription(description); + opts.setSessionId(sessionid); + opts.setSourcesName(sources); + opts.setSuiteName(suite.getId()); + ArrayList profiles = new ArrayList<>(); + for (String key : new java.util.TreeSet<>(params.keySet())) { + if (key.startsWith("profile_")) { + String profileId = params.get(key); + profiles.add(profileId); + opts.addProfile(profileId); + } + } + s.setProfiles(profiles); + s.save(logdir); + } + String webdir = conf.getWebDirs().get(s.getSourcesName()); + URI contextURI = new URI(request.getScheme(), null, request.getServerName(), request.getServerPort(), + request.getRequestURI(), null, null); + if (webdir == null) { + webdir = "."; + } + URL baseURL = new URL(contextURI.toURL(), ABOUT_ALIAS + webdir + "/"); + LOGR.fine("Base URL is " + baseURL); + opts.setBaseURI(baseURL.toString()); + TECore core = new TECore(engine, indexes.get(opts.getSourcesName()), opts); + String servletURL = request.getRequestURL().toString(); + LOGR.fine("Request URL is " + servletURL); + core.setTestServletURL(servletURL); + MonitorServlet.setBaseServletURL(servletURL.substring(0, servletURL.lastIndexOf('/'))); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos); + core.setOut(ps); + core.setWeb(true); + Thread thread = new Thread(core); + session.setAttribute("testsession", core); + thread.start(); + response.setContentType("text/xml"); + out.println(""); + } + else if (operation.equals("Stop")) { + response.setContentType("text/xml"); + TECore core = (TECore) session.getAttribute("testsession"); + if (core != null) { + core.stopThread(); + session.removeAttribute("testsession"); + out.println(""); + } + else { + out.println("Could not retrieve core object"); + } + } + else if (operation.equals("GetStatus")) { + TECore core = (TECore) session.getAttribute("testsession"); + response.setContentType("text/xml"); + out.print(""); + out.print(""); + out.println(""); + } + else if (operation.equals("GetForm")) { + TECore core = (TECore) session.getAttribute("testsession"); + String html = core.getFormHtml(); + core.setFormHtml(null); + response.setContentType("text/html"); + out.print(html); + } + else if (operation.equals("SubmitForm")) { + TECore core = (TECore) session.getAttribute("testsession"); + Document doc = DB.newDocument(); + Element root = doc.createElement("values"); + doc.appendChild(root); + for (String key : params.keySet()) { + if (!key.startsWith("te-")) { + Element valueElement = doc.createElement("value"); + valueElement.setAttribute("key", key); + valueElement.appendChild(doc.createTextNode(params.get(key))); + root.appendChild(valueElement); + } + } + if (multipart) { + Iterator iter = items.iterator(); + while (iter.hasNext()) { + FileItem item = (FileItem) iter.next(); + if (!item.isFormField() && !item.getName().isEmpty()) { + File tempDir = new File(URI.create(core.getTestRunDirectory())); + File uploadedFile = new File(tempDir, StringUtils.getFilenameFromString(item.getName())); + item.write(uploadedFile.toPath()); + Element valueElement = doc.createElement("value"); + String key = item.getFieldName(); + valueElement.setAttribute("key", key); + if (core.getFormParsers().containsKey(key)) { + Element parser = core.getFormParsers().get(key); + URL url = uploadedFile.toURI().toURL(); + Element resp = core.parse(url.openConnection(), parser, doc); + Element content = DomUtils.getElementByTagName(resp, "content"); + if (content != null) { + Element child = DomUtils.getChildElement(content); + if (child != null) { + valueElement.appendChild(child); + } + } + } + else { + Element fileEntry = doc.createElementNS(CTL_NS, "file-entry"); + fileEntry.setAttribute("full-path", uploadedFile.getAbsolutePath().replace('\\', '/')); + fileEntry.setAttribute("media-type", item.getContentType()); + fileEntry.setAttribute("size", String.valueOf(item.getSize())); + valueElement.appendChild(fileEntry); + } + root.appendChild(valueElement); + } + } + } + core.setFormResults(doc); + response.setContentType("text/html"); + out.println(""); + out.println("Form Submitted"); + out.print(""); + out.println(""); + } + } + catch (Throwable t) { + throw new ServletException(t); + } + } + +} diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/TestSession.java b/teamengine-web/src/main/java/com/occamlab/te/web/TestSession.java index f052808e1..6e10c5e3d 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/TestSession.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/TestSession.java @@ -1,207 +1,227 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - ***************************************************************************** - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): - C. Heazel (WiSC): Added Fortify adjudication changes - - ****************************************************************************/ -package com.occamlab.te.web; - -import com.occamlab.te.util.DomUtils; -import com.occamlab.te.util.StringUtils; - -import java.io.File; -import java.io.PrintStream; -import java.text.DateFormat; -import java.text.Format; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.logging.Logger; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -/** - * Encapsulates all information pertaining to a test session. - */ -public class TestSession implements Comparable { - - private static Logger LOGR = Logger.getLogger(TestSession.class.getName()); - - String sessionId; - - String sourcesName; - - String description; - - String suiteName; - - String currentDate; - - ArrayList profiles; - - /** - * Creates a new test session. - */ - public TestSession() throws Exception { - suiteName = null; - profiles = new ArrayList<>(); - } - - public void save(File logdir) throws Exception { - File sessionDir = new File(logdir, sessionId); - sessionDir.mkdir(); - DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); - Date date = new Date(); - currentDate = dateFormat.format(date); - PrintStream out = new PrintStream(new File(sessionDir, "session.xml")); - out.println( - ""); - out.println("" + suiteName + ""); - for (String profile : profiles) { - out.println("" + profile + ""); - } - - String description_data; - description_data = StringUtils.escapeXML(description); - - out.println("" + description_data + ""); - out.println(""); - // Fortify Mod: flush and close the PrintStream - out.close(); - } - - /** - * Creates a test session from a previous run. - */ - public void load(File logdir, String sessionId) throws Exception { - this.sessionId = sessionId; - File sessionDir = new File(logdir, sessionId); - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - // Fortify Mod: prevent external entity injection - dbf.setExpandEntityReferences(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.parse(new File(sessionDir, "session.xml")); - Element session = (Element) (doc.getElementsByTagName("session").item(0)); - setSourcesName(session.getAttribute("sourcesId")); - if (session.hasAttribute("date")) { - setCurrentDate(session.getAttribute("date")); - } - else { - setCurrentDate(""); - } - Element suite = DomUtils.getElementByTagName(session, "suite"); - setSuiteName(suite.getTextContent()); - for (Element profile : DomUtils.getElementsByTagName(session, "profile")) { - profiles.add(profile.getTextContent()); - } - Element description = (Element) (session.getElementsByTagName("description").item(0)); - this.description = description.getTextContent(); - } - - /** - * This will return the sorted list of TestSession data according to date. - * @param testData List of all TestSessions. - * @return Return the sorted list of testData. - */ - public List getSortedMap(List testData) { - Collections.sort(testData); - Collections.reverse(testData); - return testData; - } - - @Override - public int compareTo(TestSession other) { - if (other == null) { - return -1; - } - Date otherDate = convertStringToDate(other.getCurrentDate(), other.getSessionId()); - if (otherDate == null) { - return -1; - } - Date thisDate = convertStringToDate(this.getCurrentDate(), this.getSessionId()); - if (thisDate == null) - return 1; - return thisDate.compareTo(otherDate); - } - - private Date convertStringToDate(String dateString, String sessionId) { - try { - if (dateString != null) { - Format formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); - return ((DateFormat) formatter).parse(dateString); - } - } - catch (Exception e) { - LOGR.warning("Could not parse date '" + dateString + "' of session with id " + sessionId); - } - return null; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public ArrayList getProfiles() { - return profiles; - } - - public void setProfiles(ArrayList profiles) { - this.profiles = profiles; - } - - public String getSessionId() { - return sessionId; - } - - public void setSessionId(String sessionId) { - this.sessionId = sessionId; - } - - public String getSourcesName() { - return sourcesName; - } - - public void setSourcesName(String sourcesName) { - this.sourcesName = sourcesName; - } - - public String getCurrentDate() { - return currentDate; - } - - public void setCurrentDate(String currentDate) { - this.currentDate = currentDate; - } - - public String getSuiteName() { - return suiteName; - } - - public void setSuiteName(String suiteName) { - this.suiteName = suiteName; - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + ***************************************************************************** + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): + C. Heazel (WiSC): Added Fortify adjudication changes + + ****************************************************************************/ +package com.occamlab.te.web; + +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.occamlab.te.util.DomUtils; +import com.occamlab.te.util.StringUtils; + +import java.io.File; +import java.io.PrintStream; +import java.text.DateFormat; +import java.text.Format; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.logging.Logger; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Encapsulates all information pertaining to a test session. + */ +public class TestSession implements Comparable { + + private static Logger LOGR = Logger.getLogger(TestSession.class.getName()); + + String sessionId; + + String sourcesName; + + String description; + + String suiteName; + + String currentDate; + + ArrayList profiles; + + /** + * Creates a new test session. + */ + public TestSession() throws Exception { + suiteName = null; + profiles = new ArrayList<>(); + } + + public void save(File logdir) throws Exception { + File sessionDir = new File(logdir, sessionId); + sessionDir.mkdir(); + DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + Date date = new Date(); + currentDate = dateFormat.format(date); + PrintStream out = new PrintStream(new File(sessionDir, "session.xml")); + out.println( + ""); + out.println("" + suiteName + ""); + for (String profile : profiles) { + out.println("" + profile + ""); + } + + String description_data; + description_data = StringUtils.escapeXML(description); + + out.println("" + description_data + ""); + out.println(""); + // Fortify Mod: flush and close the PrintStream + out.close(); + } + + /** + * Creates a test session from a previous run. + */ + public void load(File logdir, String sessionId) throws Exception { + this.sessionId = sessionId; + File sessionDir = new File(logdir, sessionId); + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + // Fortify Mod: prevent external entity injection + dbf.setExpandEntityReferences(false); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.parse(new File(sessionDir, "session.xml")); + Element session = (Element) (doc.getElementsByTagName("session").item(0)); + setSourcesName(session.getAttribute("sourcesId")); + if (session.hasAttribute("date")) { + setCurrentDate(session.getAttribute("date")); + } + else { + setCurrentDate(""); + } + Element suite = DomUtils.getElementByTagName(session, "suite"); + setSuiteName(suite.getTextContent()); + for (Element profile : DomUtils.getElementsByTagName(session, "profile")) { + profiles.add(profile.getTextContent()); + } + Element description = (Element) (session.getElementsByTagName("description").item(0)); + this.description = description.getTextContent(); + } + + /** + * This will return the sorted list of TestSession data according to date. + * @param testData List of all TestSessions. + * @return Return the sorted list of testData. + */ + public List getSortedMap(List testData) { + Collections.sort(testData); + Collections.reverse(testData); + return testData; + } + + @Override + public int compareTo(TestSession other) { + if (other == null) { + return -1; + } + Date otherDate = convertStringToDate(other.getCurrentDate(), other.getSessionId()); + if (otherDate == null) { + return -1; + } + Date thisDate = convertStringToDate(this.getCurrentDate(), this.getSessionId()); + if (thisDate == null) + return 1; + return thisDate.compareTo(otherDate); + } + + private Date convertStringToDate(String dateString, String sessionId) { + try { + if (dateString != null) { + Format formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + return ((DateFormat) formatter).parse(dateString); + } + } + catch (Exception e) { + LOGR.warning("Could not parse date '" + dateString + "' of session with id " + sessionId); + } + return null; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public ArrayList getProfiles() { + return profiles; + } + + public void setProfiles(ArrayList profiles) { + this.profiles = profiles; + } + + public String getSessionId() { + return sessionId; + } + + public void setSessionId(String sessionId) { + this.sessionId = sessionId; + } + + public String getSourcesName() { + return sourcesName; + } + + public void setSourcesName(String sourcesName) { + this.sourcesName = sourcesName; + } + + public String getCurrentDate() { + return currentDate; + } + + public void setCurrentDate(String currentDate) { + this.currentDate = currentDate; + } + + public String getSuiteName() { + return suiteName; + } + + public void setSuiteName(String suiteName) { + this.suiteName = suiteName; + } + +} diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/ViewLogServlet.java b/teamengine-web/src/main/java/com/occamlab/te/web/ViewLogServlet.java index 8e2705d3b..4afb632c8 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/ViewLogServlet.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/ViewLogServlet.java @@ -1,84 +1,104 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - ***************************************************************************** - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): - C. Heazel (WiSC): Added Fortify adjudication changes - - ****************************************************************************/ -package com.occamlab.te.web; - -import java.io.File; -import java.io.OutputStreamWriter; -import java.util.ArrayList; - -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import javax.xml.transform.Templates; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.stream.StreamSource; -import javax.xml.XMLConstants; // Addition for Fortify modifications - -import com.occamlab.te.ViewLog; -import com.occamlab.te.config.Config; -import com.occamlab.te.util.Misc; - -/** - * Processes (GET method) requests to view a test log. - * - */ -public class ViewLogServlet extends HttpServlet { - - private static final long serialVersionUID = 2891486945236875019L; - - Config conf; - - Templates viewLogTemplates; - - public void init() throws ServletException { - try { - conf = new Config(); - File stylesheet = Misc.getResourceAsFile("com/occamlab/te/web/viewlog.xsl"); - TransformerFactory transformerFactory = TransformerFactory.newInstance(); - // Fortify Mod: prevent external entity injection - transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - viewLogTemplates = transformerFactory.newTemplates(new StreamSource(stylesheet)); - } - catch (Exception e) { - e.printStackTrace(System.out); - } - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { - try { - ArrayList tests = new ArrayList<>(); - String user = request.getRemoteUser(); - File userlog = new File(conf.getUsersDir(), user); - String session = request.getParameter("session"); - String test = request.getParameter("test"); - if (test != null) { - tests.add(test); - } - String suiteName = null; - ViewLog.view_log(suiteName, userlog, session, tests, viewLogTemplates, - new OutputStreamWriter(response.getOutputStream())); - } - catch (Exception e) { - throw new ServletException(e); - } - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + ***************************************************************************** + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): + C. Heazel (WiSC): Added Fortify adjudication changes + + ****************************************************************************/ +package com.occamlab.te.web; + +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.io.OutputStreamWriter; +import java.util.ArrayList; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import javax.xml.transform.Templates; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamSource; +import javax.xml.XMLConstants; // Addition for Fortify modifications + +import com.occamlab.te.ViewLog; +import com.occamlab.te.config.Config; +import com.occamlab.te.util.Misc; + +/** + * Processes (GET method) requests to view a test log. + * + */ +public class ViewLogServlet extends HttpServlet { + + private static final long serialVersionUID = 2891486945236875019L; + + Config conf; + + Templates viewLogTemplates; + + public void init() throws ServletException { + try { + conf = new Config(); + File stylesheet = Misc.getResourceAsFile("com/occamlab/te/web/viewlog.xsl"); + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + // Fortify Mod: prevent external entity injection + transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + viewLogTemplates = transformerFactory.newTemplates(new StreamSource(stylesheet)); + } + catch (Exception e) { + e.printStackTrace(System.out); + } + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { + try { + ArrayList tests = new ArrayList<>(); + String user = request.getRemoteUser(); + File userlog = new File(conf.getUsersDir(), user); + String session = request.getParameter("session"); + String test = request.getParameter("test"); + if (test != null) { + tests.add(test); + } + String suiteName = null; + ViewLog.view_log(suiteName, userlog, session, tests, viewLogTemplates, + new OutputStreamWriter(response.getOutputStream())); + } + catch (Exception e) { + throw new ServletException(e); + } + } + +} diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/ViewTestServlet.java b/teamengine-web/src/main/java/com/occamlab/te/web/ViewTestServlet.java index a0c8ae62d..d44e6acdd 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/ViewTestServlet.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/ViewTestServlet.java @@ -1,81 +1,101 @@ -/* - * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - ***************************************************************************** - - The Original Code is TEAM Engine. - - The Initial Developer of the Original Code is Northrop Grumman Corporation - jointly with The National Technology Alliance. Portions created by - Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop - Grumman Corporation. All Rights Reserved. - - Contributor(s): - C. Heazel (WiSC): Added Fortify adjudication changes - - ****************************************************************************/ -package com.occamlab.te.web; - -import java.io.File; -import java.net.URL; - -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import javax.xml.transform.Templates; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; -import javax.xml.XMLConstants; // Addition for Fortify modifications - -import com.occamlab.te.util.Misc; - -/** - * Handles (GET) requests to view a test case specification (from the test summary - * report). - * - */ -public class ViewTestServlet extends HttpServlet { - - private static final long serialVersionUID = -1396673675342836097L; - - Templates viewTestTemplates; - - public void init() throws ServletException { - try { - File stylesheet = Misc.getResourceAsFile("com/occamlab/te/web/viewtest.xsl"); - // Fortify Mod: prevent external entity injection - TransformerFactory tf = TransformerFactory.newInstance(); - tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - viewTestTemplates = tf.newTemplates(new StreamSource(stylesheet)); - // viewTestTemplates = TransformerFactory.newInstance().newTemplates( - // new StreamSource(stylesheet)); - } - catch (Exception e) { - throw new ServletException(e); - } - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { - try { - File file = new File(request.getParameter("file")); - Transformer t = viewTestTemplates.newTransformer(); - t.setParameter("namespace-uri", request.getParameter("namespace")); - t.setParameter("local-name", request.getParameter("name")); - URL url = new URL(request.getScheme(), request.getServerName(), request.getServerPort(), - request.getContextPath()); - t.setParameter("baseURL", url.toString()); - t.setParameter("user", request.getRemoteUser()); - t.transform(new StreamSource(file), new StreamResult(response.getOutputStream())); - } - catch (Exception e) { - throw new ServletException(e); - } - } - -} +/* + * The Open Geospatial Consortium licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + ***************************************************************************** + + The Original Code is TEAM Engine. + + The Initial Developer of the Original Code is Northrop Grumman Corporation + jointly with The National Technology Alliance. Portions created by + Northrop Grumman Corporation are Copyright (C) 2005-2006, Northrop + Grumman Corporation. All Rights Reserved. + + Contributor(s): + C. Heazel (WiSC): Added Fortify adjudication changes + + ****************************************************************************/ +package com.occamlab.te.web; + +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import java.io.File; +import java.net.URL; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import javax.xml.XMLConstants; // Addition for Fortify modifications + +import com.occamlab.te.util.Misc; + +/** + * Handles (GET) requests to view a test case specification (from the test summary + * report). + * + */ +public class ViewTestServlet extends HttpServlet { + + private static final long serialVersionUID = -1396673675342836097L; + + Templates viewTestTemplates; + + public void init() throws ServletException { + try { + File stylesheet = Misc.getResourceAsFile("com/occamlab/te/web/viewtest.xsl"); + // Fortify Mod: prevent external entity injection + TransformerFactory tf = TransformerFactory.newInstance(); + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + viewTestTemplates = tf.newTemplates(new StreamSource(stylesheet)); + // viewTestTemplates = TransformerFactory.newInstance().newTemplates( + // new StreamSource(stylesheet)); + } + catch (Exception e) { + throw new ServletException(e); + } + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { + try { + File file = new File(request.getParameter("file")); + Transformer t = viewTestTemplates.newTransformer(); + t.setParameter("namespace-uri", request.getParameter("namespace")); + t.setParameter("local-name", request.getParameter("name")); + URL url = new URL(request.getScheme(), request.getServerName(), request.getServerPort(), + request.getContextPath()); + t.setParameter("baseURL", url.toString()); + t.setParameter("user", request.getRemoteUser()); + t.transform(new StreamSource(file), new StreamResult(response.getOutputStream())); + } + catch (Exception e) { + throw new ServletException(e); + } + } + +} diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/listeners/CleartextPasswordContextListener.java b/teamengine-web/src/main/java/com/occamlab/te/web/listeners/CleartextPasswordContextListener.java index b575fcbf4..f26fe0aa0 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/listeners/CleartextPasswordContextListener.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/listeners/CleartextPasswordContextListener.java @@ -7,6 +7,26 @@ */ package com.occamlab.te.web.listeners; +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import java.io.File; import java.io.FileOutputStream; import java.util.logging.Level; diff --git a/teamengine-web/src/main/java/com/occamlab/te/web/listeners/TEServletContextListener.java b/teamengine-web/src/main/java/com/occamlab/te/web/listeners/TEServletContextListener.java index 3fad9a39d..eb703bd12 100644 --- a/teamengine-web/src/main/java/com/occamlab/te/web/listeners/TEServletContextListener.java +++ b/teamengine-web/src/main/java/com/occamlab/te/web/listeners/TEServletContextListener.java @@ -7,6 +7,26 @@ */ package com.occamlab.te.web.listeners; +/*- + * #%L + * TEAM Engine - Web Application + * %% + * Copyright (C) 2006 - 2024 Open Geospatial Consortium + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import com.occamlab.te.SetupOptions; import jakarta.servlet.ServletContextEvent; diff --git a/teamengine-web/src/main/resources/com/occamlab/te/web/viewlog.xsl b/teamengine-web/src/main/resources/com/occamlab/te/web/viewlog.xsl index c6bebee5b..02ab13919 100644 --- a/teamengine-web/src/main/resources/com/occamlab/te/web/viewlog.xsl +++ b/teamengine-web/src/main/resources/com/occamlab/te/web/viewlog.xsl @@ -1,4 +1,24 @@ + + + + + + text/xml diff --git a/teamengine-web/src/main/resources/coverage/WMS-GetFeatureInfo.xml b/teamengine-web/src/main/resources/coverage/WMS-GetFeatureInfo.xml index 5207dbdb8..b6aa038cf 100644 --- a/teamengine-web/src/main/resources/coverage/WMS-GetFeatureInfo.xml +++ b/teamengine-web/src/main/resources/coverage/WMS-GetFeatureInfo.xml @@ -1,4 +1,24 @@ + + text/xml diff --git a/teamengine-web/src/main/resources/coverage/WMS-GetMap.xml b/teamengine-web/src/main/resources/coverage/WMS-GetMap.xml index c49268b63..6ea64d452 100644 --- a/teamengine-web/src/main/resources/coverage/WMS-GetMap.xml +++ b/teamengine-web/src/main/resources/coverage/WMS-GetMap.xml @@ -1,4 +1,24 @@ + + image/png diff --git a/teamengine-web/src/main/resources/logging.properties b/teamengine-web/src/main/resources/logging.properties index 87f57b5ba..8e2f1429a 100644 --- a/teamengine-web/src/main/resources/logging.properties +++ b/teamengine-web/src/main/resources/logging.properties @@ -1,3 +1,22 @@ +### +# #%L +# TEAM Engine - Web Application +# %% +# Copyright (C) 2006 - 2024 Open Geospatial Consortium +# %% +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# #L% +### # JDK logging configuration for Tomcat # See https://tomcat.apache.org/tomcat-10.1-doc/logging.html handlers = org.apache.juli.FileHandler, java.util.logging.ConsoleHandler