Select Git revision
bandtrim.cpp
-
Christine Kim authored
* Adds HRSC support in socetlinescankeywords (#5669) * Adds HRSC support in socetlinescankeywords * Add test cube * Fixed tests * Converted skypt to a callable app. Converted existing Makefile tests to gtests. Removed existing Makefile tests. (#5444) * Converted skypt to a callable app. Converted existing makefile tests to gtest format and removed old makefile tests and data. Addresses #5443. * Updated contributor list to add Sarah S. Sutton. Addresses #5443. --------- Co-authored-by:
Sarah Sutton <ssutton@dhcp-10-142-214-177.uawifi.arizona.edu> * Noseam has been refactored to be callable. Makefile test has been converted to a gtest and removed. (#5600) * Noseam has been refactored to be callable. Makefile test has been converted to a gtest and removed. Addresses #5599. * Modifications to address gtest failures. Also added addtional input parameter error checking to ensure noseam exits prior to generation of temporary files. Finally modified gtests to remove the print.prt file if generated. Addresses #5599. * The explode application has been refactored to be callable and Makefile test converted to a gtest. (#5590) * Updated explode application gtest to use DefaultCube fixture instead of cube in isis/tests/data. Addresses #5557. * Cleaned up includes in default explode gtest. Added history entry to explode.xml. Addresses #5557. * Updating main.cpp and removed Makefile tests for explode conversion to callable app. Addresses #5557. * Added CHANGELOG entry for conversion of explode app to callable function. Addresses #5557. --------- Co-authored-by:
Adam Paquette <acpaquette@usgs.gov> * Isisminer has been refactored to be callable and Makefile tests converted to gtest format (#5579) * Fixed minor misspellings in error messages. Addresses #5516. * Test data added for isisminer. Addresses #5516. * Converted isisminer Makefile tests to gtest format. Addresses #5516. * Converted isisminer application to callable function. Addresses #5516. * Minor tweak to isisminer csvwriter test. Addresses #5516. * Added compareCsvLineCustomDelimiter method, specifically for isisminer testing support. Addresses #5516. * Removed isisminer Makefile tests (replaced by gtests) and updated CHANGELOG reflecting conversion of isisminer to callable app. Addresses #5516. * Replace isis cube in /isis/tests/data/isisminer/gistest with isd and label files. Minor tweaks to FunctionalTestsIsisminer.cpp. History entry added to isisminer.xml. Addresses #5516. * Minor changes for conversion of isisminer to callable app. Addresses #5516. * Had to add data file index.lbl to the .gitignore file for it to be uploaded. Addresses #5516. * Algebra has been refactored to be callable; old Makefile tests have been converted to gtests and removed. Addresses #5594. (#5597) * Photrim has been refactored to be callable; old Makefile tests have been converted to gtests and removed. (#5582) * Photrim has been converted to a callable app. Corresponding Makefile tests have been converted to gtests and removed. Addresses #5581. * Tweaks to FunctionalTestsPhotrim.cpp. Addresses #5581. * Bandtrim has been refactored to be callable; old Makefile tests have been converted to gtests. (#5572) * Bandtrim has been refactored to be callable; old Makefile tests have been removed and replaced by gtests. Addresses #5571. * Update FunctionalTestsBandtrim.cpp Minor documentation change. * Updated kaguyasp2ascii to support newer (detached) data (#5568) * Modified to work with new (detached) data * Updated changelog * Allow data specification outside current directory * Jigsaw csm error message (#5562) * Added fail-early + error message for csminit'd images without csm solve parameters * Updated changelog * Bug fix in noproj to remove persistent temporary lbl file (#5578) * Added line to close match cube in noproj.cpp. Not closing the cube resulted in a temporary "*.lbl" file that remained after running the noproj application. Addresses #5577. * CHANGELOG entry for noproj bug fix. Addresses #5577. * Added history entry in noproj.xml. Addresses #5577. * Remove restrictive validity check in caminfo (#5553) * Removed preemptive validity check for polygon * Removed unused import * Updated changelog * Qview command line Fix (#5505) * Avoid double image load when opening cubes from cmdline in qview * Added changelog entry * Revert interval change * Change qt to qt-main * Update deps and pcl cmake * Add float.h * CsmSerialNumber.trn - typo and PVL compilant fix (#5561) * Fixed typo * PVL compliant * PR feedback changes * hrsc2isis support for level 3 images (#5560) * Remove label check for level3 * update changelog * fix test * addressed PR feedback * fixed grammar * Fixed gllssi2isis to support V1.1 data (#5570) * Removed a debug output statement inadvertently left in noseam.cpp. Addresses #5660. (#5661) * Bug fixes to address incorrect handling of RADIUS in the jigsaw GUI and in the bundleout.txt file when performing a rectangular (XYZ) bundle adjustment, originally implemented in UofA OSIRIS-REx code on 2019-07-30. Addresses #5642. (#5643) * The RADIUS checkbox in the GUI is excluded when a RECTANGULAR solution is selected. * In the bundleout.txt file, for rectangular solutions, 1) RADIUS is set to N/A in the SOLVE OPTIONS section; and 2) the POINTS UNCERTAINTY SECTION was fixed to properly display adjusted point uncertainty statistics with Error Propagation turned on. * Spacing for point labels was cleaned up in the INPUT: GLOBAL IMAGE PARAMETER UNCERTAINTIES section. * Finally, a slight modification was added to the FunctionalTestJigsawBundleXYZ ctest to verify that RADIUS is N/A in a RECTANGULAR solution. * Updated kaguyasp2ascii to support newer (detached) data (#5568) * Modified to work with new (detached) data * Updated changelog * Allow data specification outside current directory * Speeds up FunctionalTestCamstatsDefaultParameters (#5647) * speed up camstats * add changelog * fixes photomet not accepting backplanes (#5658) * fixes photomet not accepting backplanes * fix changelog * Converted to gtests * Add input cube attributes * Convert dstripe to gtests (#5665) * Convert dstripe to gtests * add changelog * Fixed build error * trigger build * trigger build * Update docs --------- Co-authored-by:
Amy Stamile <74275278+amystamile-usgs@users.noreply.github.com> Co-authored-by:
Sarah Sutton <ssutton@lpl.arizona.edu> Co-authored-by:
Sarah Sutton <ssutton@dhcp-10-142-214-177.uawifi.arizona.edu> Co-authored-by:
kledmundson <6842706+kledmundson@users.noreply.github.com> Co-authored-by:
Adam Paquette <acpaquette@usgs.gov> Co-authored-by:
Austin Sanders <arsanders@usgs.gov> Co-authored-by:
Shin-ya Murakami <86389420+murashinln@users.noreply.github.com>
Christine Kim authored* Adds HRSC support in socetlinescankeywords (#5669) * Adds HRSC support in socetlinescankeywords * Add test cube * Fixed tests * Converted skypt to a callable app. Converted existing Makefile tests to gtests. Removed existing Makefile tests. (#5444) * Converted skypt to a callable app. Converted existing makefile tests to gtest format and removed old makefile tests and data. Addresses #5443. * Updated contributor list to add Sarah S. Sutton. Addresses #5443. --------- Co-authored-by:
Sarah Sutton <ssutton@dhcp-10-142-214-177.uawifi.arizona.edu> * Noseam has been refactored to be callable. Makefile test has been converted to a gtest and removed. (#5600) * Noseam has been refactored to be callable. Makefile test has been converted to a gtest and removed. Addresses #5599. * Modifications to address gtest failures. Also added addtional input parameter error checking to ensure noseam exits prior to generation of temporary files. Finally modified gtests to remove the print.prt file if generated. Addresses #5599. * The explode application has been refactored to be callable and Makefile test converted to a gtest. (#5590) * Updated explode application gtest to use DefaultCube fixture instead of cube in isis/tests/data. Addresses #5557. * Cleaned up includes in default explode gtest. Added history entry to explode.xml. Addresses #5557. * Updating main.cpp and removed Makefile tests for explode conversion to callable app. Addresses #5557. * Added CHANGELOG entry for conversion of explode app to callable function. Addresses #5557. --------- Co-authored-by:
Adam Paquette <acpaquette@usgs.gov> * Isisminer has been refactored to be callable and Makefile tests converted to gtest format (#5579) * Fixed minor misspellings in error messages. Addresses #5516. * Test data added for isisminer. Addresses #5516. * Converted isisminer Makefile tests to gtest format. Addresses #5516. * Converted isisminer application to callable function. Addresses #5516. * Minor tweak to isisminer csvwriter test. Addresses #5516. * Added compareCsvLineCustomDelimiter method, specifically for isisminer testing support. Addresses #5516. * Removed isisminer Makefile tests (replaced by gtests) and updated CHANGELOG reflecting conversion of isisminer to callable app. Addresses #5516. * Replace isis cube in /isis/tests/data/isisminer/gistest with isd and label files. Minor tweaks to FunctionalTestsIsisminer.cpp. History entry added to isisminer.xml. Addresses #5516. * Minor changes for conversion of isisminer to callable app. Addresses #5516. * Had to add data file index.lbl to the .gitignore file for it to be uploaded. Addresses #5516. * Algebra has been refactored to be callable; old Makefile tests have been converted to gtests and removed. Addresses #5594. (#5597) * Photrim has been refactored to be callable; old Makefile tests have been converted to gtests and removed. (#5582) * Photrim has been converted to a callable app. Corresponding Makefile tests have been converted to gtests and removed. Addresses #5581. * Tweaks to FunctionalTestsPhotrim.cpp. Addresses #5581. * Bandtrim has been refactored to be callable; old Makefile tests have been converted to gtests. (#5572) * Bandtrim has been refactored to be callable; old Makefile tests have been removed and replaced by gtests. Addresses #5571. * Update FunctionalTestsBandtrim.cpp Minor documentation change. * Updated kaguyasp2ascii to support newer (detached) data (#5568) * Modified to work with new (detached) data * Updated changelog * Allow data specification outside current directory * Jigsaw csm error message (#5562) * Added fail-early + error message for csminit'd images without csm solve parameters * Updated changelog * Bug fix in noproj to remove persistent temporary lbl file (#5578) * Added line to close match cube in noproj.cpp. Not closing the cube resulted in a temporary "*.lbl" file that remained after running the noproj application. Addresses #5577. * CHANGELOG entry for noproj bug fix. Addresses #5577. * Added history entry in noproj.xml. Addresses #5577. * Remove restrictive validity check in caminfo (#5553) * Removed preemptive validity check for polygon * Removed unused import * Updated changelog * Qview command line Fix (#5505) * Avoid double image load when opening cubes from cmdline in qview * Added changelog entry * Revert interval change * Change qt to qt-main * Update deps and pcl cmake * Add float.h * CsmSerialNumber.trn - typo and PVL compilant fix (#5561) * Fixed typo * PVL compliant * PR feedback changes * hrsc2isis support for level 3 images (#5560) * Remove label check for level3 * update changelog * fix test * addressed PR feedback * fixed grammar * Fixed gllssi2isis to support V1.1 data (#5570) * Removed a debug output statement inadvertently left in noseam.cpp. Addresses #5660. (#5661) * Bug fixes to address incorrect handling of RADIUS in the jigsaw GUI and in the bundleout.txt file when performing a rectangular (XYZ) bundle adjustment, originally implemented in UofA OSIRIS-REx code on 2019-07-30. Addresses #5642. (#5643) * The RADIUS checkbox in the GUI is excluded when a RECTANGULAR solution is selected. * In the bundleout.txt file, for rectangular solutions, 1) RADIUS is set to N/A in the SOLVE OPTIONS section; and 2) the POINTS UNCERTAINTY SECTION was fixed to properly display adjusted point uncertainty statistics with Error Propagation turned on. * Spacing for point labels was cleaned up in the INPUT: GLOBAL IMAGE PARAMETER UNCERTAINTIES section. * Finally, a slight modification was added to the FunctionalTestJigsawBundleXYZ ctest to verify that RADIUS is N/A in a RECTANGULAR solution. * Updated kaguyasp2ascii to support newer (detached) data (#5568) * Modified to work with new (detached) data * Updated changelog * Allow data specification outside current directory * Speeds up FunctionalTestCamstatsDefaultParameters (#5647) * speed up camstats * add changelog * fixes photomet not accepting backplanes (#5658) * fixes photomet not accepting backplanes * fix changelog * Converted to gtests * Add input cube attributes * Convert dstripe to gtests (#5665) * Convert dstripe to gtests * add changelog * Fixed build error * trigger build * trigger build * Update docs --------- Co-authored-by:
Amy Stamile <74275278+amystamile-usgs@users.noreply.github.com> Co-authored-by:
Sarah Sutton <ssutton@lpl.arizona.edu> Co-authored-by:
Sarah Sutton <ssutton@dhcp-10-142-214-177.uawifi.arizona.edu> Co-authored-by:
kledmundson <6842706+kledmundson@users.noreply.github.com> Co-authored-by:
Adam Paquette <acpaquette@usgs.gov> Co-authored-by:
Austin Sanders <arsanders@usgs.gov> Co-authored-by:
Shin-ya Murakami <86389420+murashinln@users.noreply.github.com>
XMLSerializer.java 21.66 KiB
package uws.job.serializer;
/*
* This file is part of UWSLibrary.
*
* UWSLibrary is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* UWSLibrary is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with UWSLibrary. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2012-2017 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
* Astronomisches Rechen Institut (ARI)
*/
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Iterator;
import uws.ISO8601Format;
import uws.UWSException;
import uws.job.ErrorSummary;
import uws.job.JobList;
import uws.job.Result;
import uws.job.UWSJob;
import uws.job.jobInfo.JobInfo;
import uws.job.serializer.filter.JobListRefiner;
import uws.job.user.JobOwner;
import uws.service.UWS;
import uws.service.UWSUrl;
import uws.service.request.UploadFile;
/**
* Lets serializing any UWS resource in XML.
*
* @author Grégory Mantelet (CDS;ARI)
* @version 4.3 (10/2017)
*/
public class XMLSerializer extends UWSSerializer {
private static final long serialVersionUID = 1L;
/** Tab to add just before each next XML node. */
protected String tabPrefix = "";
/** The path of the XSLT style-sheet. */
protected String xsltPath = null;
/**
* Builds a XML serializer.
*/
public XMLSerializer(){
;
}
/**
* Builds a XML serializer with a XSLT link.
*
* @param xsltPath Path of a XSLT style-sheet.
*/
public XMLSerializer(final String xsltPath){
this.xsltPath = xsltPath;
}
/**
* Gets the path/URL of the XSLT style-sheet to use.
*
* @return XSLT path/url.
*/
public final String getXSLTPath(){
return xsltPath;
}
/**
* Sets the path/URL of the XSLT style-sheet to use.
*
* @param path The new XSLT path/URL.
*/
public final void setXSLTPath(final String path){
if (path == null)
xsltPath = null;
else{
xsltPath = path.trim();
if (xsltPath.isEmpty())
xsltPath = null;
}
}
/**
* Gets the XML file header (xml version, encoding and the xslt
* style-sheet link if any).
*
* <p>
* It is always called by the implementation of the UWSSerializer functions
* if their boolean parameter (<i>root</i>) is <i>true</i>.
* </p>
*
* @return The XML file header.
*/
public String getHeader(){
StringBuffer xmlHeader = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
if (xsltPath != null)
xmlHeader.append("<?xml-stylesheet type=\"text/xsl\" href=\"").append(escapeXMLAttribute(xsltPath)).append("\"?>\n");
return xmlHeader.toString();
}
/**
* Gets all UWS namespaces declarations needed for an XML representation of
* a UWS object.
*
* @return The UWS namespaces: <br /> (i.e. <i>= "xmlns:uws=[...]
* xmlns:xlink=[...] xmlns:xs=[...] xmlns:xsi=[...]
* xsi:schemaLocation=[...]"</i>).
*/
public String getUWSNamespace(){
return "xmlns=\"http://www.ivoa.net/xml/UWS/v1.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.ivoa.net/xml/UWS/v1.0 http://www.ivoa.net/xml/UWS/v1.0 http://www.w3.org/1999/xlink http://www.w3.org/1999/xlink.xsd http://www.w3.org/2001/XMLSchema http://www.w3.org/2001/XMLSchema.xsd\"";
}
/**
* Gets the node attributes which declare the UWS namespace.
*
* @param root <i>false</i> if the attribute to serialize will be included
* in a top level serialization (for a job attribute: job),
* <i>true</i> otherwise.
*
* @return "" if <i>root</i> is <i>false</i>, " "+UWSNamespace
* otherwise.
*
* @see #getUWSNamespace()
*/
protected final String getUWSNamespace(boolean root){
if (root)
return " " + getUWSNamespace();
else
return "";
}
@Override
public final String getMimeType(){
return MIME_TYPE_XML;
}
@Override
public String getUWS(final UWS uws, final JobOwner user){
String name = uws.getName(), description = uws.getDescription();
StringBuffer xml = new StringBuffer(getHeader());
xml.append("<uws version=\"").append(UWS.VERSION).append('"').append(getUWSNamespace(true));
if (name != null)
xml.append(" name=\"").append(escapeXMLAttribute(name)).append('"');
xml.append(">\n");
if (description != null)
xml.append("\t<description>\n").append(escapeXMLData(description)).append("\n\t</description>\n");
xml.append("\t<jobLists>\n");
for(JobList jobList : uws){
UWSUrl jlUrl = jobList.getUrl();
xml.append("\t\t<jobListRef name=\"").append(escapeXMLAttribute(jobList.getName())).append('"');
/* The XLink attributes are optional. So if no URL is available for
* this Job List reference, none is written here: */
if (jlUrl != null && jlUrl.getRequestURL() != null)
xml.append(" xlink:type=\"simple\" xlink:href=\"").append(escapeXMLAttribute(jlUrl.getRequestURL())).append('"');
xml.append(" />\n");
}
xml.append("\t</jobLists>\n");
xml.append("</uws>\n");
return xml.toString();
}
@Override
public String getJobList(final JobList jobsList, final JobOwner owner, final JobListRefiner listRefiner, final boolean root) throws Exception{
StringBuffer xml = new StringBuffer(getHeader());
xml.append("<jobs version=\"").append(UWS.VERSION).append('"').append(getUWSNamespace(true));
/* NOTE: NO ATTRIBUTE "name" IN THE XML SCHEMA!
* String name = jobsList.getName();
* if (name != null)
* xml.append(" name=\"").append(escapeXMLAttribute(name)).append("\"");
*/
xml.append('>');
UWSUrl jobsListUrl = jobsList.getUrl();
// Security filter: retrieve only the jobs of the specified owner:
Iterator<UWSJob> it = jobsList.getJobs(owner);
/* User filter: filter the jobs in function of filters specified by the
* user: */
if (listRefiner != null)
it = listRefiner.refine(it);
// Append the jobs' description:
while(it.hasNext())
xml.append("\n\t").append(getJobRef(it.next(), jobsListUrl));
xml.append("\n</jobs>");
return xml.toString();
}
@Override
public String getJob(final UWSJob job, final boolean root) throws UWSException{
StringBuffer xml = new StringBuffer(root ? getHeader() : "");
String newLine = "\n\t";
// general information:
xml.append("<job version=\"").append(UWS.VERSION).append('"').append(getUWSNamespace(root)).append('>');
xml.append(newLine).append(getJobID(job, false));
if (job.getRunId() != null)
xml.append(newLine).append(getRunID(job, false));
xml.append(newLine).append(getOwnerID(job, false));
xml.append(newLine).append(getPhase(job, false));
xml.append(newLine).append(getQuote(job, false));
xml.append(newLine).append(getCreationTime(job, false));
xml.append(newLine).append(getStartTime(job, false));
xml.append(newLine).append(getEndTime(job, false));
xml.append(newLine).append(getExecutionDuration(job, false));
xml.append(newLine).append(getDestructionTime(job, false));
tabPrefix = "\t";
newLine = "\n";
// parameters:
xml.append(newLine).append(getAdditionalParameters(job, false));
// results:
xml.append(newLine).append(getResults(job, false));
// errorSummary:
if (job.getErrorSummary() != null)
xml.append(newLine).append(getErrorSummary(job.getErrorSummary(), false));
// jobInfo:
if (job.getJobInfo() != null)
xml.append(newLine).append(getJobInfo(job));
tabPrefix = "";
return xml.append("\n</job>").toString();
}
@Override
public String getJobRef(final UWSJob job, final UWSUrl jobsListUrl){
String url = null;
if (jobsListUrl != null){
jobsListUrl.setJobId(job.getJobId());
url = jobsListUrl.getRequestURL();
}
StringBuffer xml = new StringBuffer("<jobref id=\"");
// [MANDATORY] Set the job ID as an attribute:
xml.append(escapeXMLAttribute(job.getJobId())).append('"');
/* [OPTIONAL] Set the XLink attributes. If no URL is available for this
* Job reference, none is written here: */
if (url != null)
xml.append(" xlink:type=\"simple\" xlink:href=\"").append(escapeXMLAttribute(url)).append('"');
xml.append('>');
// [MANDATORY] Append the execution phase:
xml.append("\n\t\t").append(getPhase(job, false));
// [OPTIONAL] Append the RUN ID (name/label of the job set by the user), if any:
if (job.getRunId() != null)
xml.append("\n\t\t").append(getRunID(job, false));
// [OPTIONAL] Append the job owner, if any:
if (job.getOwner() != null)
xml.append("\n\t\t").append(getOwnerID(job, false));
// [OPTIONAL] Append the creation time:
xml.append("\n\t\t").append(getCreationTime(job, false));
xml.append("\n\t</jobref>");
return xml.toString();
}
@Override
public String getJobID(final UWSJob job, final boolean root){
return (new StringBuffer(root ? getHeader() : "")).append("<jobId").append(getUWSNamespace(root)).append('>').append(escapeXMLData(job.getJobId())).append("</jobId>").toString();
}
@Override
public String getRunID(final UWSJob job, final boolean root){
if (job.getRunId() != null){
StringBuffer xml = new StringBuffer(root ? getHeader() : "");
xml.append("<runId").append(getUWSNamespace(root));
xml.append('>').append(escapeXMLData(job.getRunId())).append("</runId>");
return xml.toString();
}else
return "";
}
@Override
public String getOwnerID(final UWSJob job, final boolean root){
StringBuffer xml = new StringBuffer(root ? getHeader() : "");
xml.append("<ownerId").append(getUWSNamespace(root));
if (job.getOwner() == null)
xml.append(" xsi:nil=\"true\" />");
else
xml.append('>').append(escapeXMLData(job.getOwner().getPseudo())).append("</ownerId>");
return xml.toString();
}
@Override
public String getPhase(final UWSJob job, final boolean root){
return (new StringBuffer(root ? getHeader() : "")).append("<phase").append(getUWSNamespace(root)).append('>').append(job.getPhase()).append("</phase>").toString();
}
@Override
public String getQuote(final UWSJob job, final boolean root){
StringBuffer xml = new StringBuffer(root ? getHeader() : "");
xml.append("<quote").append(getUWSNamespace(root));
if (job.getQuote() <= 0)
xml.append(" xsi:nil=\"true\" />");
else
xml.append('>').append(job.getQuote()).append("</quote>");
return xml.toString();
}
@Override
public String getCreationTime(final UWSJob job, final boolean root){
return (new StringBuffer(root ? getHeader() : "")).append("<creationTime").append(getUWSNamespace(root)).append('>').append(ISO8601Format.format(job.getCreationTime())).append("</creationTime>").toString();
}
@Override
public String getStartTime(final UWSJob job, final boolean root){
StringBuffer xml = new StringBuffer(root ? getHeader() : "");
xml.append("<startTime").append(getUWSNamespace(root));
if (job.getStartTime() == null)
xml.append(" xsi:nil=\"true\" />");
else
xml.append('>').append(ISO8601Format.format(job.getStartTime())).append("</startTime>");
return xml.toString();
}
@Override
public String getEndTime(final UWSJob job, final boolean root){
StringBuffer xml = new StringBuffer(root ? getHeader() : "");
xml.append("<endTime").append(getUWSNamespace(root));
if (job.getEndTime() == null)
xml.append(" xsi:nil=\"true\" />");
else
xml.append('>').append(ISO8601Format.format(job.getEndTime())).append("</endTime>");
return xml.toString();
}
@Override
public String getDestructionTime(final UWSJob job, final boolean root){
StringBuffer xml = new StringBuffer(root ? getHeader() : "");
xml.append("<destruction").append(getUWSNamespace(root));
if (job.getDestructionTime() == null)
xml.append(" xsi:nil=\"true\" />");
else
xml.append('>').append(ISO8601Format.format(job.getDestructionTime())).append("</destruction>");
return xml.toString();
}
@Override
public String getExecutionDuration(final UWSJob job, final boolean root){
return (new StringBuffer(root ? getHeader() : "")).append("<executionDuration").append(getUWSNamespace(root)).append('>').append(job.getExecutionDuration()).append("</executionDuration>").toString();
}
@Override
public String getErrorSummary(final ErrorSummary error, final boolean root){
if (error != null){
StringBuffer xml = new StringBuffer(root ? getHeader() : "");
xml.append(tabPrefix).append("<errorSummary").append(getUWSNamespace(root));
xml.append(" type=\"").append(error.getType()).append('"').append(" hasDetail=\"").append(error.hasDetail()).append("\">");
xml.append("\n\t").append(tabPrefix).append("<message>").append(escapeXMLData(error.getMessage())).append("</message>");
xml.append('\n').append(tabPrefix).append("</errorSummary>");
return xml.toString();
}else
return "";
}
@Override
public String getAdditionalParameters(final UWSJob job, final boolean root){
StringBuffer xml = new StringBuffer(root ? getHeader() : "");
xml.append(tabPrefix).append("<parameters").append(getUWSNamespace(root)).append(">");
String newLine = "\n\t" + tabPrefix;
for(String paramName : job.getAdditionalParameters())
xml.append(newLine).append(getAdditionalParameter(paramName, job.getAdditionalParameterValue(paramName), false));
xml.append('\n').append(tabPrefix).append("</parameters>");
return xml.toString();
}
@Override
public String getAdditionalParameter(final String paramName, final Object paramValue, final boolean root){
if (paramName != null && paramValue != null){
// If ROOT, just the value must be returned:
if (root){
if (paramValue.getClass().isArray()){
StringBuffer buf = new StringBuffer();
for(Object o : (Object[])paramValue){
if (buf.length() > 0)
buf.append(';');
buf.append(o.toString());
}
return buf.toString();
}else
return paramValue.toString();
}
// OTHERWISE, return the XML description:
else{
StringBuffer buf = new StringBuffer();
// if array (=> multiple occurrences of the parameter), each item must be one individual parameter:
if (paramValue.getClass().isArray()){
for(Object o : (Object[])paramValue){
if (buf.length() > 0)
buf.append("\n\t").append(tabPrefix);
buf.append(getAdditionalParameter(paramName, o, root));
}
}
// otherwise, just return the XML parameter description:
else{
buf.append("<parameter").append(getUWSNamespace(root)).append(" id=\"").append(escapeXMLAttribute(paramName)).append('"');
// set if it is an uploaded file:
if (paramValue instanceof UploadFile)
buf.append(" byReference=\"true");
/*
* Note:
* The attribute isPost is not supported in this library.
* This information is not stored by the UWS Library and
* so is never reported in the XML serialization of the
* job. Besides, this attribute is optional.
*/
buf.append('>').append(escapeXMLData(paramValue.toString())).append("</parameter>");
}
return buf.toString();
}
}
// If NO VALUE or NO NAME, return an empty string:
else
return "";
}
@Override
public String getResults(final UWSJob job, final boolean root){
StringBuffer xml = new StringBuffer(root ? getHeader() : "");
xml.append(tabPrefix).append("<results").append(getUWSNamespace(root)).append(">");
Iterator<Result> it = job.getResults();
String newLine = "\n\t" + tabPrefix;
while(it.hasNext())
xml.append(newLine).append(getResult(it.next(), false));
xml.append('\n').append(tabPrefix).append("</results>");
return xml.toString();
}
@Override
public String getResult(final Result result, final boolean root){
StringBuffer xml = new StringBuffer(root ? getHeader() : "");
xml.append("<result").append(getUWSNamespace(root)).append(" id=\"").append(escapeXMLAttribute(result.getId())).append('"');
/* The XLink attributes are optional. So if no URL is available, none
* will be written here: */
if (result.getHref() != null){
xml.append(" xlink:type=\"").append((result.getType() == null) ? "simple" : escapeXMLAttribute(result.getType())).append('"');
xml.append(" xlink:href=\"").append(escapeXMLAttribute(result.getHref())).append('"');
}
// Append the MIME type, if any:
if (result.getMimeType() != null)
xml.append(" mime-type=\"").append(escapeXMLAttribute(result.getMimeType())).append('"');
// Append the result size (in bytes), if any:
if (result.getSize() >= 0)
xml.append(" size=\"").append(result.getSize()).append('"');
return xml.append(" />").toString();
}
/**
* Serialize into XML the {@link JobInfo} of the given job, if any.
*
* <p><b>Important note:</b>
* By default, this function wrap the XML content returned by
* {@link JobInfo#getXML(String)} inside an XML node "jobInfo".
* To change this behavior, you should overwrite this function.
* </p>
*
* @param job The job whose the jobInfo must be serialized into XML.
*
* @return The XML serialization of the given job's jobInfo,
* or an empty string if the given job has no jobInfo.
*
* @since 4.2
*/
public String getJobInfo(final UWSJob job) throws UWSException{
if (job.getJobInfo() != null){
StringBuffer xml = new StringBuffer();
xml.append(tabPrefix).append("<jobInfo>");
xml.append("\n\t").append(tabPrefix).append(job.getJobInfo().getXML("\n\t" + tabPrefix));
xml.append('\n').append(tabPrefix).append("</jobInfo>");
return xml.toString();
}else
return "";
}
/* ************** */
/* ESCAPE METHODS */
/* ************** */
/**
* Escapes the content of a node (data between the open and the close tags).
*
* @param data Data to escape.
*
* @return Escaped data.
*/
public static String escapeXMLData(final String data){
StringBuffer encoded = new StringBuffer();
for(int i = 0; i < data.length(); i++){
char c = data.charAt(i);
switch(c){
case '&':
encoded.append("&");
break;
case '<':
encoded.append("<");
break;
case '>':
encoded.append(">");
break;
default:
encoded.append(ensureLegalXml(c));
}
}
return encoded.toString();
}
/**
* Escapes the given value of an XML attribute.
*
* @param value Value of an XML attribute.
*
* @return The escaped value.
*/
public static String escapeXMLAttribute(final String value){
StringBuffer encoded = new StringBuffer();
for(int i = 0; i < value.length(); i++){
char c = value.charAt(i);
switch(c){
case '&':
encoded.append("&");
break;
case '<':
encoded.append("<");
break;
case '>':
encoded.append(">");
break;
case '"':
encoded.append(""");
break;
default:
encoded.append(ensureLegalXml(c));
}
}
return encoded.toString();
}
/**
* Escapes the given URL.
*
* @param url URL to escape.
*
* @return The escaped URL.
*
* @see URLEncoder
* @see #escapeXMLAttribute(String)
*/
public static String escapeURL(final String url){
try{
return URLEncoder.encode(url, "UTF-8");
}catch(UnsupportedEncodingException e){
return escapeXMLAttribute(url);
}
}
/**
* <p>Returns a legal XML character corresponding to an input character.
* Certain characters are simply illegal in XML (regardless of encoding).
* If the input character is legal in XML, it is returned;
* otherwise some other weird but legal character
* (currently the inverted question mark, "\u00BF") is returned instead.</p>
*
* <p><i>Note:
* copy of the STILTS VOSerializer.ensureLegalXml(char) function.
* </i></p>
*
* @param c input character
* @return legal XML character, <code>c</code> if possible
*
* @since 4.1
*/
public static char ensureLegalXml(char c){
return ((c >= '\u0020' && c <= '\uD7FF') || (c >= '\uE000' && c <= '\uFFFD') || ((c) == 0x09 || (c) == 0x0A || (c) == 0x0D)) ? c : '\u00BF';
}
/** Regular expression for the first character of a valid XML node name.
* <p><i>Note:
* This rule comes from the XML 1.1 standard by the W3C:
* <a href="https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-NameStartChar">https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-NameStartChar</a>
* </i></p>
* @since 4.2 */
private final static String XML_START_NODE_NAME_REGEX = ":A-Z_a-z\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\x{2FF}\\x{370}-\\x{37D}\\x{37F}-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD\\x{10000}-\\x{EFFFF}";
/**
* Regular expression of a whole valid XML node name.
* <p><i>Note:
* This rule comes from the XML 1.1 standard by the W3C:
* <a href="https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-Name">https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-Name</a>
* </i></p>
* @since 4.2 */
private final static String XML_NODE_NAME_REGEX = "[" + XML_START_NODE_NAME_REGEX + "][" + XML_START_NODE_NAME_REGEX + "\\-.0-9\\xB7\\u0300-\\u036F\\u203F-\\u2040]*";
/**
* Determine whether the given name is a valid XML node name
* according to the W3C (XML 1.1).
*
* <p><i>Note:
* In addition of validating the given name against the regular expression
* provided by the W3C (see {@link #XML_NODE_NAME_REGEX}), this function
* ensures the given name does not start with "XML" according to the
* following W3C note:
* <a href="https://www.w3.org/TR/2006/REC-xml11-20060816/#dt-name">https://www.w3.org/TR/2006/REC-xml11-20060816/#dt-name</a>
* </i></p>
*
* @param nodeName XML node name to test.
*
* @return <code>true</code> if the given node name is valid,
* <code>false</code> otherwise.
*
* @since 4.2
*/
public static boolean isValidXMLNodeName(final String nodeName){
return nodeName.matches(XML_NODE_NAME_REGEX) && !nodeName.toLowerCase().startsWith("xml");
}
}