001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcwebservices/wps/XMLFactory.java $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005       Department of Geography, University of Bonn
006     and
007       lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035    ----------------------------------------------------------------------------*/
036    package org.deegree.ogcwebservices.wps;
037    
038    import static org.deegree.ogcbase.CommonNamespaces.WPSNS;
039    
040    import java.io.ByteArrayOutputStream;
041    import java.io.IOException;
042    import java.io.StringReader;
043    import java.io.UnsupportedEncodingException;
044    import java.net.URI;
045    import java.net.URL;
046    import java.net.URLEncoder;
047    import java.util.Iterator;
048    import java.util.List;
049    import java.util.Map;
050    
051    import org.deegree.datatypes.Code;
052    import org.deegree.datatypes.values.TypedLiteral;
053    import org.deegree.datatypes.values.ValueRange;
054    import org.deegree.framework.util.CharsetUtils;
055    import org.deegree.framework.xml.XMLFragment;
056    import org.deegree.framework.xml.XMLTools;
057    import org.deegree.model.feature.FeatureCollection;
058    import org.deegree.model.feature.FeatureException;
059    import org.deegree.model.feature.GMLFeatureAdapter;
060    import org.deegree.model.spatialschema.Envelope;
061    import org.deegree.model.spatialschema.Position;
062    import org.deegree.ogcwebservices.ExceptionReport;
063    import org.deegree.ogcwebservices.MetadataType;
064    import org.deegree.ogcwebservices.OGCWebServiceException;
065    import org.deegree.ogcwebservices.getcapabilities.Contents;
066    import org.deegree.ogcwebservices.getcapabilities.OperationsMetadata;
067    import org.deegree.ogcwebservices.getcapabilities.ServiceIdentification;
068    import org.deegree.ogcwebservices.getcapabilities.ServiceProvider;
069    import org.deegree.ogcwebservices.wps.capabilities.ProcessOfferings;
070    import org.deegree.ogcwebservices.wps.capabilities.WPSCapabilities;
071    import org.deegree.ogcwebservices.wps.capabilities.WPSCapabilitiesDocument;
072    import org.deegree.ogcwebservices.wps.describeprocess.ComplexData;
073    import org.deegree.ogcwebservices.wps.describeprocess.InputDescription;
074    import org.deegree.ogcwebservices.wps.describeprocess.LiteralInput;
075    import org.deegree.ogcwebservices.wps.describeprocess.LiteralOutput;
076    import org.deegree.ogcwebservices.wps.describeprocess.OutputDescription;
077    import org.deegree.ogcwebservices.wps.describeprocess.ProcessDescription;
078    import org.deegree.ogcwebservices.wps.describeprocess.ProcessDescriptions;
079    import org.deegree.ogcwebservices.wps.describeprocess.ProcessDescriptionsDocument;
080    import org.deegree.ogcwebservices.wps.describeprocess.SupportedCRSs;
081    import org.deegree.ogcwebservices.wps.describeprocess.SupportedComplexData;
082    import org.deegree.ogcwebservices.wps.describeprocess.SupportedUOMs;
083    import org.deegree.ogcwebservices.wps.describeprocess.ProcessDescription.DataInputs;
084    import org.deegree.ogcwebservices.wps.describeprocess.ProcessDescription.ProcessOutputs;
085    import org.deegree.ogcwebservices.wps.execute.ComplexValue;
086    import org.deegree.ogcwebservices.wps.execute.ExecuteDataInputs;
087    import org.deegree.ogcwebservices.wps.execute.ExecuteResponse;
088    import org.deegree.ogcwebservices.wps.execute.ExecuteResponseDocument;
089    import org.deegree.ogcwebservices.wps.execute.IOValue;
090    import org.deegree.ogcwebservices.wps.execute.OutputDefinition;
091    import org.deegree.ogcwebservices.wps.execute.OutputDefinitions;
092    import org.deegree.ogcwebservices.wps.execute.ProcessFailed;
093    import org.deegree.ogcwebservices.wps.execute.ProcessStarted;
094    import org.deegree.ogcwebservices.wps.execute.Status;
095    import org.deegree.ogcwebservices.wps.execute.IOValue.ComplexValueReference;
096    import org.deegree.owscommon.OWSMetadata;
097    import org.deegree.owscommon.com110.OWSAllowedValues;
098    import org.w3c.dom.Document;
099    import org.w3c.dom.Element;
100    import org.w3c.dom.Node;
101    import org.xml.sax.SAXException;
102    
103    /**
104     * XMLFactory.java
105     *
106     * Created on 08.03.2006. 23:28:46h
107     *
108     * @author <a href="mailto:christian@kiehle.org">Christian Kiehle</a>
109     * @author <a href="mailto:christian.heier@gmx.de">Christian Heier</a>
110     *
111     * @version 1.0.
112     *
113     * @since 2.0
114     */
115    public class XMLFactory extends org.deegree.owscommon.XMLFactory {
116    
117        /**
118         *
119         * @param capabilities
120         * @return an WPSCapabilitiesDocument for the capabilities
121         * @throws IOException
122         */
123        public static WPSCapabilitiesDocument export( WPSCapabilities capabilities )
124                                throws IOException {
125    
126            WPSCapabilitiesDocument capabilitiesDocument = new WPSCapabilitiesDocument();
127    
128            try {
129                capabilitiesDocument.createEmptyDocument();
130                Element root = capabilitiesDocument.getRootElement();
131    
132                ServiceIdentification serviceIdentification = capabilities.getServiceIdentification();
133                if ( serviceIdentification != null ) {
134                    appendServiceIdentification( root, serviceIdentification );
135                }
136    
137                ServiceProvider serviceProvider = capabilities.getServiceProvider();
138                if ( serviceProvider != null ) {
139                    appendServiceProvider( root, capabilities.getServiceProvider() );
140                }
141    
142                OperationsMetadata operationsMetadata = capabilities.getOperationsMetadata();
143                if ( operationsMetadata != null ) {
144                    appendOperationsMetadata( root, operationsMetadata );
145                }
146                Contents contents = capabilities.getContents();
147                if ( contents != null ) {
148                    // appendContents(root, contents);
149                }
150                ProcessOfferings processOfferings = capabilities.getProcessOfferings();
151                if ( null != processOfferings ) {
152                    appendProcessOfferings( root, processOfferings );
153                }
154    
155            } catch ( SAXException e ) {
156                LOG.logError( e.getMessage(), e );
157            }
158    
159            return capabilitiesDocument;
160        }
161    
162        /**
163         * Appends the DOM representation of the <code>wps:ProcessOfferings</code>- section to the
164         * passed <code>Element</code>.
165         *
166         * @param root
167         * @param processOfferings
168         */
169        private static void appendProcessOfferings( Element root, ProcessOfferings processOfferings ) {
170    
171            // Add a <wps:ProcessOfferings>node to the <wps:Capabilities> node
172            Element processOfferingsNode = XMLTools.appendElement( root, WPSNS, "wps:ProcessOfferings", null );
173            // Add <wps:Process> nodes to the <wps:ProcessOfferings> node
174            List<ProcessBrief> processBriefTypeList = processOfferings.getProcessBriefTypesList();
175            if ( null != processBriefTypeList && 0 != processBriefTypeList.size() ) {
176                int size = processBriefTypeList.size();
177                for ( int i = 0; i < size; i++ ) {
178                    appendProcessBriefType( processOfferingsNode, processBriefTypeList.get( i ) );
179                }
180            }
181    
182        }
183    
184        /**
185         * Appends the DOM representation of the <code>ProcessBriefType</code> instance to the passed
186         * <code>Element</code>.
187         *
188         * @param processOfferingsNode
189         * @param processBriefType
190         */
191        private static void appendProcessBriefType( Element processOfferingsNode, ProcessBrief processBriefType ) {
192    
193            // Add a <wps:Process> node to the <wps:ProcessOfferings> node
194            Element processBriefTypeNode = XMLTools.appendElement( processOfferingsNode, WPSNS, "wps:Process" );
195            // Add optional attribute "processVersion" to <wps:Process> node if
196            // present
197            String processVersion = processBriefType.getProcessVersion();
198            if ( null != processVersion && !"".equals( processVersion ) ) {
199                processBriefTypeNode.setAttribute( "processVersion", processVersion );
200            }
201    
202            // Add mandatory node <ows:Identifier>
203            Code identifier = processBriefType.getIdentifier();
204            if ( null != identifier ) {
205                appendIdentifier( processBriefTypeNode, identifier );
206            } else {
207                LOG.logError( "identifier is null." );
208            }
209    
210            // Add mandatory node <ows:Title>
211            String title = processBriefType.getTitle();
212            if ( null != title ) {
213                appendTitle( processBriefTypeNode, title );
214            } else {
215                LOG.logError( "title is null." );
216            }
217    
218            // Add optional node <ows:Abstract/>
219    
220            String _abstract = processBriefType.getAbstract();
221            if ( null != _abstract ) {
222                appendAbstract( processBriefTypeNode, _abstract );
223            }
224    
225            // Add optional nodes <ows:Metadata/>
226            List<MetadataType> metaDataTypeList = processBriefType.getMetadata();
227            if ( null != metaDataTypeList && 0 != metaDataTypeList.size() ) {
228                int size = metaDataTypeList.size();
229                for ( int i = 0; i < size; i++ ) {
230                    appendMetaDataType( processBriefTypeNode, metaDataTypeList.get( i ) );
231                }
232            }
233    
234        }
235    
236        /**
237         *
238         * @param e
239         * @param identifier
240         */
241        private static void appendIdentifier( Element e, Code identifier ) {
242    
243            String identifierString = identifier.getCode();
244    
245            if ( null != identifierString && !"".equals( identifierString ) ) {
246                XMLTools.appendElement( e, OWSNS, "ows:Identifier", identifierString );
247            } else {
248                LOG.logError( "identifier is empty." );
249            }
250    
251        }
252    
253        /**
254         *
255         * @param e
256         * @param title
257         */
258        private static void appendTitle( Element e, String title ) {
259    
260            if ( !"".equals( title ) ) {
261                XMLTools.appendElement( e, OWSNS, "ows:Title", title );
262            } else {
263                LOG.logError( "title is empty." );
264            }
265    
266        }
267    
268        /**
269         * Appends the DOM representation of the <code>MetadataType</code> instance to the passed
270         * <code>Element</code>.
271         *
272         * @param e
273         * @param metaDataType
274         */
275        private static void appendMetaDataType( Element e, MetadataType metaDataType ) {
276    
277            // Add optional node <ows:Metadata>
278            String metadataTypeValue = metaDataType.value;
279            if ( null != metadataTypeValue && !"".equals( metadataTypeValue ) ) {
280                Element metadataNode = XMLTools.appendElement( e, OWSNS, "ows:Metadata" );
281                metadataNode.setAttributeNS( XLNNS.toString(), "xlink:title", metadataTypeValue );
282            }
283    
284        }
285    
286        /**
287         *
288         * @param processDescriptions
289         * @return a ProcessDescriptionDocument for the process description
290         * @throws IOException
291         */
292        public static ProcessDescriptionsDocument export( ProcessDescriptions processDescriptions )
293                                throws IOException {
294            ProcessDescriptionsDocument processDescriptionsDocument = new ProcessDescriptionsDocument();
295            try {
296                processDescriptionsDocument.createEmptyDocument();
297                Element root = processDescriptionsDocument.getRootElement();
298                List<ProcessDescription> processDescriptionList = processDescriptions.getProcessDescription();
299                if ( null != processDescriptionList ) {
300                    int processDescriptionListSize = processDescriptionList.size();
301                    for ( int i = 0; i < processDescriptionListSize; i++ ) {
302                        ProcessDescription processDescription = processDescriptionList.get( i );
303                        appendProcessDescription( root, processDescription );
304                    }
305                }
306            } catch ( SAXException sex ) {
307                LOG.logError( sex.getMessage(), sex );
308            }
309    
310            return processDescriptionsDocument;
311        }
312    
313        /**
314         * Appends the DOM representation of the <code>ProcessDescription</code> instance to the
315         * passed <code>Element</code>..
316         *
317         * @param root
318         * @param processDescription
319         */
320        private static void appendProcessDescription( Element root, ProcessDescription processDescription ) {
321    
322            // Add a <wps:ProcessDescription> node to the <wps:ProcessDescriptions>
323            // node
324            Element processDescriptionNode = XMLTools.appendElement( root, WPSNS, "wps:ProcessDescription", null );
325    
326            String statusSupported = Boolean.toString( processDescription.isStatusSupported() );
327            processDescriptionNode.setAttribute( "statusSupported", statusSupported );
328    
329            String storeSupported = Boolean.toString( processDescription.isStoreSupported() );
330            processDescriptionNode.setAttribute( "storeSupported", storeSupported );
331    
332            String processVersion = processDescription.getProcessVersion();
333            processDescriptionNode.setAttribute( "processVersion", processVersion );
334    
335            Code identifier = processDescription.getIdentifier();
336            if ( null != identifier ) {
337                appendIdentifier( processDescriptionNode, identifier );
338            } else {
339                LOG.logError( "Identifier is null." );
340            }
341    
342            String title = processDescription.getTitle();
343            if ( null != title ) {
344                appendTitle( processDescriptionNode, title );
345            } else {
346                LOG.logError( "title is null." );
347            }
348    
349            String _abstract = processDescription.getAbstract();
350            if ( null != _abstract ) {
351                appendAbstract( processDescriptionNode, _abstract );
352            }
353    
354            Element metaDataTypeNode = null;
355    
356            MetadataType metadataType = null;
357            List<MetadataType> metaDataTypeList = processDescription.getMetadata();
358            int metaDataTypeListSize = metaDataTypeList.size();
359            for ( int i = 0; i < metaDataTypeListSize; i++ ) {
360                metadataType = metaDataTypeList.get( i );
361                metaDataTypeNode = XMLTools.appendElement( processDescriptionNode, OWSNS, "ows:Metadata" );
362                metaDataTypeNode.setAttributeNS( XLNNS.toString(), "xlink:title", metadataType.value );
363            }
364    
365            DataInputs dataInputs = processDescription.getDataInputs();
366            appendDataInputs( processDescriptionNode, dataInputs );
367    
368            ProcessOutputs processOutputs = processDescription.getProcessOutputs();
369            appendProcessOutputs( processDescriptionNode, processOutputs );
370    
371        }
372    
373        /**
374         *
375         * @param e
376         * @param _abstract
377         */
378        private static void appendAbstract( Element e, String _abstract ) {
379            if ( !"".equals( _abstract ) ) {
380                XMLTools.appendElement( e, OWSNS, "ows:Abstract", _abstract );
381            } else {
382                LOG.logError( "abstract is empty." );
383            }
384    
385        }
386    
387        /**
388         *
389         * @param processDescriptionNode
390         * @param dataInputs
391         */
392        private static void appendDataInputs( Element processDescriptionNode, DataInputs dataInputs ) {
393    
394            // Add a <wps:DataInputs> node to the <wps:ProcessDescription> node
395            Element dataInputsNode = XMLTools.appendElement( processDescriptionNode, WPSNS, "wps:DataInputs", null );
396            if ( null != dataInputs ) {
397                List<InputDescription> dataInputsList = dataInputs.getInputDescriptions();
398                InputDescription inputDescription = null;
399                int dataInputListSize = dataInputsList.size();
400                for ( int i = 0; i < dataInputListSize; i++ ) {
401                    inputDescription = dataInputsList.get( i );
402                    appendDataInput( dataInputsNode, inputDescription );
403                }
404            }
405    
406        }
407    
408        /**
409         *
410         * @param dataInputsNode
411         * @param inputDescription
412         */
413        private static void appendDataInput( Element dataInputsNode, InputDescription inputDescription ) {
414    
415            // Add a <wps:DataInput> node to the <wps:DataInputs> node
416            Element inputNode = XMLTools.appendElement( dataInputsNode, WPSNS, "wps:Input", null );
417    
418            if ( null != inputNode ) {
419    
420                Code identifier = inputDescription.getIdentifier();
421                if ( null != identifier ) {
422                    appendIdentifier( inputNode, identifier );
423                } else {
424                    LOG.logError( "identifier is null." );
425                }
426    
427                String title = inputDescription.getTitle();
428                if ( null != title ) {
429                    appendTitle( inputNode, title );
430                } else {
431                    LOG.logError( "title is null." );
432                }
433    
434                String _abstract = inputDescription.getAbstract();
435                if ( null != _abstract ) {
436                    appendAbstract( inputNode, _abstract );
437                }
438    
439                try {
440    
441                    SupportedCRSs supportedCRSs = inputDescription.getBoundingBoxData();
442                    ComplexData complexData = inputDescription.getComplexData();
443                    LiteralInput literalInput = inputDescription.getLiteralData();
444    
445                    if ( null != supportedCRSs ) {
446                        appendBoundingBoxData( inputNode, supportedCRSs );
447                    } else if ( null != complexData ) {
448                        appendComplexData( inputNode, complexData );
449                    } else if ( null != literalInput ) {
450                        appendLiteralInput( inputNode, literalInput );
451                    } else {
452                        LOG.logError( "a required datatype description is missing." );
453                    }
454    
455                } catch ( Exception e ) {
456                    LOG.logError( e.getMessage(), e );
457                }
458    
459                XMLTools.appendElement( inputNode, WPSNS, "wps:MinimumOccurs",
460                                        String.valueOf( inputDescription.getMinimumOccurs() ) );
461            }
462    
463        }
464    
465        /**
466         *
467         * @param root
468         * @param processOutputs
469         */
470        private static void appendProcessOutputs( Element root, ProcessOutputs processOutputs ) {
471    
472            if ( null != processOutputs ) {
473                // Add a <wps:ProcessOutputs> node to the <wps:ProcessDescription>
474                // node
475                Element processOutputsNode = XMLTools.appendElement( root, WPSNS, "wps:ProcessOutputs", null );
476                OutputDescription outputDescription = null;
477                List<OutputDescription> outputDescriptionList = processOutputs.getOutput();
478                int outputDescriptionListSize = outputDescriptionList.size();
479                for ( int i = 0; i < outputDescriptionListSize; i++ ) {
480                    outputDescription = outputDescriptionList.get( i );
481                    appendOutputDescription( processOutputsNode, outputDescription );
482                }
483            }
484    
485        }
486    
487        /**
488         *
489         * @param processOutputsNode
490         * @param outputDescription
491         */
492        private static void appendOutputDescription( Element processOutputsNode, OutputDescription outputDescription ) {
493    
494            if ( null != outputDescription ) {
495    
496                Element outputNode = XMLTools.appendElement( processOutputsNode, WPSNS, "wps:Output", null );
497    
498                Code identifier = outputDescription.getIdentifier();
499                if ( null != identifier ) {
500                    appendIdentifier( outputNode, identifier );
501                } else {
502                    LOG.logError( "identifier is null." );
503                }
504    
505                String title = outputDescription.getTitle();
506                if ( null != title ) {
507                    appendTitle( outputNode, title );
508                } else {
509                    LOG.logError( "title is null." );
510                }
511    
512                String _abstract = outputDescription.getAbstract();
513                if ( null != _abstract ) {
514                    appendAbstract( outputNode, _abstract );
515                }
516    
517                SupportedCRSs supportedCRSs = outputDescription.getBoundingBoxOutput();
518                ComplexData complexData = outputDescription.getComplexOutput();
519                LiteralOutput literalOutput = outputDescription.getLiteralOutput();
520    
521                if ( null != supportedCRSs ) {
522                    appendBoundingBoxOutput( outputNode, supportedCRSs );
523                } else if ( null != complexData ) {
524                    appendComplexOutput( outputNode, complexData );
525                } else if ( null != literalOutput ) {
526                    appendLiteralOutput( outputNode, literalOutput );
527                } else {
528                    LOG.logError( "a required output datatype description is missing." );
529                }
530            }
531    
532        }
533    
534        /**
535         *
536         * @param outputNode
537         * @param complexData
538         */
539        private static void appendComplexOutput( Element outputNode, ComplexData complexData ) {
540    
541            String defaultEncoding = complexData.getDefaultEncoding();
542            String defaultFormat = complexData.getDefaultFormat();
543            String defaultSchema = complexData.getDefaultSchema();
544            Element complexDataNode = XMLTools.appendElement( outputNode, WPSNS, "wps:ComplexOutput", null );
545    
546            if ( null != defaultFormat && !"".equals( defaultFormat ) ) {
547                complexDataNode.setAttribute( "defaultFormat", defaultFormat );
548            }
549            if ( null != defaultEncoding && !"".equals( defaultEncoding ) ) {
550                complexDataNode.setAttribute( "defaultEncoding", defaultEncoding );
551            }
552            if ( null != defaultSchema && !"".equals( defaultSchema ) ) {
553                complexDataNode.setAttribute( "defaultSchema", defaultSchema );
554            }
555    
556            List<SupportedComplexData> supportedComplexDataList = complexData.getSupportedComplexData();
557            int supporteComplexDataListSize = supportedComplexDataList.size();
558            for ( int i = 0; i < supporteComplexDataListSize; i++ ) {
559                appendSupportedComplexData( complexDataNode, supportedComplexDataList.get( i ) );
560            }
561    
562        }
563    
564        /**
565         *
566         * @param outputNode
567         * @param supportedCRSs
568         */
569        private static void appendBoundingBoxOutput( Element outputNode, SupportedCRSs supportedCRSs ) {
570    
571            URI defaultCrs = supportedCRSs.getDefaultCRS();
572            Element defaultCRSs = XMLTools.appendElement( outputNode, WPSNS, "wps:BoundingBoxOutput", null );
573            defaultCRSs.setAttribute( "defaultCRS", defaultCrs.toString() );
574    
575            List<URI> crsList = supportedCRSs.getCRS();
576            int crsListSize = crsList.size();
577            for ( int i = 0; i < crsListSize; i++ ) {
578                URI uri = crsList.get( i );
579                XMLTools.appendElement( defaultCRSs, WPSNS, "wps:CRS", uri.toString() );
580            }
581    
582        }
583    
584        /**
585         *
586         * @param outputNode
587         * @param literalOutput
588         */
589        private static void appendLiteralOutput( Element outputNode, LiteralOutput literalOutput ) {
590    
591            Element literalOutputNode = XMLTools.appendElement( outputNode, WPSNS, "wps:LiteralOutput", null );
592            Element owsDataType = XMLTools.appendElement( literalOutputNode, OWSNS, "ows:DataType",
593                                                          literalOutput.getDataType().getName() );
594            owsDataType.setAttribute( "ows:reference", literalOutput.getDataType().getLink().getHref().toString() );
595            Element supportedUOMsNode = XMLTools.appendElement( literalOutputNode, WPSNS, "wps:SupportedUOMs", null );
596    
597            supportedUOMsNode.setAttribute( "defaultUOM",
598                                            literalOutput.getSupportedUOMs().getDefaultUOM().getLink().getHref().toString() );
599    
600            List<OWSMetadata> supportedUOMs = literalOutput.getSupportedUOMs().getUOM();
601            int size = supportedUOMs.size();
602            for ( int i = 0; i < size; i++ ) {
603                OWSMetadata uom = supportedUOMs.get( i );
604                Element uomNode = XMLTools.appendElement( supportedUOMsNode, OWSNS, "ows:UOM", null );
605                uomNode.setAttribute( "ows:reference", uom.getLink().getHref().toString() );
606            }
607    
608        }
609    
610        /**
611         *
612         * @param inputNode
613         * @param complexData
614         */
615        private static void appendComplexData( Element inputNode, ComplexData complexData ) {
616    
617            String defaultEncoding = complexData.getDefaultEncoding();
618            String defaultFormat = complexData.getDefaultFormat();
619            String defaultSchema = complexData.getDefaultSchema();
620            Element complexDataNode = XMLTools.appendElement( inputNode, WPSNS, "wps:ComplexData", null );
621    
622            if ( null != defaultFormat && !"".equals( defaultFormat ) ) {
623                complexDataNode.setAttribute( "defaultFormat", defaultFormat );
624            }
625            if ( null != defaultEncoding && !"".equals( defaultEncoding ) ) {
626                complexDataNode.setAttribute( "defaultEncoding", defaultEncoding );
627            }
628            if ( null != defaultSchema && !"".equals( defaultSchema ) ) {
629                complexDataNode.setAttribute( "defaultSchema", defaultSchema );
630            }
631    
632            List<SupportedComplexData> supportedComplexDataList = complexData.getSupportedComplexData();
633            int supporteComplexDataListSize = supportedComplexDataList.size();
634            for ( int i = 0; i < supporteComplexDataListSize; i++ ) {
635                appendSupportedComplexData( complexDataNode, supportedComplexDataList.get( i ) );
636            }
637    
638        }
639    
640        /**
641         *
642         * @param complexDataNode
643         * @param supportedComplexData
644         */
645        private static void appendSupportedComplexData( Element complexDataNode, SupportedComplexData supportedComplexData ) {
646    
647            Element supportedComplexDataNode = XMLTools.appendElement( complexDataNode, WPSNS, "wps:SupportedComplexData",
648                                                                       null );
649    
650            XMLTools.appendElement( supportedComplexDataNode, WPSNS, "wps:Format", supportedComplexData.getFormat() );
651    
652            XMLTools.appendElement( supportedComplexDataNode, WPSNS, "wps:Encoding", supportedComplexData.getEncoding() );
653    
654            XMLTools.appendElement( supportedComplexDataNode, WPSNS, "wps:Schema", supportedComplexData.getSchema() );
655    
656        }
657    
658        /**
659         *
660         * @param inputNode
661         * @param literalInput
662         */
663        private static void appendLiteralInput( Element inputNode, LiteralInput literalInput ) {
664    
665            Element literalDataNode = XMLTools.appendElement( inputNode, WPSNS, "wps:LiteralData", null );
666            Element owsDataType = XMLTools.appendElement( literalDataNode, OWSNS, "ows:DataType",
667                                                          literalInput.getDataType().getName() );
668            owsDataType.setAttribute( "ows:reference", literalInput.getDataType().getLink().getHref().toString() );
669            appendLiteralInputTypes( literalDataNode, literalInput );
670    
671        }
672    
673        /**
674         *
675         * @param literalDataNode
676         * @param literalInput
677         */
678        private static void appendLiteralInputTypes( Element literalDataNode, LiteralInput literalInput ) {
679    
680            Element supportedUOMsNode = XMLTools.appendElement( literalDataNode, WPSNS, "wps:SupportedUOMs", null );
681    
682            SupportedUOMs supportedUOMs = literalInput.getSupportedUOMs();
683            if ( null != supportedUOMs ) {
684    
685                OWSMetadata defaultUOM = literalInput.getSupportedUOMs().getDefaultUOM();
686                if ( null != defaultUOM ) {
687                    supportedUOMsNode.setAttribute(
688                                                    "defaultUOM",
689                                                    literalInput.getSupportedUOMs().getDefaultUOM().getLink().getHref().toString() );
690                }
691    
692                List<OWSMetadata> supportedUOMsList = literalInput.getSupportedUOMs().getUOM();
693                int size = supportedUOMsList.size();
694                for ( int i = 0; i < size; i++ ) {
695                    OWSMetadata uom = supportedUOMsList.get( i );
696                    Element uomNode = XMLTools.appendElement( supportedUOMsNode, OWSNS, "ows:UOM", null );
697                    uomNode.setAttribute( "ows:reference", uom.getLink().getHref().toString() );
698                }
699            }
700    
701            // append <ows:AllowedValues> on <LiteralData>
702            OWSAllowedValues owsAllowedValues = literalInput.getAllowedValues();
703            if ( null != owsAllowedValues ) {
704                Element allowedValuesNode = XMLTools.appendElement( literalDataNode, OWSNS, "ows:AllowedValues", null );
705                TypedLiteral[] typedLiteralArray = owsAllowedValues.getOwsValues();
706                if ( null != typedLiteralArray ) {
707                    for ( int i = 0; i < typedLiteralArray.length; i++ ) {
708                        // append <ows:Value/> on <ows:AllowedValues>
709                        XMLTools.appendElement( allowedValuesNode, OWSNS, "ows:Value", typedLiteralArray[i].getValue() );
710                    }
711                }
712                // append <ows:Range> on <ows:AllowedValues>
713                ValueRange[] valueRangeArray = owsAllowedValues.getValueRanges();
714                if ( null != valueRangeArray ) {
715                    for ( int i = 0; i < valueRangeArray.length; i++ ) {
716                        Element owsRangeNode = XMLTools.appendElement( allowedValuesNode, OWSNS, "ows:Range" );
717                        String closure = valueRangeArray[i].getClosure().value;
718                        if ( null != closure ) {
719                            owsRangeNode.setAttribute( "ows:rangeClosure", closure );
720                        }
721                        String minimumValue = valueRangeArray[i].getMin().getValue();
722                        if ( null != minimumValue ) {
723                            XMLTools.appendElement( owsRangeNode, OWSNS, "ows:MinimumValue", minimumValue );
724                        }
725                        String maximumValue = valueRangeArray[i].getMax().getValue();
726                        if ( null != maximumValue ) {
727                            XMLTools.appendElement( owsRangeNode, OWSNS, "ows:MaximumValue", maximumValue );
728                        }
729                        TypedLiteral typedLiteralSpacing = valueRangeArray[i].getSpacing();
730                        if ( null != typedLiteralSpacing ) {
731                            String spacing = typedLiteralSpacing.getValue();
732                            if ( null != spacing ) {
733                                XMLTools.appendElement( owsRangeNode, OWSNS, "ows:Spacing", spacing );
734                            }
735                        }
736    
737                    }
738                }
739            }
740    
741            // append <ows:AnyValue> on <LiteralData>
742            boolean anyValueAllowed = literalInput.getAnyValue();
743            if ( false != anyValueAllowed ) {
744                XMLTools.appendElement( literalDataNode, OWSNS, "ows:AnyValue" );
745            }
746    
747            // append <ows:ValuesReference> on <LiteralData>
748            OWSMetadata owsValuesReference = literalInput.getValuesReference();
749            if ( null != owsValuesReference ) {
750                Element valuesReference = XMLTools.appendElement( literalDataNode, OWSNS, "ows:ValuesReference",
751                                                                  owsValuesReference.getName() );
752                String reference = owsValuesReference.getLink().getHref().toString();
753                if ( null != reference && !"".equals( reference ) ) {
754                    valuesReference.setAttribute( "ows:reference", reference );
755                }
756            }
757    
758            // append <ows:DefaultValue> on <LiteralData>
759            ValueRange defaultValue = literalInput.getDefaultValue();
760            if ( null != defaultValue ) {
761                Element owsRangeNode = XMLTools.appendElement( literalDataNode, OWSNS, "ows:DefaultValue" );
762                String closure = defaultValue.getClosure().value;
763                if ( null != closure ) {
764                    owsRangeNode.setAttribute( "ows:rangeClosure", closure );
765                }
766                String minimumValue = defaultValue.getMin().getValue();
767                if ( null != minimumValue ) {
768                    XMLTools.appendElement( owsRangeNode, OWSNS, "ows:MinimumValue", minimumValue );
769                }
770                String maximumValue = defaultValue.getMax().getValue();
771                if ( null != maximumValue ) {
772                    XMLTools.appendElement( owsRangeNode, OWSNS, "ows:MaximumValue", maximumValue );
773                }
774                String spacing = defaultValue.getSpacing().getValue();
775                if ( null != spacing ) {
776                    XMLTools.appendElement( owsRangeNode, OWSNS, "ows:Spacing", spacing );
777                }
778            }
779    
780        }
781    
782        /**
783         *
784         * @param inputNode
785         * @param supportedCRSs
786         */
787        private static void appendBoundingBoxData( Element inputNode, SupportedCRSs supportedCRSs ) {
788    
789            URI defaultCrs = supportedCRSs.getDefaultCRS();
790            Element defaultCRSs = XMLTools.appendElement( inputNode, WPSNS, "wps:BoundingBoxData", null );
791            defaultCRSs.setAttribute( "defaultCRS", defaultCrs.toString() );
792    
793            List<URI> crsList = supportedCRSs.getCRS();
794            int crsListSize = crsList.size();
795            for ( int i = 0; i < crsListSize; i++ ) {
796                URI uri = crsList.get( i );
797                XMLTools.appendElement( defaultCRSs, WPSNS, "wps:CRS", uri.toString() );
798    
799            }
800    
801        }
802    
803        /**
804         *
805         * @param executeResponse
806         * @return an ExecuteResponseDocument for the execute response
807         */
808        public static ExecuteResponseDocument export( ExecuteResponse executeResponse ) {
809    
810            ExecuteResponseDocument executeResponseDocument = new ExecuteResponseDocument();
811    
812            try {
813                // Prepare empty ExecuteResponseDocument
814                executeResponseDocument.createEmptyDocument();
815    
816                // Get root of execute
817                Element root = executeResponseDocument.getRootElement();
818    
819                // Append optional statusLocation attribute
820                String statusLocation = executeResponse.getStatusLocation();
821                if ( null != statusLocation ) {
822                    root.setAttribute( "statusLocation", statusLocation );
823                }
824    
825                // Append mandatory <ows:Identifier> node
826                Code identifier = executeResponse.getIdentifier();
827                if ( null != identifier ) {
828                    appendIdentifier( root, identifier );
829                } else {
830                    LOG.logError( "identifier is null." );
831                }
832    
833                // Append mandatory <Status> node
834                appendStatus( root, executeResponse.getStatus() );
835    
836                // Append optional <DataInputs> node
837                ExecuteDataInputs executeDataInputs = executeResponse.getDataInputs();
838                if ( null != executeDataInputs ) {
839                    appendExecuteDataInputs( root, executeResponse.getDataInputs() );
840                }
841    
842                // Append optional <OutputDefinitions> node
843                OutputDefinitions outputDefinitions = executeResponse.getOutputDefinitions();
844                if ( null != outputDefinitions ) {
845                    appendOutputDefinitions( root, outputDefinitions );
846                }
847    
848                // Append optional <ProcessOutputs> node
849                ExecuteResponse.ProcessOutputs processOutputs = executeResponse.getProcessOutputs();
850                if ( null != processOutputs ) {
851                    appendExecuteProcessOutputs( root, processOutputs );
852                }
853    
854            } catch ( IOException e ) {
855                LOG.logError( e.getMessage(), e );
856            } catch ( SAXException e ) {
857                LOG.logError( e.getMessage(), e );
858            }
859    
860            return executeResponseDocument;
861        }
862    
863        /**
864         *
865         * @param root
866         * @param status
867         */
868        private static void appendStatus( Element root, Status status ) {
869    
870            Element statusNode = XMLTools.appendElement( root, WPSNS, "Status" );
871    
872            String processSucceeded = status.getProcessSucceeded();
873    
874            ProcessFailed processFailed = status.getProcessFailed();
875    
876            String processAccepted = status.getProcessAccepted();
877    
878            ProcessStarted processStarted = status.getProcessStarted();
879    
880            if ( null != processSucceeded ) {
881                if ( "".equals( processSucceeded ) ) {
882                    XMLTools.appendElement( statusNode, WPSNS, "ProcessSucceeded" );
883                } else {
884                    XMLTools.appendElement( statusNode, WPSNS, "ProcessSucceeded", processSucceeded );
885                }
886            }
887    
888            else if ( null != processFailed ) {
889    
890                Element processfailedNode = XMLTools.appendElement( statusNode, WPSNS, "ProcessFailed" );
891    
892                ExceptionReport exceptionReport = processFailed.getExceptionReport();
893                if ( null != exceptionReport ) {
894                    Element execeptionReportNode = XMLTools.appendElement( processfailedNode, OWSNS, "ows:ExceptionReport" );
895                    String version = exceptionReport.getVersion();
896                    if ( null != version && !"".equals( version ) ) {
897                        execeptionReportNode.setAttribute( "version", version );
898                    }
899                    OGCWebServiceException[] ogcWebserviceExceptions = exceptionReport.getExceptions();
900                    int size = ogcWebserviceExceptions.length;
901                    if ( 0 < size ) {
902                        for ( int i = 0; i < size; i++ ) {
903                            appendException( execeptionReportNode, ogcWebserviceExceptions[i] );
904                        }
905                    }
906                }
907            }
908    
909            else if ( null != processAccepted ) {
910    
911                if ( "".equals( processAccepted ) ) {
912                    XMLTools.appendElement( statusNode, WPSNS, "ProcessAccepted" );
913                } else {
914                    XMLTools.appendElement( statusNode, WPSNS, "ProcessAccepted", processAccepted );
915                }
916            }
917    
918            else if ( null != processStarted ) {
919    
920                Element processStartedNode = null;
921                String processStartedMessage = processStarted.getValue();
922                if ( "".equals( processStartedMessage ) ) {
923                    processStartedNode = XMLTools.appendElement( statusNode, WPSNS, "ProcessStarted" );
924                } else {
925                    processStartedNode = XMLTools.appendElement( statusNode, WPSNS, "ProcessStarted", processStartedMessage );
926                }
927                int percentCompleted = processStarted.getPercentCompleted();
928                if ( 0 >= percentCompleted && percentCompleted <= 100 ) {
929                    processStartedNode.setAttribute( "PercentCompleted", String.valueOf( percentCompleted ) );
930                }
931            }
932    
933        }
934    
935        /**
936         * appends a xml representation of an <tt>OGCWebServiceException</tt> to the passed
937         * <tt>Element</tt> Overriding method of superclass because the nodes appended from that
938         * method do not conform with current ows specification
939         *
940         * @param node
941         * @param ex
942         */
943        protected static void appendException( Element node, OGCWebServiceException ex ) {
944    
945            Element exceptionNode = XMLTools.appendElement( node, OWSNS, "ows:Exception" );
946    
947            if ( null != ex.getCode() ) {
948                exceptionNode.setAttribute( "exceptionCode", ex.getCode().value );
949            }
950            String locator = ex.getLocator();
951            try {
952                if ( null != locator ) {
953                    locator = URLEncoder.encode( locator, CharsetUtils.getSystemCharset() );
954                } else {
955                    locator = "-";
956                }
957            } catch ( UnsupportedEncodingException e ) {
958                //nottin
959            }
960            exceptionNode.setAttribute( "locator", locator );
961    
962        }
963    
964        /**
965         *
966         * @param root
967         * @param executeDataInputs
968         */
969        private static void appendExecuteDataInputs( Element root, ExecuteDataInputs executeDataInputs ) {
970    
971            Map<String, IOValue> inputs = executeDataInputs.getInputs();
972    
973            if ( null != inputs ) {
974    
975                int size = inputs.size();
976    
977                if ( 0 < size ) {
978    
979                    Iterator<String> it = inputs.keySet().iterator();
980    
981                    Element dataInputsNode = XMLTools.appendElement( root, WPSNS, "DataInputs" );
982    
983                    while ( it.hasNext() ) {
984    
985                        IOValue ioValue = inputs.get( it.next() );
986    
987                        appendInput( dataInputsNode, ioValue );
988                    }
989                }
990            }
991    
992        }
993    
994        /**
995         *
996         * @param dataInputsNode
997         * @param ioValue
998         */
999        private static void appendInput( Element dataInputsNode, IOValue ioValue ) {
1000    
1001            Element inputNode = XMLTools.appendElement( dataInputsNode, WPSNS, "Input" );
1002    
1003            Code identifier = ioValue.getIdentifier();
1004            if ( null != identifier ) {
1005                appendIdentifier( inputNode, identifier );
1006            } else {
1007                LOG.logError( "identifier is null." );
1008            }
1009    
1010            String title = ioValue.getTitle();
1011            if ( null != title ) {
1012                appendTitle( inputNode, title );
1013            } else {
1014                LOG.logError( "title is null." );
1015            }
1016    
1017            String _abstract = ioValue.getAbstract();
1018            if ( null != _abstract ) {
1019                appendAbstract( inputNode, _abstract );
1020            }
1021    
1022            ComplexValue complexValue = ioValue.getComplexValue();
1023            ComplexValueReference complexValueReference = ioValue.getComplexValueReference();
1024            TypedLiteral literalValue = ioValue.getLiteralValue();
1025            Envelope boundingBoxValue = ioValue.getBoundingBoxValue();
1026    
1027            if ( null != complexValue ) {
1028                appendComplexValue( inputNode, complexValue );
1029            } else if ( null != complexValueReference ) {
1030                appendComplexValueReference( inputNode, complexValueReference );
1031            } else if ( null != literalValue ) {
1032                appendLiteralValue( inputNode, literalValue );
1033            } else if ( null != boundingBoxValue ) {
1034                appendBoundingBoxValue( inputNode, boundingBoxValue );
1035            } else {
1036                LOG.logError( "a required input element is missing." );
1037            }
1038    
1039        }
1040    
1041        /**
1042         *
1043         * @param e
1044         * @param complexValue
1045         */
1046        private static void appendComplexValue( Element e, ComplexValue complexValue ) {
1047    
1048            Element complexValueNode = XMLTools.appendElement( e, WPSNS, "ComplexValue" );
1049    
1050            String format = complexValue.getFormat();
1051            if ( null != format && !"".equals( format ) ) {
1052                complexValueNode.setAttribute( "format", format );
1053            }
1054    
1055            URI encoding = complexValue.getEncoding();
1056            if ( null != encoding ) {
1057                complexValueNode.setAttribute( "encoding", encoding.toString() );
1058            }
1059    
1060            URL schema = complexValue.getSchema();
1061            if ( null != schema ) {
1062                complexValueNode.setAttribute( "schema", schema.toString() );
1063            }
1064    
1065            Object content = complexValue.getContent();
1066    
1067            if ( content instanceof FeatureCollection ) {
1068    
1069                // TODO weird hack! are there better ways to append a
1070                // featurecollection to an element?
1071                FeatureCollection fc = (FeatureCollection) content;
1072                ByteArrayOutputStream bos = new ByteArrayOutputStream();
1073    
1074                try {
1075                    new GMLFeatureAdapter().export( fc, bos );
1076                } catch ( IOException ioe ) {
1077                    LOG.logError( "error exporting featurecollection." + ioe.getMessage());
1078                } catch ( FeatureException fe ) {
1079                    LOG.logError( "error exporting featurecollection." + fe.getMessage());
1080                }
1081    
1082                String gmlString = null;
1083                try {
1084                    gmlString = bos.toString( "UTF-8" );
1085                } catch ( UnsupportedEncodingException e1 ) {
1086                    //nottin
1087                }
1088    
1089                XMLFragment xmlFragment = null;
1090                try {
1091                    xmlFragment = new XMLFragment( new StringReader( gmlString ), XMLFragment.DEFAULT_URL );
1092                } catch ( SAXException saxe ) {
1093                    LOG.logError( "error converting featurecollection to xmlfragment." + saxe.getMessage());
1094                } catch ( IOException ioex ) {
1095                    LOG.logError( "error converting featurecollection to xmlfragment." + ioex.getMessage());
1096                }
1097    
1098                Node fcElement = xmlFragment.getRootElement();
1099    
1100                Document owner = complexValueNode.getOwnerDocument();
1101    
1102                complexValueNode.appendChild( owner.importNode( fcElement, true ) );
1103    
1104            } else {
1105                LOG.logDebug( "Content is not of type FeatureCollection. This is currently not supported." );
1106                // TODO implement output methods for complex value types other than
1107                // featurecollection
1108            }
1109    
1110        }
1111    
1112        /**
1113         *
1114         * @param inputNode
1115         * @param complexValueReference
1116         */
1117        private static void appendComplexValueReference( Element inputNode, ComplexValueReference complexValueReference ) {
1118    
1119            Element complexValueReferenceNode = XMLTools.appendElement( inputNode, WPSNS, "ComplexValueReference" );
1120    
1121            String format = complexValueReference.getFormat();
1122            if ( null != format && !"".equals( format ) ) {
1123                complexValueReferenceNode.setAttribute( "format", format );
1124            }
1125    
1126            URI encoding = complexValueReference.getEncoding();
1127            if ( null != encoding ) {
1128                complexValueReferenceNode.setAttribute( "encoding", encoding.toString() );
1129            }
1130    
1131            URL schema = complexValueReference.getSchema();
1132            if ( null != schema ) {
1133                complexValueReferenceNode.setAttribute( "schema", schema.toString() );
1134            }
1135    
1136            URL reference = complexValueReference.getReference();
1137            if ( null != reference ) {
1138                complexValueReferenceNode.setAttributeNS( OWSNS.toString(), "ows:reference", reference.toString() );
1139            }
1140    
1141        }
1142    
1143        /**
1144         *
1145         * @param inputNode
1146         * @param literalValue
1147         */
1148        private static void appendLiteralValue( Element inputNode, TypedLiteral literalValue ) {
1149    
1150            Element literalValueNode = XMLTools.appendElement( inputNode, WPSNS, "LiteralValue" );
1151    
1152            URI dataType = literalValue.getType();
1153            if ( null != dataType ) {
1154                literalValueNode.setAttribute( "dataType", dataType.toString() );
1155            }
1156    
1157            URI uom = literalValue.getUom();
1158            if ( null != uom ) {
1159                literalValueNode.setAttribute( "uom", uom.toString() );
1160            }
1161    
1162            String value = literalValue.getValue();
1163            if ( null != value && !"".equals( value ) ) {
1164                literalValueNode.setTextContent( value );
1165            }
1166    
1167        }
1168    
1169        /**
1170         *
1171         * @param inputNode
1172         * @param boundingBoxValue
1173         */
1174        private static void appendBoundingBoxValue( Element inputNode, Envelope boundingBoxValue ) {
1175    
1176            Element boundingBoxValueNode = XMLTools.appendElement( inputNode, WPSNS, "BoundingBoxValue" );
1177    
1178            String crs = boundingBoxValue.getCoordinateSystem().getIdentifier();
1179            if ( null != crs ) {
1180                boundingBoxValueNode.setAttribute( "crs", crs );
1181            }
1182    
1183            int dimensions = boundingBoxValue.getCoordinateSystem().getDimension();
1184            if ( 0 != dimensions ) {
1185                boundingBoxValueNode.setAttribute( "dimensions", String.valueOf( dimensions ) );
1186            }
1187    
1188            Position positionMin = boundingBoxValue.getMin();
1189            if ( null != positionMin ) {
1190                XMLTools.appendElement( boundingBoxValueNode, OWSNS, "ows:LowerCorner",
1191                                        String.valueOf( positionMin.getX() ) + " " + String.valueOf( positionMin.getY() ) );
1192            }
1193    
1194            Position positionMax = boundingBoxValue.getMax();
1195            if ( null != positionMax ) {
1196                XMLTools.appendElement( boundingBoxValueNode, OWSNS, "ows:UpperCorner",
1197                                        String.valueOf( positionMax.getX() ) + " " + String.valueOf( positionMax.getY() ) );
1198            }
1199    
1200        }
1201    
1202        /**
1203         *
1204         * @param root
1205         * @param outputDefintions
1206         */
1207        private static void appendOutputDefinitions( Element root, OutputDefinitions outputDefintions ) {
1208    
1209            Element outputDefinitionsNode = XMLTools.appendElement( root, WPSNS, "OutputDefinitions" );
1210    
1211            List<OutputDefinition> outputDefinitionsList = outputDefintions.getOutputDefinitions();
1212    
1213            if ( null != outputDefinitionsList ) {
1214    
1215                int size = outputDefinitionsList.size();
1216    
1217                if ( 0 < size ) {
1218                    for ( int i = 0; i < outputDefinitionsList.size(); i++ ) {
1219    
1220                        appendOutputDefinition( outputDefinitionsNode, outputDefinitionsList.get( i ) );
1221    
1222                    }
1223                }
1224            }
1225    
1226        }
1227    
1228        /**
1229         *
1230         * @param outputDefinitionsNode
1231         * @param outputDefinition
1232         */
1233        private static void appendOutputDefinition( Element outputDefinitionsNode, OutputDefinition outputDefinition ) {
1234    
1235            Element outputNode = XMLTools.appendElement( outputDefinitionsNode, WPSNS, "Output" );
1236    
1237            String format = outputDefinition.getFormat();
1238            if ( null != format && !"".equals( format ) ) {
1239                outputNode.setAttribute( "format", format );
1240            }
1241    
1242            URI encoding = outputDefinition.getEncoding();
1243            if ( null != encoding ) {
1244                outputNode.setAttribute( "encoding", encoding.toString() );
1245            }
1246    
1247            URL schema = outputDefinition.getSchema();
1248            if ( null != schema ) {
1249                outputNode.setAttribute( "schema", schema.toString() );
1250            }
1251    
1252            URI uom = outputDefinition.getUom();
1253            if ( null != uom ) {
1254                outputNode.setAttribute( "uom", uom.toString() );
1255            }
1256    
1257            Code identifier = outputDefinition.getIdentifier();
1258            if ( null != identifier ) {
1259                appendIdentifier( outputNode, identifier );
1260            } else {
1261                LOG.logError( "identifier is null." );
1262            }
1263    
1264            String title = outputDefinition.getTitle();
1265            if ( null != title ) {
1266                appendTitle( outputNode, title );
1267            } else {
1268                LOG.logError( "title is null." );
1269            }
1270    
1271            String _abstract = outputDefinition.getAbstract();
1272            if ( null != _abstract ) {
1273                appendAbstract( outputNode, _abstract );
1274            }
1275    
1276        }
1277    
1278        /**
1279         *
1280         * @param root
1281         * @param processOutputs
1282         */
1283        private static void appendExecuteProcessOutputs( Element root, ExecuteResponse.ProcessOutputs processOutputs ) {
1284    
1285            Element processOutputsNode = XMLTools.appendElement( root, WPSNS, "ProcessOutputs" );
1286    
1287            List<IOValue> processOutputsList = processOutputs.getOutputs();
1288            if ( null != processOutputsList ) {
1289    
1290                int size = processOutputsList.size();
1291                if ( 0 < size ) {
1292    
1293                    for ( int i = 0; i < size; i++ ) {
1294                        appendExecuteProcessOutput( processOutputsNode, processOutputsList.get( i ) );
1295                    }
1296                }
1297            }
1298    
1299        }
1300    
1301        /**
1302         *
1303         * @param processOutputsNode
1304         * @param processOutput
1305         */
1306        private static void appendExecuteProcessOutput( Element processOutputsNode, IOValue processOutput ) {
1307    
1308            Element outputNode = XMLTools.appendElement( processOutputsNode, WPSNS, "Output" );
1309    
1310            Code identifier = processOutput.getIdentifier();
1311            if ( null != identifier ) {
1312                appendIdentifier( outputNode, identifier );
1313            } else {
1314                LOG.logError( "identifier is null." );
1315            }
1316    
1317            String title = processOutput.getTitle();
1318            if ( null != title ) {
1319                appendTitle( outputNode, title );
1320            } else {
1321                LOG.logError( "title is null." );
1322            }
1323    
1324            String _abstract = processOutput.getAbstract();
1325            if ( null != _abstract ) {
1326                appendAbstract( outputNode, _abstract );
1327            }
1328    
1329            ComplexValue complexValue = processOutput.getComplexValue();
1330            ComplexValueReference complexValueReference = processOutput.getComplexValueReference();
1331            TypedLiteral literalValue = processOutput.getLiteralValue();
1332            Envelope boundingBoxValue = processOutput.getBoundingBoxValue();
1333    
1334            if ( null != complexValue ) {
1335                appendComplexValue( outputNode, complexValue );
1336            } else if ( null != complexValueReference ) {
1337                appendComplexValueReference( outputNode, complexValueReference );
1338            } else if ( null != literalValue ) {
1339                appendLiteralValue( outputNode, literalValue );
1340            } else if ( null != boundingBoxValue ) {
1341                appendBoundingBoxValue( outputNode, boundingBoxValue );
1342            } else {
1343                LOG.logError( "a required output element is missing." );
1344            }
1345    
1346        }
1347    
1348    }