Skip to content
Snippets Groups Projects
XMLSerializer.java 14.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
     */
    
    import java.io.UnsupportedEncodingException;
    import java.net.URLEncoder;
    import java.util.Iterator;
    
    import uws.UWSException;
    import uws.job.ErrorSummary;
    import uws.job.JobList;
    import uws.job.Result;
    import uws.job.UWSJob;
    import uws.job.user.JobOwner;
    import uws.service.UWS;
    import uws.service.UWSUrl;
    
    /**
     * Lets serializing any UWS resource in XML.
     * 
     * @author Gr&eacute;gory Mantelet (CDS)
     * @version 05/2012
     */
    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.
    	 */
    
    
    	/**
    	 * 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){
    
    			xsltPath = null;
    		else{
    			xsltPath = path.trim();
    			if (xsltPath.isEmpty())
    				xsltPath = null;
    		}
    	}
    
    	/**
    	 * <p>Gets the XML file header (xml version, encoding and the xslt style-sheet link if any).</p>
    	 * <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=[...]"</i>).
    	 */
    	public String getUWSNamespace(){
    		return "xmlns:uws=\"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\"";
    	}
    
    	/**
    	 * 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)
    
    		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").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("\" href=\"");
    
    			if (jlUrl != null && jlUrl.getRequestURL() != null)
    
    				xml.append(escapeURL(jlUrl.getRequestURL()));
    
    			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 boolean root) throws UWSException{
    
    		String name = jobsList.getName();
    		StringBuffer xml = new StringBuffer(getHeader());
    
    		xml.append("<uws:jobList").append(getUWSNamespace(true));
    		if (name != null)
    			xml.append(" name=\"").append(escapeXMLAttribute(name)).append("\"");
    		xml.append(">");
    
    		UWSUrl jobsListUrl = jobsList.getUrl();
    		Iterator<UWSJob> it = jobsList.getJobs(owner);
    		while(it.hasNext())
    			xml.append("\n\t").append(getJobRef(it.next(), jobsListUrl));
    
    		xml.append("\n</uws:jobList>");
    
    		return xml.toString();
    	}
    
    	@Override
    
    	public String getJob(final UWSJob job, final boolean root){
    		StringBuffer xml = new StringBuffer(root ? getHeader() : "");
    
    		String newLine = "\n\t";
    
    		// general information:
    		xml.append("<uws:job").append(getUWSNamespace(root)).append(">");
    		xml.append(newLine).append(getJobID(job, false));
    		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(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:
    		xml.append(newLine).append(getErrorSummary(job.getErrorSummary(), false));
    
    		tabPrefix = "";
    		return xml.append("\n</uws: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("<uws:jobRef id=\"");
    		xml.append(escapeXMLAttribute(job.getJobId()));
    		if (job.getRunId() != null && job.getRunId().length() > 0)
    			xml.append("\" runId=\"").append(escapeXMLAttribute(job.getRunId()));
    		xml.append("\" xlink:href=\"");
    
    		xml.append("\">").append(getPhase(job, false)).append("</uws:jobRef>");
    
    		return xml.toString();
    	}
    
    	@Override
    
    	public String getJobID(final UWSJob job, final boolean root){
    		return (new StringBuffer(root ? getHeader() : "")).append("<uws:jobId").append(getUWSNamespace(root)).append(">").append(escapeXMLData(job.getJobId())).append("</uws:jobId>").toString();
    
    	public String getRunID(final UWSJob job, final boolean root){
    		StringBuffer xml = new StringBuffer(root ? getHeader() : "");
    
    		xml.append("<uws:runId").append(getUWSNamespace(root));
    		if (job.getRunId() == null)
    			xml.append(" xsi:nil=\"true\" />");
    		else
    			xml.append(">").append(escapeXMLData(job.getRunId())).append("</uws:runId>");
    		return xml.toString();
    	}
    
    	@Override
    
    	public String getOwnerID(final UWSJob job, final boolean root){
    		StringBuffer xml = new StringBuffer(root ? getHeader() : "");
    
    		xml.append("<uws:ownerId").append(getUWSNamespace(root));
    		if (job.getOwner() == null)
    			xml.append(" xsi:nil=\"true\" />");
    		else
    			xml.append(">").append(escapeXMLData(job.getOwner().getPseudo())).append("</uws:ownerId>");
    		return xml.toString();
    	}
    
    	@Override
    
    	public String getPhase(final UWSJob job, final boolean root){
    		return (new StringBuffer(root ? getHeader() : "")).append("<uws:phase").append(getUWSNamespace(root)).append(">").append(job.getPhase()).append("</uws:phase>").toString();
    
    	public String getQuote(final UWSJob job, final boolean root){
    		StringBuffer xml = new StringBuffer(root ? getHeader() : "");
    
    		xml.append("<uws:quote").append(getUWSNamespace(root));
    		if (job.getQuote() <= 0)
    			xml.append(" xsi:nil=\"true\" />");
    		else
    			xml.append(">").append(job.getQuote()).append("</uws:quote>");
    		return xml.toString();
    	}
    
    	@Override
    
    	public String getStartTime(final UWSJob job, final boolean root){
    		StringBuffer xml = new StringBuffer(root ? getHeader() : "");
    
    		xml.append("<uws:startTime").append(getUWSNamespace(root));
    		if (job.getStartTime() == null)
    			xml.append(" xsi:nil=\"true\" />");
    		else
    			xml.append(">").append(UWSJob.dateFormat.format(job.getStartTime())).append("</uws:startTime>");
    		return xml.toString();
    	}
    
    	@Override
    
    	public String getEndTime(final UWSJob job, final boolean root){
    		StringBuffer xml = new StringBuffer(root ? getHeader() : "");
    
    		xml.append("<uws:endTime").append(getUWSNamespace(root));
    		if (job.getEndTime() == null)
    			xml.append(" xsi:nil=\"true\" />");
    		else
    			xml.append(">").append(UWSJob.dateFormat.format(job.getEndTime())).append("</uws:endTime>");
    		return xml.toString();
    	}
    
    	@Override
    
    	public String getDestructionTime(final UWSJob job, final boolean root){
    		StringBuffer xml = new StringBuffer(root ? getHeader() : "");
    
    		xml.append("<uws:destruction").append(getUWSNamespace(root));
    		if (job.getDestructionTime() == null)
    			xml.append(" xsi:nil=\"true\" />");
    		else
    			xml.append(">").append(UWSJob.dateFormat.format(job.getDestructionTime())).append("</uws:destruction>");
    		return xml.toString();
    	}
    
    	@Override
    
    	public String getExecutionDuration(final UWSJob job, final boolean root){
    		return (new StringBuffer(root ? getHeader() : "")).append("<uws:executionDuration").append(getUWSNamespace(root)).append(">").append(job.getExecutionDuration()).append("</uws:executionDuration>").toString();
    
    	public String getErrorSummary(final ErrorSummary error, final boolean root){
    		StringBuffer xml = new StringBuffer(root ? getHeader() : "");
    
    		xml.append(tabPrefix).append("<uws:errorSummary").append(getUWSNamespace(root));
    		if (error != null){
    			xml.append(" type=\"").append(error.getType()).append("\"").append(" hasDetail=\"").append(error.hasDetail()).append("\">");
    			xml.append("\n\t").append(tabPrefix).append("<uws:message>").append(escapeXMLData(error.getMessage())).append("</uws:message>");
    			xml.append("\n").append(tabPrefix).append("</uws:errorSummary>");
    		}else
    			xml.append(" xsi:nil=\"true\" />");
    		return xml.toString();
    	}
    
    	@Override
    
    	public String getAdditionalParameters(final UWSJob job, final boolean root){
    		StringBuffer xml = new StringBuffer(root ? getHeader() : "");
    
    		xml.append(tabPrefix).append("<uws:parameters").append(getUWSNamespace(root)).append(">");
    
    		for(String paramName : job.getAdditionalParameters())
    			xml.append(newLine).append(getAdditionalParameter(paramName, job.getAdditionalParameterValue(paramName), false));
    		xml.append("\n").append(tabPrefix).append("</uws:parameters>");
    		return xml.toString();
    	}
    
    	@Override
    
    	public String getAdditionalParameter(final String paramName, final Object paramValue, final boolean root){
    
    		if (paramName != null && paramValue != null){
    			if (root)
    				return paramValue.toString();
    			else
    				return (new StringBuffer("<uws:parameter")).append(getUWSNamespace(root)).append(" id=\"").append(escapeXMLAttribute(paramName)).append("\">").append(escapeXMLData(paramValue.toString())).append("</uws:parameter>").toString();
    		}else
    			return "";
    	}
    
    	@Override
    
    	public String getResults(final UWSJob job, final boolean root){
    		StringBuffer xml = new StringBuffer(root ? getHeader() : "");
    
    		xml.append(tabPrefix).append("<uws:results").append(getUWSNamespace(root)).append(">");
    
    		Iterator<Result> it = job.getResults();
    
    		while(it.hasNext())
    			xml.append(newLine).append(getResult(it.next(), false));
    		xml.append("\n").append(tabPrefix).append("</uws:results>");
    		return xml.toString();
    	}
    
    	@Override
    
    	public String getResult(final Result result, final boolean root){
    		StringBuffer xml = new StringBuffer(root ? getHeader() : "");
    
    		xml.append("<uws:result").append(getUWSNamespace(root)).append(" id=\"").append(escapeXMLAttribute(result.getId())).append("\"");
    		if (result.getHref() != null){
    			if (result.getType() != null)
    				xml.append(" xlink:type=\"").append(escapeXMLAttribute(result.getType())).append("\"");
    			xml.append(" xlink:href=\"").append(escapeURL(result.getHref())).append("\"");
    		}
    		if (result.getMimeType() != null)
    			xml.append(" mime=\"").append(escapeXMLAttribute(result.getMimeType())).append("\"");
    		if (result.getSize() >= 0)
    			xml.append(" size=\"").append(result.getSize()).append("\"");
    		return xml.append(" />").toString();
    	}
    
    	/* ************** */
    	/* ESCAPE METHODS */
    	/* ************** */
    	/**
    	 * <p>Escapes the content of a node (data between the open and the close tags).</p>
    	 * 
    	 * <p><i>By default: surrounds the given data by "&lt;![CDATA[" and "]]&gt;".</i></p>
    	 * 
    	 * @param data	Data to escape.
    	 * 
    	 * @return		Escaped data.
    	 */
    	public static String escapeXMLData(final String data){
    
    	}
    
    	/**
    	 * 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();
    
    			char c = value.charAt(i);
    			switch(c){
    
    				case '&':
    					encoded.append("&amp;");
    					break;
    				case '<':
    					encoded.append("&lt;");
    					break;
    				case '>':
    					encoded.append("&gt;");
    					break;
    				case '"':
    					encoded.append("&quot;");
    					break;
    				case '\'':
    					encoded.append("&#039;");
    					break;
    				default:
    					encoded.append(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){
    
    			return URLEncoder.encode(url, "UTF-8");