masterfix DEV300: #i10000# build fix
[LibreOffice.git] / forms / source / xforms / submission.cxx
blobb61ad498933e12adad09cd93b3348280b20aa510
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_forms.hxx"
30 #include "submission.hxx"
32 #include "model.hxx"
33 #include "binding.hxx"
34 #include "mip.hxx"
35 #include "evaluationcontext.hxx"
36 #include "unohelper.hxx"
37 #include "submission/submission_put.hxx"
38 #include "submission/submission_post.hxx"
39 #include "submission/submission_get.hxx"
41 #include <rtl/ustring.hxx>
42 #include <rtl/ustrbuf.hxx>
44 #include <com/sun/star/uno/Sequence.hxx>
45 #include <com/sun/star/uno/Reference.hxx>
46 #include <com/sun/star/xforms/XModel.hpp>
47 #include <com/sun/star/uno/RuntimeException.hpp>
48 #include <com/sun/star/xml/xpath/XXPathObject.hpp>
49 #include <com/sun/star/container/XNameAccess.hpp>
50 #include <com/sun/star/xml/xpath/XPathObjectType.hpp>
51 #include <com/sun/star/xml/dom/XNodeList.hpp>
52 #include <com/sun/star/xml/dom/XDocument.hpp>
53 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
54 #include <com/sun/star/xml/dom/XDocumentFragment.hpp>
55 #include <com/sun/star/xml/dom/NodeType.hpp>
56 #include <com/sun/star/task/XInteractionHandler.hpp>
57 #include <com/sun/star/task/XInteractionRequest.hpp>
58 #include <com/sun/star/task/XInteractionContinuation.hpp>
59 #include <com/sun/star/xforms/InvalidDataOnSubmitException.hpp>
60 #include <com/sun/star/frame/XFrame.hpp>
61 #include <cppuhelper/typeprovider.hxx>
62 #include <comphelper/propertysetinfo.hxx>
63 #include <comphelper/interaction.hxx>
64 #include <unotools/processfactory.hxx>
65 #include <memory>
70 using rtl::OUString;
71 using rtl::OUStringBuffer;
72 using com::sun::star::beans::UnknownPropertyException;
73 using com::sun::star::beans::PropertyVetoException;
74 using com::sun::star::lang::IllegalArgumentException;
75 using com::sun::star::util::VetoException;
76 using com::sun::star::form::submission::XSubmissionVetoListener;
77 using com::sun::star::lang::WrappedTargetException;
78 using com::sun::star::lang::NoSupportException;
79 using com::sun::star::task::XInteractionHandler;
80 using com::sun::star::task::XInteractionRequest;
81 using com::sun::star::task::XInteractionContinuation;
82 using com::sun::star::xforms::XModel;
83 using com::sun::star::xforms::InvalidDataOnSubmitException;
84 using com::sun::star::container::XNameAccess;
85 using com::sun::star::xml::xpath::XXPathObject;
86 using com::sun::star::xml::xpath::XPathObjectType;
87 using com::sun::star::frame::XFrame;
88 using xforms::Submission;
89 using xforms::Model;
90 using xforms::MIP;
91 using std::auto_ptr;
93 using namespace com::sun::star::uno;
94 using namespace com::sun::star::lang;
95 using namespace com::sun::star::xml::dom;
97 Submission::Submission() :
98 msID(),
99 msBind(),
100 maRef(),
101 msAction(),
102 msMethod(),
103 msVersion(),
104 mbIndent(),
105 msMediaType(),
106 msEncoding(),
107 mbOmitXmlDeclaration(),
108 mbStandalone(),
109 msCDataSectionElement(),
110 msReplace( OUSTRING("none") ),
111 msSeparator(),
112 msIncludeNamespacePrefixes(),
113 m_aFactory(utl::getProcessServiceFactory())
115 initializePropertySet();
118 Submission::~Submission() throw()
122 Reference<XModel> Submission::getModel() const
124 return mxModel;
127 void Submission::setModel( const Reference<XModel>& xModel )
129 mxModel = xModel;
132 OUString Submission::getID() const
134 return msID;
137 void Submission::setID( const OUString& sID )
139 msID = sID;
142 OUString Submission::getBind() const
144 return msBind;
147 void Submission::setBind( const OUString& sBind )
149 msBind = sBind;
152 OUString Submission::getRef() const
154 return maRef.getExpression();
157 void Submission::setRef( const OUString& sRef )
159 maRef.setExpression( sRef );
162 OUString Submission::getAction() const
164 return msAction;
167 void Submission::setAction( const OUString& sAction )
169 msAction = sAction;
172 OUString Submission::getMethod() const
174 return msMethod;
177 void Submission::setMethod( const OUString& sMethod )
179 msMethod = sMethod;
182 OUString Submission::getVersion() const
184 return msVersion;
187 void Submission::setVersion( const OUString& sVersion )
189 msVersion = sVersion;
192 bool Submission::getIndent() const
194 return mbIndent;
197 void Submission::setIndent( bool bIndent )
199 mbIndent = bIndent;
202 OUString Submission::getMediaType() const
204 return msMediaType;
207 void Submission::setMediaType( const OUString& sMediaType )
209 msMediaType = sMediaType;
212 OUString Submission::getEncoding() const
214 return msEncoding;
217 void Submission::setEncoding( const OUString& sEncoding )
219 msEncoding = sEncoding;
222 bool Submission::getOmitXmlDeclaration() const
224 return mbOmitXmlDeclaration;
227 void Submission::setOmitXmlDeclaration( bool bOmitXmlDeclaration )
229 mbOmitXmlDeclaration = bOmitXmlDeclaration;
232 bool Submission::getStandalone() const
234 return mbStandalone;
237 void Submission::setStandalone( bool bStandalone )
239 mbStandalone = bStandalone;
242 OUString Submission::getCDataSectionElement() const
244 return msCDataSectionElement;
247 void Submission::setCDataSectionElement( const OUString& sCDataSectionElement )
249 msCDataSectionElement = sCDataSectionElement;
252 OUString Submission::getReplace() const
254 return msReplace;
257 void Submission::setReplace( const OUString& sReplace )
259 msReplace = sReplace;
262 OUString Submission::getSeparator() const
264 return msSeparator;
267 void Submission::setSeparator( const OUString& sSeparator )
269 msSeparator = sSeparator;
272 Sequence< OUString > Submission::getIncludeNamespacePrefixes() const
274 return msIncludeNamespacePrefixes;
277 void Submission::setIncludeNamespacePrefixes( const Sequence< OUString >& rIncludeNamespacePrefixes )
279 msIncludeNamespacePrefixes = rIncludeNamespacePrefixes;
282 bool Submission::doSubmit( const Reference< XInteractionHandler >& xHandler )
284 liveCheck();
286 // construct XXPathObject for submission doc; use bind in preference of ref
287 EvaluationContext aEvalContext;
288 ComputedExpression aExpression;
289 if( msBind.getLength() != 0 )
291 Binding* pBinding = Binding::getBinding( mxModel->getBinding(msBind) );
292 if( pBinding != NULL )
294 aExpression.setExpression( pBinding->getBindingExpression() );
295 aEvalContext = pBinding->getEvaluationContext();
297 // TODO: else: illegal binding name -> raise error
299 else if( maRef.getExpression().getLength() != 0 )
301 aExpression.setExpression( maRef.getExpression() );
302 aEvalContext = Model::getModel( mxModel )->getEvaluationContext();
304 else
306 aExpression.setExpression( OUSTRING( "/" ) );
307 aEvalContext = Model::getModel( mxModel )->getEvaluationContext();
309 aExpression.evaluate( aEvalContext );
310 Reference<XXPathObject> xResult = aExpression.getXPath();
311 OSL_ENSURE( xResult.is(), "no result?" );
313 // early out if we have not obtained any result
314 if( ! xResult.is() )
315 return false;
318 // Reference< XNodeList > aList = xResult->getNodeList();
319 OUString aMethod = getMethod();
321 // strip whitespace-only text node for get submission
322 Reference< XDocumentFragment > aFragment = createSubmissionDocument(
323 xResult, aMethod.equalsIgnoreAsciiCaseAscii("get"));
325 // submit result; set encoding, etc.
326 auto_ptr<CSubmission> xSubmission;
327 if (aMethod.equalsIgnoreAsciiCaseAscii("PUT"))
328 xSubmission = auto_ptr<CSubmission>(
329 new CSubmissionPut( getAction(), aFragment));
330 else if (aMethod.equalsIgnoreAsciiCaseAscii("post"))
331 xSubmission = auto_ptr<CSubmission>(
332 new CSubmissionPost( getAction(), aFragment));
333 else if (aMethod.equalsIgnoreAsciiCaseAscii("get"))
334 xSubmission = auto_ptr<CSubmission>(
335 new CSubmissionGet( getAction(), aFragment));
336 else
338 OSL_ENSURE(sal_False, "Unsupported xforms submission method");
339 return false;
342 xSubmission->setEncoding(getEncoding());
343 CSubmission::SubmissionResult aResult = xSubmission->submit( xHandler );
345 if (aResult == CSubmission::SUCCESS)
347 Reference< XDocument > aInstanceDoc = getInstanceDocument(xResult);
348 aResult = xSubmission->replace(getReplace(), aInstanceDoc, Reference< XFrame >());
351 return ( aResult == CSubmission::SUCCESS );
354 Sequence<sal_Int8> Submission::getUnoTunnelID()
356 static cppu::OImplementationId aImplementationId;
357 return aImplementationId.getImplementationId();
360 Submission* Submission::getSubmission(
361 const Reference<XPropertySet>& xPropertySet )
363 Reference<XUnoTunnel> xTunnel( xPropertySet, UNO_QUERY );
364 return xTunnel.is()
365 ? reinterpret_cast<Submission*>(
366 xTunnel->getSomething( getUnoTunnelID() ) )
367 : NULL;
375 void Submission::liveCheck()
376 throw( RuntimeException )
378 bool bValid = mxModel.is();
380 if( ! bValid )
381 throw RuntimeException();
384 Model* Submission::getModelImpl() const
386 Model* pModel = NULL;
387 if( mxModel.is() )
388 pModel = Model::getModel( mxModel );
389 return pModel;
394 // Property-Set implementation
397 #define HANDLE_ID 0
398 #define HANDLE_Bind 1
399 #define HANDLE_Ref 2
400 #define HANDLE_Action 3
401 #define HANDLE_Method 4
402 #define HANDLE_Version 5
403 #define HANDLE_Indent 6
404 #define HANDLE_MediaType 7
405 #define HANDLE_Encoding 8
406 #define HANDLE_OmitXmlDeclaration 9
407 #define HANDLE_Standalone 10
408 #define HANDLE_CDataSectionElement 11
409 #define HANDLE_Replace 12
410 #define HANDLE_Separator 13
411 #define HANDLE_IncludeNamespacePrefixes 14
412 #define HANDLE_Model 15
414 #define REGISTER_PROPERTY( property, type ) \
415 registerProperty( PROPERTY( property, type ), \
416 new DirectPropertyAccessor< Submission, type >( this, &Submission::set##property, &Submission::get##property ) );
418 #define REGISTER_PROPERTY_BOOL( property ) \
419 registerProperty( PROPERTY( property, bool ), \
420 new BooleanPropertyAccessor< Submission, bool >( this, &Submission::set##property, &Submission::get##property ) );
422 void Submission::initializePropertySet()
424 REGISTER_PROPERTY ( ID, OUString );
425 REGISTER_PROPERTY ( Bind, OUString );
426 REGISTER_PROPERTY ( Ref, OUString );
427 REGISTER_PROPERTY ( Action, OUString );
428 REGISTER_PROPERTY ( Method, OUString );
429 REGISTER_PROPERTY ( Version, OUString );
430 REGISTER_PROPERTY_BOOL( Indent );
431 REGISTER_PROPERTY ( MediaType, OUString );
432 REGISTER_PROPERTY ( Encoding, OUString );
433 REGISTER_PROPERTY_BOOL( OmitXmlDeclaration );
434 REGISTER_PROPERTY_BOOL( Standalone );
435 REGISTER_PROPERTY ( CDataSectionElement, OUString );
436 REGISTER_PROPERTY ( Replace, OUString );
437 REGISTER_PROPERTY ( Separator, OUString );
438 REGISTER_PROPERTY ( IncludeNamespacePrefixes, Sequence< OUString > );
439 REGISTER_PROPERTY ( Model, Reference<XModel> );
441 initializePropertyValueCache( HANDLE_Indent );
442 initializePropertyValueCache( HANDLE_OmitXmlDeclaration );
443 initializePropertyValueCache( HANDLE_Standalone );
446 sal_Bool SAL_CALL Submission::convertFastPropertyValue(
447 Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue )
448 throw ( IllegalArgumentException )
450 if ( nHandle == HANDLE_IncludeNamespacePrefixes )
452 // for convinience reasons (????), we accept a string which contains
453 // a comma-separated list of namespace prefixes
454 ::rtl::OUString sTokenList;
455 if ( rValue >>= sTokenList )
457 std::vector< OUString > aPrefixes;
458 sal_Int32 p = 0;
459 while ( p >= 0 )
460 aPrefixes.push_back( sTokenList.getToken( 0, ',', p ) );
462 Sequence< ::rtl::OUString > aConvertedPrefixes( &aPrefixes[0], aPrefixes.size() );
463 return PropertySetBase::convertFastPropertyValue( rConvertedValue, rOldValue, nHandle, makeAny( aConvertedPrefixes ) );
467 return PropertySetBase::convertFastPropertyValue( rConvertedValue, rOldValue, nHandle, rValue );
470 OUString SAL_CALL Submission::getName()
471 throw( RuntimeException )
473 return getID();
476 void SAL_CALL Submission::setName( const OUString& sID )
477 throw( RuntimeException )
479 setID( sID );
484 sal_Int64 SAL_CALL Submission::getSomething(
485 const Sequence<sal_Int8>& aId )
486 throw( RuntimeException )
488 return ( aId == getUnoTunnelID() ) ? reinterpret_cast<sal_Int64>(this) : 0;
492 OUString lcl_message( const OUString& rID, const OUString& rText )
494 OUStringBuffer aMessage;
495 aMessage.append( OUSTRING("XForms submission '") );
496 aMessage.append( rID );
497 aMessage.append( OUSTRING("' failed") );
498 aMessage.append( rText );
499 aMessage.append( OUSTRING(".") );
500 return aMessage.makeStringAndClear();
503 void SAL_CALL Submission::submitWithInteraction(
504 const Reference<XInteractionHandler>& _rxHandler )
505 throw ( VetoException,
506 WrappedTargetException,
507 RuntimeException )
509 // as long as this class is not really threadsafe, we need to copy
510 // the members we're interested in
511 Reference< XModel > xModel( mxModel );
512 ::rtl::OUString sID( msID );
514 if ( !xModel.is() || !msID.getLength() )
515 throw RuntimeException(
516 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "This is not a valid submission object." ) ),
517 *this
520 Model* pModel = Model::getModel( xModel );
521 OSL_ENSURE( pModel != NULL, "illegal model?" );
523 // #i36765# #i47248# warning on submission of illegal data
524 // check for validity (and query user if invalid)
525 bool bValid = pModel->isValid();
526 if( ! bValid )
528 InvalidDataOnSubmitException aInvalidDataException(
529 lcl_message(sID, OUSTRING(" due to invalid data") ), *this );
531 if( _rxHandler.is() )
533 // labouriously create interaction request
534 comphelper::OInteractionRequest* pRequest
535 = new comphelper::OInteractionRequest(
536 makeAny( aInvalidDataException ) );
537 Reference<XInteractionRequest> xRequest = pRequest;
539 comphelper::OInteractionApprove* pContinue
540 = new comphelper::OInteractionApprove();
541 Reference<XInteractionContinuation> xContinue = pContinue;
542 pRequest->addContinuation( xContinue );
544 comphelper::OInteractionDisapprove* pCancel
545 = new comphelper::OInteractionDisapprove();
546 Reference<XInteractionContinuation> xCancel = pCancel;
547 pRequest->addContinuation( xCancel );
549 // ask the handler...
550 _rxHandler->handle( xRequest );
551 OSL_ENSURE( pContinue->wasSelected() || pCancel->wasSelected(),
552 "handler didn't select" );
554 // and continue, if user chose 'continue'
555 if( pContinue->wasSelected() )
556 bValid = true;
559 // abort if invalid (and user didn't tell us to continue)
560 if( ! bValid )
561 throw aInvalidDataException;
564 // attempt submission
565 bool bResult = false;
568 bResult = doSubmit( _rxHandler );
570 catch( const VetoException& )
572 OSL_ENSURE( sal_False, "Model::submit: Hmm. How can a single submission have a veto right?" );
573 // allowed to leave
574 throw;
576 catch( const Exception& e )
578 // exception caught: re-throw as wrapped target exception
579 throw WrappedTargetException(
580 lcl_message( sID, OUSTRING(" due to exception being thrown") ),
581 *this, makeAny( e ) );
584 if( bResult )
586 mxModel->rebuild();
588 else
590 // other failure: throw wrapped target exception, too.
591 throw WrappedTargetException(
592 lcl_message( sID, OUString() ), *this, Any() );
596 void SAL_CALL Submission::submit( ) throw ( VetoException, WrappedTargetException, RuntimeException )
598 submitWithInteraction( NULL );
601 void SAL_CALL Submission::addSubmissionVetoListener( const Reference< XSubmissionVetoListener >& /*listener*/ ) throw (NoSupportException, RuntimeException)
603 // TODO
604 throw NoSupportException();
607 void SAL_CALL Submission::removeSubmissionVetoListener( const Reference< XSubmissionVetoListener >& /*listener*/ ) throw (NoSupportException, RuntimeException)
609 // TODO
610 throw NoSupportException();
613 static sal_Bool _isIgnorable(const Reference< XNode >& aNode)
615 // ignore whitespace-only textnodes
616 if (aNode->getNodeType() == NodeType_TEXT_NODE)
618 OUString aTrimmedValue = aNode->getNodeValue().trim();
619 if (aTrimmedValue.getLength() == 0) return sal_True;
622 return sal_False;
625 // recursively copy relevant nodes from A to B
626 static void _cloneNodes(Model& aModel, const Reference< XNode >& dstParent, const Reference< XNode >& source, sal_Bool bRemoveWSNodes)
628 if (!source.is()) return;
630 Reference< XNode > cur = source;
631 Reference< XDocument > dstDoc = dstParent->getOwnerDocument();
632 Reference< XNode > imported;
634 if (cur.is())
636 // is this node relevant?
637 MIP mip = aModel.queryMIP(cur);
638 if(mip.isRelevant() && !(bRemoveWSNodes && _isIgnorable(cur)))
640 imported = dstDoc->importNode(cur, sal_False);
641 imported = dstParent->appendChild(imported);
642 // append source children to new imported parent
643 for( cur = cur->getFirstChild(); cur.is(); cur = cur->getNextSibling() )
644 _cloneNodes(aModel, imported, cur, bRemoveWSNodes);
648 Reference< XDocument > Submission::getInstanceDocument(const Reference< XXPathObject >& aObj)
650 using namespace com::sun::star::xml::xpath;
651 // result
652 Reference< XDocument > aDocument;
654 if (aObj->getObjectType() == XPathObjectType_XPATH_NODESET)
656 Reference< XNodeList > aList = aObj->getNodeList();
657 if (aList->getLength() > 0)
658 aDocument = aList->item(0)->getOwnerDocument();
660 return aDocument;
663 Reference< XDocumentFragment > Submission::createSubmissionDocument(const Reference< XXPathObject >& aObj, sal_Bool bRemoveWSNodes)
665 using namespace com::sun::star::xml::xpath;
666 Reference< XDocumentBuilder > aDocBuilder(m_aFactory->createInstance(
667 OUString::createFromAscii("com.sun.star.xml.dom.DocumentBuilder")), UNO_QUERY);
668 Reference< XDocument > aDocument = aDocBuilder->newDocument();
669 Reference< XDocumentFragment > aFragment = aDocument->createDocumentFragment();
672 if (aObj->getObjectType() == XPathObjectType_XPATH_NODESET)
674 Reference< XNodeList > aList = aObj->getNodeList();
675 Reference< XNode > aListItem;
676 for (sal_Int32 i=0; i < aList->getLength(); i++)
678 aListItem = aList->item(i);
679 if (aListItem->getNodeType()==NodeType_DOCUMENT_NODE)
680 aListItem = Reference< XNode >(
681 (Reference< XDocument >(aListItem, UNO_QUERY))->getDocumentElement(), UNO_QUERY);
682 // copy relevant nodes from instance into fragment
683 _cloneNodes(*getModelImpl(), Reference< XNode >(aFragment, UNO_QUERY), aListItem, bRemoveWSNodes);
686 return aFragment;
689 // some forwarding: XPropertySet is implemented in our base class,
690 // but also available as base of XSubmission
691 Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL Submission::getPropertySetInfo( ) throw(RuntimeException)
693 return PropertySetBase::getPropertySetInfo();
695 void SAL_CALL Submission::setPropertyValue( const ::rtl::OUString& aPropertyName, const Any& aValue ) throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
697 PropertySetBase::setPropertyValue( aPropertyName, aValue );
699 Any SAL_CALL Submission::getPropertyValue( const ::rtl::OUString& PropertyName ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
701 return PropertySetBase::getPropertyValue( PropertyName );
703 void SAL_CALL Submission::addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
705 PropertySetBase::addPropertyChangeListener( aPropertyName, xListener );
707 void SAL_CALL Submission::removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
709 PropertySetBase::removePropertyChangeListener( aPropertyName, aListener );
711 void SAL_CALL Submission::addVetoableChangeListener( const ::rtl::OUString& PropertyName, const Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
713 PropertySetBase::addVetoableChangeListener( PropertyName, aListener );
715 void SAL_CALL Submission::removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
717 PropertySetBase::removeVetoableChangeListener( PropertyName, aListener );