update dev300-m58
[ooovba.git] / forms / source / xforms / submission.cxx
bloba21afd416f3f29fefa0dff04994bffc4bb8c940a
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: submission.cxx,v $
10 * $Revision: 1.12 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_forms.hxx"
33 #include "submission.hxx"
35 #include "model.hxx"
36 #include "binding.hxx"
37 #include "mip.hxx"
38 #include "evaluationcontext.hxx"
39 #include "unohelper.hxx"
40 #include "submission/submission_put.hxx"
41 #include "submission/submission_post.hxx"
42 #include "submission/submission_get.hxx"
44 #include <rtl/ustring.hxx>
45 #include <rtl/ustrbuf.hxx>
47 #include <com/sun/star/uno/Sequence.hxx>
48 #include <com/sun/star/uno/Reference.hxx>
49 #include <com/sun/star/xforms/XModel.hpp>
50 #include <com/sun/star/uno/RuntimeException.hpp>
51 #include <com/sun/star/xml/xpath/XXPathObject.hpp>
52 #include <com/sun/star/container/XNameAccess.hpp>
53 #include <com/sun/star/xml/xpath/XPathObjectType.hpp>
54 #include <com/sun/star/xml/dom/XNodeList.hpp>
55 #include <com/sun/star/xml/dom/XDocument.hpp>
56 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
57 #include <com/sun/star/xml/dom/XDocumentFragment.hpp>
58 #include <com/sun/star/xml/dom/NodeType.hpp>
59 #include <com/sun/star/task/XInteractionHandler.hpp>
60 #include <com/sun/star/task/XInteractionRequest.hpp>
61 #include <com/sun/star/task/XInteractionContinuation.hpp>
62 #include <com/sun/star/xforms/InvalidDataOnSubmitException.hpp>
63 #include <com/sun/star/frame/XFrame.hpp>
64 #include <cppuhelper/typeprovider.hxx>
65 #include <comphelper/propertysetinfo.hxx>
66 #include <comphelper/interaction.hxx>
67 #include <unotools/processfactory.hxx>
68 #include <memory>
73 using rtl::OUString;
74 using rtl::OUStringBuffer;
75 using com::sun::star::beans::UnknownPropertyException;
76 using com::sun::star::beans::PropertyVetoException;
77 using com::sun::star::lang::IllegalArgumentException;
78 using com::sun::star::util::VetoException;
79 using com::sun::star::form::submission::XSubmissionVetoListener;
80 using com::sun::star::lang::WrappedTargetException;
81 using com::sun::star::lang::NoSupportException;
82 using com::sun::star::task::XInteractionHandler;
83 using com::sun::star::task::XInteractionRequest;
84 using com::sun::star::task::XInteractionContinuation;
85 using com::sun::star::xforms::XModel;
86 using com::sun::star::xforms::InvalidDataOnSubmitException;
87 using com::sun::star::container::XNameAccess;
88 using com::sun::star::xml::xpath::XXPathObject;
89 using com::sun::star::xml::xpath::XPathObjectType;
90 using com::sun::star::frame::XFrame;
91 using xforms::Submission;
92 using xforms::Model;
93 using xforms::MIP;
94 using std::auto_ptr;
96 using namespace com::sun::star::uno;
97 using namespace com::sun::star::lang;
98 using namespace com::sun::star::xml::dom;
100 Submission::Submission() :
101 msID(),
102 msBind(),
103 maRef(),
104 msAction(),
105 msMethod(),
106 msVersion(),
107 mbIndent(),
108 msMediaType(),
109 msEncoding(),
110 mbOmitXmlDeclaration(),
111 mbStandalone(),
112 msCDataSectionElement(),
113 msReplace( OUSTRING("none") ),
114 msSeparator(),
115 msIncludeNamespacePrefixes(),
116 m_aFactory(utl::getProcessServiceFactory())
118 initializePropertySet();
121 Submission::~Submission() throw()
125 Reference<XModel> Submission::getModel() const
127 return mxModel;
130 void Submission::setModel( const Reference<XModel>& xModel )
132 mxModel = xModel;
135 OUString Submission::getID() const
137 return msID;
140 void Submission::setID( const OUString& sID )
142 msID = sID;
145 OUString Submission::getBind() const
147 return msBind;
150 void Submission::setBind( const OUString& sBind )
152 msBind = sBind;
155 OUString Submission::getRef() const
157 return maRef.getExpression();
160 void Submission::setRef( const OUString& sRef )
162 maRef.setExpression( sRef );
165 OUString Submission::getAction() const
167 return msAction;
170 void Submission::setAction( const OUString& sAction )
172 msAction = sAction;
175 OUString Submission::getMethod() const
177 return msMethod;
180 void Submission::setMethod( const OUString& sMethod )
182 msMethod = sMethod;
185 OUString Submission::getVersion() const
187 return msVersion;
190 void Submission::setVersion( const OUString& sVersion )
192 msVersion = sVersion;
195 bool Submission::getIndent() const
197 return mbIndent;
200 void Submission::setIndent( bool bIndent )
202 mbIndent = bIndent;
205 OUString Submission::getMediaType() const
207 return msMediaType;
210 void Submission::setMediaType( const OUString& sMediaType )
212 msMediaType = sMediaType;
215 OUString Submission::getEncoding() const
217 return msEncoding;
220 void Submission::setEncoding( const OUString& sEncoding )
222 msEncoding = sEncoding;
225 bool Submission::getOmitXmlDeclaration() const
227 return mbOmitXmlDeclaration;
230 void Submission::setOmitXmlDeclaration( bool bOmitXmlDeclaration )
232 mbOmitXmlDeclaration = bOmitXmlDeclaration;
235 bool Submission::getStandalone() const
237 return mbStandalone;
240 void Submission::setStandalone( bool bStandalone )
242 mbStandalone = bStandalone;
245 OUString Submission::getCDataSectionElement() const
247 return msCDataSectionElement;
250 void Submission::setCDataSectionElement( const OUString& sCDataSectionElement )
252 msCDataSectionElement = sCDataSectionElement;
255 OUString Submission::getReplace() const
257 return msReplace;
260 void Submission::setReplace( const OUString& sReplace )
262 msReplace = sReplace;
265 OUString Submission::getSeparator() const
267 return msSeparator;
270 void Submission::setSeparator( const OUString& sSeparator )
272 msSeparator = sSeparator;
275 Sequence< OUString > Submission::getIncludeNamespacePrefixes() const
277 return msIncludeNamespacePrefixes;
280 void Submission::setIncludeNamespacePrefixes( const Sequence< OUString >& rIncludeNamespacePrefixes )
282 msIncludeNamespacePrefixes = rIncludeNamespacePrefixes;
285 bool Submission::doSubmit( const Reference< XInteractionHandler >& xHandler )
287 liveCheck();
289 // construct XXPathObject for submission doc; use bind in preference of ref
290 EvaluationContext aEvalContext;
291 ComputedExpression aExpression;
292 if( msBind.getLength() != 0 )
294 Binding* pBinding = Binding::getBinding( mxModel->getBinding(msBind) );
295 if( pBinding != NULL )
297 aExpression.setExpression( pBinding->getBindingExpression() );
298 aEvalContext = pBinding->getEvaluationContext();
300 // TODO: else: illegal binding name -> raise error
302 else if( maRef.getExpression().getLength() != 0 )
304 aExpression.setExpression( maRef.getExpression() );
305 aEvalContext = Model::getModel( mxModel )->getEvaluationContext();
307 else
309 aExpression.setExpression( OUSTRING( "/" ) );
310 aEvalContext = Model::getModel( mxModel )->getEvaluationContext();
312 aExpression.evaluate( aEvalContext );
313 Reference<XXPathObject> xResult = aExpression.getXPath();
314 OSL_ENSURE( xResult.is(), "no result?" );
316 // early out if we have not obtained any result
317 if( ! xResult.is() )
318 return false;
321 // Reference< XNodeList > aList = xResult->getNodeList();
322 OUString aMethod = getMethod();
324 // strip whitespace-only text node for get submission
325 Reference< XDocumentFragment > aFragment = createSubmissionDocument(
326 xResult, aMethod.equalsIgnoreAsciiCaseAscii("get"));
328 // submit result; set encoding, etc.
329 auto_ptr<CSubmission> xSubmission;
330 if (aMethod.equalsIgnoreAsciiCaseAscii("PUT"))
331 xSubmission = auto_ptr<CSubmission>(
332 new CSubmissionPut( getAction(), aFragment));
333 else if (aMethod.equalsIgnoreAsciiCaseAscii("post"))
334 xSubmission = auto_ptr<CSubmission>(
335 new CSubmissionPost( getAction(), aFragment));
336 else if (aMethod.equalsIgnoreAsciiCaseAscii("get"))
337 xSubmission = auto_ptr<CSubmission>(
338 new CSubmissionGet( getAction(), aFragment));
339 else
341 OSL_ENSURE(sal_False, "Unsupported xforms submission method");
342 return false;
345 xSubmission->setEncoding(getEncoding());
346 CSubmission::SubmissionResult aResult = xSubmission->submit( xHandler );
348 if (aResult == CSubmission::SUCCESS)
350 Reference< XDocument > aInstanceDoc = getInstanceDocument(xResult);
351 aResult = xSubmission->replace(getReplace(), aInstanceDoc, Reference< XFrame >());
354 return ( aResult == CSubmission::SUCCESS );
357 Sequence<sal_Int8> Submission::getUnoTunnelID()
359 static cppu::OImplementationId aImplementationId;
360 return aImplementationId.getImplementationId();
363 Submission* Submission::getSubmission(
364 const Reference<XPropertySet>& xPropertySet )
366 Reference<XUnoTunnel> xTunnel( xPropertySet, UNO_QUERY );
367 return xTunnel.is()
368 ? reinterpret_cast<Submission*>(
369 xTunnel->getSomething( getUnoTunnelID() ) )
370 : NULL;
378 void Submission::liveCheck()
379 throw( RuntimeException )
381 bool bValid = mxModel.is();
383 if( ! bValid )
384 throw RuntimeException();
387 Model* Submission::getModelImpl() const
389 Model* pModel = NULL;
390 if( mxModel.is() )
391 pModel = Model::getModel( mxModel );
392 return pModel;
397 // Property-Set implementation
400 #define HANDLE_ID 0
401 #define HANDLE_Bind 1
402 #define HANDLE_Ref 2
403 #define HANDLE_Action 3
404 #define HANDLE_Method 4
405 #define HANDLE_Version 5
406 #define HANDLE_Indent 6
407 #define HANDLE_MediaType 7
408 #define HANDLE_Encoding 8
409 #define HANDLE_OmitXmlDeclaration 9
410 #define HANDLE_Standalone 10
411 #define HANDLE_CDataSectionElement 11
412 #define HANDLE_Replace 12
413 #define HANDLE_Separator 13
414 #define HANDLE_IncludeNamespacePrefixes 14
415 #define HANDLE_Model 15
417 #define REGISTER_PROPERTY( property, type ) \
418 registerProperty( PROPERTY( property, type ), \
419 new DirectPropertyAccessor< Submission, type >( this, &Submission::set##property, &Submission::get##property ) );
421 #define REGISTER_PROPERTY_BOOL( property ) \
422 registerProperty( PROPERTY( property, bool ), \
423 new BooleanPropertyAccessor< Submission, bool >( this, &Submission::set##property, &Submission::get##property ) );
425 void Submission::initializePropertySet()
427 REGISTER_PROPERTY ( ID, OUString );
428 REGISTER_PROPERTY ( Bind, OUString );
429 REGISTER_PROPERTY ( Ref, OUString );
430 REGISTER_PROPERTY ( Action, OUString );
431 REGISTER_PROPERTY ( Method, OUString );
432 REGISTER_PROPERTY ( Version, OUString );
433 REGISTER_PROPERTY_BOOL( Indent );
434 REGISTER_PROPERTY ( MediaType, OUString );
435 REGISTER_PROPERTY ( Encoding, OUString );
436 REGISTER_PROPERTY_BOOL( OmitXmlDeclaration );
437 REGISTER_PROPERTY_BOOL( Standalone );
438 REGISTER_PROPERTY ( CDataSectionElement, OUString );
439 REGISTER_PROPERTY ( Replace, OUString );
440 REGISTER_PROPERTY ( Separator, OUString );
441 REGISTER_PROPERTY ( IncludeNamespacePrefixes, Sequence< OUString > );
442 REGISTER_PROPERTY ( Model, Reference<XModel> );
444 initializePropertyValueCache( HANDLE_Indent );
445 initializePropertyValueCache( HANDLE_OmitXmlDeclaration );
446 initializePropertyValueCache( HANDLE_Standalone );
449 sal_Bool SAL_CALL Submission::convertFastPropertyValue(
450 Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue )
451 throw ( IllegalArgumentException )
453 if ( nHandle == HANDLE_IncludeNamespacePrefixes )
455 // for convinience reasons (????), we accept a string which contains
456 // a comma-separated list of namespace prefixes
457 ::rtl::OUString sTokenList;
458 if ( rValue >>= sTokenList )
460 std::vector< OUString > aPrefixes;
461 sal_Int32 p = 0;
462 while ( p >= 0 )
463 aPrefixes.push_back( sTokenList.getToken( 0, ',', p ) );
465 Sequence< ::rtl::OUString > aConvertedPrefixes( &aPrefixes[0], aPrefixes.size() );
466 return PropertySetBase::convertFastPropertyValue( rConvertedValue, rOldValue, nHandle, makeAny( aConvertedPrefixes ) );
470 return PropertySetBase::convertFastPropertyValue( rConvertedValue, rOldValue, nHandle, rValue );
473 OUString SAL_CALL Submission::getName()
474 throw( RuntimeException )
476 return getID();
479 void SAL_CALL Submission::setName( const OUString& sID )
480 throw( RuntimeException )
482 setID( sID );
487 sal_Int64 SAL_CALL Submission::getSomething(
488 const Sequence<sal_Int8>& aId )
489 throw( RuntimeException )
491 return ( aId == getUnoTunnelID() ) ? reinterpret_cast<sal_Int64>(this) : 0;
495 OUString lcl_message( const OUString& rID, const OUString& rText )
497 OUStringBuffer aMessage;
498 aMessage.append( OUSTRING("XForms submission '") );
499 aMessage.append( rID );
500 aMessage.append( OUSTRING("' failed") );
501 aMessage.append( rText );
502 aMessage.append( OUSTRING(".") );
503 return aMessage.makeStringAndClear();
506 void SAL_CALL Submission::submitWithInteraction(
507 const Reference<XInteractionHandler>& _rxHandler )
508 throw ( VetoException,
509 WrappedTargetException,
510 RuntimeException )
512 // as long as this class is not really threadsafe, we need to copy
513 // the members we're interested in
514 Reference< XModel > xModel( mxModel );
515 ::rtl::OUString sID( msID );
517 if ( !xModel.is() || !msID.getLength() )
518 throw RuntimeException(
519 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "This is not a valid submission object." ) ),
520 *this
523 Model* pModel = Model::getModel( xModel );
524 OSL_ENSURE( pModel != NULL, "illegal model?" );
526 // #i36765# #i47248# warning on submission of illegal data
527 // check for validity (and query user if invalid)
528 bool bValid = pModel->isValid();
529 if( ! bValid )
531 InvalidDataOnSubmitException aInvalidDataException(
532 lcl_message(sID, OUSTRING(" due to invalid data") ), *this );
534 if( _rxHandler.is() )
536 // labouriously create interaction request
537 comphelper::OInteractionRequest* pRequest
538 = new comphelper::OInteractionRequest(
539 makeAny( aInvalidDataException ) );
540 Reference<XInteractionRequest> xRequest = pRequest;
542 comphelper::OInteractionApprove* pContinue
543 = new comphelper::OInteractionApprove();
544 Reference<XInteractionContinuation> xContinue = pContinue;
545 pRequest->addContinuation( xContinue );
547 comphelper::OInteractionDisapprove* pCancel
548 = new comphelper::OInteractionDisapprove();
549 Reference<XInteractionContinuation> xCancel = pCancel;
550 pRequest->addContinuation( xCancel );
552 // ask the handler...
553 _rxHandler->handle( xRequest );
554 OSL_ENSURE( pContinue->wasSelected() || pCancel->wasSelected(),
555 "handler didn't select" );
557 // and continue, if user chose 'continue'
558 if( pContinue->wasSelected() )
559 bValid = true;
562 // abort if invalid (and user didn't tell us to continue)
563 if( ! bValid )
564 throw aInvalidDataException;
567 // attempt submission
568 bool bResult = false;
571 bResult = doSubmit( _rxHandler );
573 catch( const VetoException& )
575 OSL_ENSURE( sal_False, "Model::submit: Hmm. How can a single submission have a veto right?" );
576 // allowed to leave
577 throw;
579 catch( const Exception& e )
581 // exception caught: re-throw as wrapped target exception
582 throw WrappedTargetException(
583 lcl_message( sID, OUSTRING(" due to exception being thrown") ),
584 *this, makeAny( e ) );
587 if( bResult )
589 mxModel->rebuild();
591 else
593 // other failure: throw wrapped target exception, too.
594 throw WrappedTargetException(
595 lcl_message( sID, OUString() ), *this, Any() );
599 void SAL_CALL Submission::submit( ) throw ( VetoException, WrappedTargetException, RuntimeException )
601 submitWithInteraction( NULL );
604 void SAL_CALL Submission::addSubmissionVetoListener( const Reference< XSubmissionVetoListener >& /*listener*/ ) throw (NoSupportException, RuntimeException)
606 // TODO
607 throw NoSupportException();
610 void SAL_CALL Submission::removeSubmissionVetoListener( const Reference< XSubmissionVetoListener >& /*listener*/ ) throw (NoSupportException, RuntimeException)
612 // TODO
613 throw NoSupportException();
616 static sal_Bool _isIgnorable(const Reference< XNode >& aNode)
618 // ignore whitespace-only textnodes
619 if (aNode->getNodeType() == NodeType_TEXT_NODE)
621 OUString aTrimmedValue = aNode->getNodeValue().trim();
622 if (aTrimmedValue.getLength() == 0) return sal_True;
625 return sal_False;
628 // recursively copy relevant nodes from A to B
629 static void _cloneNodes(Model& aModel, const Reference< XNode >& dstParent, const Reference< XNode >& source, sal_Bool bRemoveWSNodes)
631 if (!source.is()) return;
633 Reference< XNode > cur = source;
634 Reference< XDocument > dstDoc = dstParent->getOwnerDocument();
635 Reference< XNode > imported;
637 if (cur.is())
639 // is this node relevant?
640 MIP mip = aModel.queryMIP(cur);
641 if(mip.isRelevant() && !(bRemoveWSNodes && _isIgnorable(cur)))
643 imported = dstDoc->importNode(cur, sal_False);
644 imported = dstParent->appendChild(imported);
645 // append source children to new imported parent
646 for( cur = cur->getFirstChild(); cur.is(); cur = cur->getNextSibling() )
647 _cloneNodes(aModel, imported, cur, bRemoveWSNodes);
651 Reference< XDocument > Submission::getInstanceDocument(const Reference< XXPathObject >& aObj)
653 using namespace com::sun::star::xml::xpath;
654 // result
655 Reference< XDocument > aDocument;
657 if (aObj->getObjectType() == XPathObjectType_XPATH_NODESET)
659 Reference< XNodeList > aList = aObj->getNodeList();
660 if (aList->getLength() > 0)
661 aDocument = aList->item(0)->getOwnerDocument();
663 return aDocument;
666 Reference< XDocumentFragment > Submission::createSubmissionDocument(const Reference< XXPathObject >& aObj, sal_Bool bRemoveWSNodes)
668 using namespace com::sun::star::xml::xpath;
669 Reference< XDocumentBuilder > aDocBuilder(m_aFactory->createInstance(
670 OUString::createFromAscii("com.sun.star.xml.dom.DocumentBuilder")), UNO_QUERY);
671 Reference< XDocument > aDocument = aDocBuilder->newDocument();
672 Reference< XDocumentFragment > aFragment = aDocument->createDocumentFragment();
675 if (aObj->getObjectType() == XPathObjectType_XPATH_NODESET)
677 Reference< XNodeList > aList = aObj->getNodeList();
678 Reference< XNode > aListItem;
679 for (sal_Int32 i=0; i < aList->getLength(); i++)
681 aListItem = aList->item(i);
682 if (aListItem->getNodeType()==NodeType_DOCUMENT_NODE)
683 aListItem = Reference< XNode >(
684 (Reference< XDocument >(aListItem, UNO_QUERY))->getDocumentElement(), UNO_QUERY);
685 // copy relevant nodes from instance into fragment
686 _cloneNodes(*getModelImpl(), Reference< XNode >(aFragment, UNO_QUERY), aListItem, bRemoveWSNodes);
689 return aFragment;
692 // some forwarding: XPropertySet is implemented in our base class,
693 // but also available as base of XSubmission
694 Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL Submission::getPropertySetInfo( ) throw(RuntimeException)
696 return PropertySetBase::getPropertySetInfo();
698 void SAL_CALL Submission::setPropertyValue( const ::rtl::OUString& aPropertyName, const Any& aValue ) throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
700 PropertySetBase::setPropertyValue( aPropertyName, aValue );
702 Any SAL_CALL Submission::getPropertyValue( const ::rtl::OUString& PropertyName ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
704 return PropertySetBase::getPropertyValue( PropertyName );
706 void SAL_CALL Submission::addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
708 PropertySetBase::addPropertyChangeListener( aPropertyName, xListener );
710 void SAL_CALL Submission::removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
712 PropertySetBase::removePropertyChangeListener( aPropertyName, aListener );
714 void SAL_CALL Submission::addVetoableChangeListener( const ::rtl::OUString& PropertyName, const Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
716 PropertySetBase::addVetoableChangeListener( PropertyName, aListener );
718 void SAL_CALL Submission::removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
720 PropertySetBase::removeVetoableChangeListener( PropertyName, aListener );