Language

The Free and Open Productivity Suite
Released: Apache OpenOffice 4.1.15

OpenOffice.orgHow To Use The Universal Content Broker API


Contents

Abstract
Getting access to the UCB
Creating a UCB Content for a given URL
Executing a command at a UCB Content
Querying the commands supported by a UCB Content
Querying the properties supported by a UCB Content
Obtaining property values from a UCB Content
Setting property values of a UCB Content
Accessing the children of a UCB Folder Content
Accessing (loading) the content data stream of a UCB Document Content
Setting (storing) the content data stream of a UCB Document Content
Creating a new resource
Deleting a resource
Copying, Moving and Creating links to a resource


Abstract

This document describes how software developers can access the functionality of the Universal Content Broker (UCB). There are code snippets in several sections that demonstrate the usage of the UCB API, as well as the usage of the UCBHELPER library. That library was designed especially to simplify UCB usage.

An example for an application that uses the native UCB API can be found at http://www.openoffice.org/source/browse/ucb/ucb/workben/ucb/. An application that uses the UCBHELPER library can be found at http://www.openoffice.org/source/browse/ucb/ucbhelper/workben/ucbexplorer/. A complete description of the UCB's UNO interfaces and UNO services can be found in the UCB API Reference.


Getting access to the UCB

Before a process can use the UCB, it needs to do the following steps once:

  • Create and set the UNO Service Manager.

  • Create an instance of the UNO service "com.sun.star.ucb.UniversalContentBroker", passing the keys identifying a predefined UCB configuration.

Note: There are several predefined UCB configurations. Each configuration contains data that describe a set of UCPs. All UCPs contained in a configuration will be registered at the UCB that shall be created using this configuration. A UCB configuration is identified by two keys, which are strings. The standard configuration is "Local" and "Office", which generally allows access to all UCPs.


Example 1 (C++)


using namespace com::sun::star;

bool initUCB()
{
    /////////////////////////////////////////////////////////////////////
    // Create Process Service Manager. This needs to be done only once
    // per process! Afterwards it is accessable via
    // comphelper::getProcessServiceFactory().
    /////////////////////////////////////////////////////////////////////

    uno::Reference< lang::XMultiServiceFactory > xServiceFactory;
    try
    {
        xServiceFactory = cppu::createRegistryServiceFactory(
                                  comphelper::getPathToSystemRegistry(),
                                  rtl::OUString(),
                                  true );
    }
    catch ( uno::Exception const & ) {}

    if ( !xServiceFactory.is() )
        return false;

    comphelper::setProcessServiceFactory( xServiceFactory );

    /////////////////////////////////////////////////////////////////////
    // Create UCB. This needs to be done only once per process!
    /////////////////////////////////////////////////////////////////////

    // Supply configuration to use for this UCB instance...
    uno::Sequence< uno::Any > aArgs( 2 );
    aArgs[ 0 ] <<= rtl::OUString::createFromAscii( "Local" );
    aArgs[ 1 ] <<= rtl::OUString::createFromAscii( "Office" );

    uno::Reference< uno::XInterface > xUCB;
    try
    {
        xUCB = xServiceFactory->createInstanceWithArguments(
                    rtl::OUString::createFromAscii(
                        "com.sun.star.ucb.UniversalContentBroker" ),
                    aArgs );
    }
    catch ( uno::Exception const & ) {}

    if ( !xUCB.is() )
        return false;

    return true;
}

Example 2 (C++, using UCBHELPER library)


using namespace com::sun::star;

bool initUCB()
{
    /////////////////////////////////////////////////////////////////////
    // Create Process Service Manager. This needs to be done only once
    // per process! Afterwards it is accessable via
    // comphelper::getProcessServiceFactory().
    /////////////////////////////////////////////////////////////////////

    uno::Reference< lang::XMultiServiceFactory > xServiceFactory;
    try
    {
        xServiceFactory = cppu::createRegistryServiceFactory(
                                  comphelper::getPathToSystemRegistry(),
                                  rtl::OUString(),
                                  true );
    }
    catch ( uno::Exception const & ) {}

    if ( !xServiceFactory.is() )
        return false;

    comphelper::setProcessServiceFactory( xServiceFactory );

    /////////////////////////////////////////////////////////////////////
    // Create UCB. This needs to be done only once per process!
    /////////////////////////////////////////////////////////////////////

    // Supply configuration to use for this UCB instance...
    uno::Sequence< uno::Any > aArgs( 2 );
    aArgs[ 0 ] <<= rtl::OUString::createFromAscii(
                                  UCB_CONFIGURATION_KEY1_LOCAL );
    aArgs[ 1 ] <<= rtl::OUString::createFromAscii(
                                  UCB_CONFIGURATION_KEY2_OFFICE );

    return ::ucb::ContentBroker::initialize( xServiceFactory, aArgs );
}


Creating a UCB Content for a given URL

Each UCB Content can be identified using a URL. To create a content object for a given URL:

  • Obtain access to the UCB.

  • Let the UCB create a content identifier object for the requested URL (createContentIdentifier).

  • Let the UCB create a content object for the just created content identifier object (queryContent).

  • The UCB dispatches the queryContent-call to the appropriate UCP. The UCP will be selected according to the URL contained in the identifier object.

  • The UCP creates the content implementation object.

  • The UCB returns the content object returned from the UCP to the original queryContent-caller.


Example 1 (C++)


using namespace com::sun::star;

{
    /////////////////////////////////////////////////////////////////////
    // Obtain access to UCB...
    /////////////////////////////////////////////////////////////////////

    uno::Reference< uno::XInterface > xUCB = ...

    // Obtain required UCB interfaces...
    uno::Reference< ucb::XContentIdentifierFactory > xIdFactory(
                                                  xUCB, uno::UNO_QUERY );
    if ( !xIdFactory.is() )
        ... error ...

    uno::Reference< ucb::XContentProvider > xProvider(
                                                  xUCB, uno::UNO_QUERY );
    if ( !xProvider.is() )
        ... error ...

    /////////////////////////////////////////////////////////////////////
    // Obtain content object from UCB...
    /////////////////////////////////////////////////////////////////////

    // Create identifier object.
    uno::Reference< ucb::XContentIdentifier > xId
        = xIdFactory->createContentIdentifier( rURL );

    if ( !xId.is() )
        ... error ...

    uno::Reference< ucb::XContent > xContent
        = xProvider->queryContent( xId );

    if ( !xContent.is() )
        ... error ...
}

Example 2 (C++, using UCBHELPER library)


using namespace com::sun::star;

{
    rtl::OUString aURL = ...

    /////////////////////////////////////////////////////////////////////
    // Create an empty content object. ucb::Content::create(...)
    // will associate that content with the requested URL...
    /////////////////////////////////////////////////////////////////////

    ::ucb::Content aContent;
    bool bSuccess = ::ucb::Content::create(
        aURL, uno::Reference< ucb::XCommandEnvironment >(), aContent );
    if ( bSuccess )
    {
        // content is ready for usage now...
    }
}


Executing a command at a UCB Content

Each UCB Content is able to execute commands. Once you have created a content object, you can execute commands at it using its XCommandProcessor interface. For a complete list of predefined commands, refer to the description of the UNO service Content.

If executing a command cannot proceed because of some error condition, the following happens: If the execute-call was supplied with an XCommandEnvironment that contains an XInteractionHandler, this interaction handler is used to resolve the problem. If no interaction handler is supplied (or if it cannot resolve the problem), an exception describing the error condition is thrown.


Example 1 (C++)


using namespace com::sun::star;

uno::Any executeCommand( const uno::Reference< ucb::XContent > & xContent,
                         const rtl::OUString & rCommandName,
                         const uno::Any & rArgument )
    throw ( ucb::CommandAbortedException, uno::Exception )
{
    /////////////////////////////////////////////////////////////////////
    // Obtain command processor interface from given content.
    /////////////////////////////////////////////////////////////////////

    ucb::XCommandProcessor xCmdProcessor( xContent, uno::UNO_QUERY );

    /////////////////////////////////////////////////////////////////////
    // Assemble command to execute.
    /////////////////////////////////////////////////////////////////////

    ucb::Command aCommand;
    aCommand.Name     = rCommandName;
    aCommand.Handle   = -1; // not available
    aCommand.Argument = rArgument;

    // Note: throws ucb::CommandAbortedException, uno::Exception
    return xCmdProcessor->execute(
            aCommand, 0, uno::Reference< ucb::XCommandEnvironment >() );
}

Example 2 (C++, using UCBHELPER library)


using namespace com::sun::star;

uno::Any executeCommand( const ::ucb::Content & rContent,
                         const rtl::OUString & rCommandName,
                         const uno::Any & rArgument )
    throw ( ucb::CommandAbortedException, uno::Exception )
{
    // Note: throws ucb::CommandAbortedException, uno::Exception
    return rContent.executeCommand( rCommandName, rCommandArgument );
}


Querying the commands supported by a UCB Content

Each UCB Content supports the command getCommandInfo. This command takes a void argument and returns an implementation of the interface XCommandInfo that can be used to obtain information on the supported commands.


Example 1 (C++)


using namespace com::sun::star;

uno::Reference< ucb::XCommandInfo > getCommandInfo(
                 const uno::Reference< ucb::XContent > & xContent )
{
    // Execute command "getCommandInfo".

    uno::Reference< ucb::XCommandInfo > xInfo;
    try
    {
        executeCommand( xContent,
                        rtl::OUString::createFromAscii(
                                                "getCommandInfo" ),
                        uno::Any() ) >>= xInfo;
    {
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }

    return xInfo;
}

Example 2 (C++, using UCBHELPER library)


using namespace com::sun::star;

uno::Reference< ucb::XCommandInfo > getCommandInfo(
                             const ::ucb::Content & rContent )
{
    uno::Reference< ucb::XCommandInfo > xInfo;
    try
    {
        // UCBHELPER Content has a special method for this command.
        xInfo = rContent.getCommands();
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }

    return xInfo;
}


Querying the properties supported by a UCB Content

Each UCB Content supports the command getPropertySetInfo. This command takes a void argument and returns an implementation of the interface XPropertySetInfo that can be used to obtain information on the supported properties.


Example 1 (C++)


using namespace com::sun::star;

uno::Reference< beans::XPropertySetInfo > getPropertySetInfo(
                 const uno::Reference< ucb::XContent > & xContent )
{
    uno::Reference< beans::XPropertySetInfo > xInfo;
    try
    {
        // Execute command "getPropertySetInfo".
        executeCommand( xContent,
                        rtl::OUString::createFromAscii(
                                            "getPropertySetInfo" ),
                        uno::Any() ) >>= xInfo;
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }

    return xInfo;
}

Example 2 (C++, using UCBHELPER library)


using namespace com::sun::star;

uno::Reference< beans::XPropertySetInfo > getPropertySetInfo(
                         const ::ucb::Content & rContent )
{
    uno::Reference< beans::XPropertySetInfo > xInfo;
    try
    {
        // UCBHELPER Content has a special method for this command.
        xInfo = rContent.getProperties();
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }

    return xInfo;
}


Obtaining property values from a UCB Content

A UCB Content maintains a set of properties. It supports the command getPropertyValues, which can be used to obtain one or more property values from a content. This command takes an argument of type sequence< Property > and returns an implementation of the interface XRow, which is very similar to a row of a JDBC resultset. To obtain property values from a UCB Content:

  • Define a sequence of properties for which you want to obtain the values.

  • Let the UCB Content execute the command getPropertyValues.

  • Obtain the property values from the returned row object.

Note that there are additional methods available at the Content class of the UCBHELPER library that can be used to obtain a single property value as uno::Any or to obtain multiple values as a sequence of uno::Any.


Example 1 (C++)


using namespace com::sun::star;

{
    uno::Reference< ucb::XContent > xContent = ...

    /////////////////////////////////////////////////////////////////////
    // Obtain value of the string property Title and the boolean property
    // IsFolder from xContent...
    /////////////////////////////////////////////////////////////////////

    // Define property sequence.

    uno::Sequence< beans::Property > aProps( 2 );
    aProps[ 0 ].Name = rtl::OUString::createFromAscii( "Title" );
    aProps[ 0 ].Handle = -1; // n/a
    aProps[ 1 ].Name = rtl::OUString::createFromAscii( "IsFolder" );
    aProps[ 1 ].Handle = -1; // n/a

    uno::Reference< sdbc::XRow > xValues;
    try
    {
        // Execute command "getPropertyValues".
        executeCommand( xContent,
                        rtl::OUString::createFromAscii(
                                            "getPropertyValues" ),
                        makeAny( aProps ) ) >>= xValues;
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }

    if ( !xValues.is() )
        ... error ...

    // Extract values from row object. Note that that the
    // first column is 1, not 0.

    // Title: Obtain value of column 1 as string.
    rtl::OUString aTitle = xValues->getString( 1 ) );
    if ( aTitle.Len() == 0 && xValues->wasNull() )
        ... error ...

    // IsFolder: Obtain value of column 2 as boolean.
    sal_Bool bFolder = xValues->getBoolean( 2 );
    if ( !bFolder && xValues->wasNull() )
        ... error ...
}

Example 2a (C++, using UCBHELPER library)


using namespace com::sun::star;

{
    ::ucb::Content aContent = ...

    /////////////////////////////////////////////////////////////////////
    // Obtain value of the string property Title and the boolean property
    // IsFolder from xContent...
    /////////////////////////////////////////////////////////////////////

    // Define property sequence.

    uno::Sequence< rtl::OUString > aProps( 2 );
    aProps[ 0 ] = rtl::OUString::createFromAscii( "Title" );
    aProps[ 1 ] = rtl::OUString::createFromAscii( "IsFolder" );

    uno::Reference< sdbc::XRow > xValues;

    try
    {
        // Obtain property values.
        xValues = aContent.getPropertyValuesInterface( aProps );
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }

    // Extract values from row object. Note that that the
    // first column is 1, not 0.

    // Title: Obtain value of column 1 as string.
    rtl::OUString aTitle = xValues->getString( 1 ) );
    if ( aTitle.getLength() == 0 && xValues->wasNull() )
        ... error ...

    // IsFolder: Obtain value of column 2 as boolean.
    sal_Bool bFolder = xValues->getBoolean( 2 );
    if ( !bFolder && xValues->wasNull() )
        ... error ...
}

Example 2b (C++, using UCBHELPER library)


using namespace com::sun::star;

{
    ::ucb::Content aContent = ...

    /////////////////////////////////////////////////////////////////////
    // Obtain value of the string property Title and the boolean property
    // IsFolder from xContent...
    /////////////////////////////////////////////////////////////////////

    // Define property sequence.

    uno::Sequence< rtl::OUString > aProps( 2 );
    aProps[ 0 ] = rtl::OUString::createFromAscii( "Title" );
    aProps[ 1 ] = rtl::OUString::createFromAscii( "IsFolder" );

    uno::Sequence< uno::Any > aValues;

    try
    {
        // Obtain property values.
        aValues = aContent.getPropertyValues( aProps );
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }

    // Extract values from sequence.

    // Title:
    rtl::OUString aTitle;
    if ( !( aValues[ 0 ] >>= aTitle ) )
        ... error ...

    // IsFolder:
    sal_Bool bFolder;
    if ( !( aValues[ 1 ] >>= bFolder ) )
        ... error ...
}


Setting property values of a UCB Content

A UCB Content maintains a set of properties. It supports the command setPropertyValues, which can be used to set one or more property values of a content. This command takes an argument of type sequence< PropertyValue > and returns void. To set property values of a UCB Content:

  • Define a sequence of property values you want to set.

  • Let the UCB Content execute the command setPropertyValues.

Note that the command will not be aborted if one or more of the property values cannot be set (because the requested property is not supported by the content or because it is read-only). Currently there is no other way to check whether a property value was set successfully than to obain the property value after a set-operation. This may change in the near future, when status information could be returned by the command setPropertyValues.


Example 1 (C++)


using namespace com::sun::star;

{
    uno::Reference< ucb::XContent > xContent = ...
    rtl::OUString aNewTitle
            = rtl::OUString::createFromAscii( "NewTitle" );

    /////////////////////////////////////////////////////////////////////
    // Set value of the string property Title...
    /////////////////////////////////////////////////////////////////////

    // Define property value sequence.

    uno::Sequence< beans::PropertyValue > aProps( 1 );
    aProps[ 0 ].Name   = rtl::OUString::createFromAscii( "Title" );
    aProps[ 0 ].Handle = -1; // n/a
    aProps[ 0 ].Value  <<= aNewTitle;

    try
    {
        // Execute command "setPropertyValues".
        executeCommand( xContent,
                        rtl::OUString::createFromAscii(
                                            "setPropertyValues" ),
                        makeAny( aProps );
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }
}

Example 2a (C++, using UCBHELPER library)


using namespace com::sun::star;

{
    ::ucb::Content aContent = ...
    rtl::OUString aNewTitle
            = rtl::OUString::createFromAscii( "NewTitle" );

    /////////////////////////////////////////////////////////////////////
    // Set value of the string property Title...
    /////////////////////////////////////////////////////////////////////

    // Define property name sequence.
    uno::Sequence< rtl::OUString > aProps( 1 );
    aProps[ 0 ] = rtl::OUString::createFromAscii( "Title" );

    // Define property value sequence.
    uno::Sequence< uno::Any > aValues;
    aValues[ 0 ] <<= aNewTitle;

    try
    {
        // Set property values.
        aContent.setPropertyValues( aProps, aValues );
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }
}

Example 2b (C++, using UCBHELPER library)


using namespace com::sun::star;

{
    ::ucb::Content aContent = ...
    rtl::OUString aNewTitle
            = rtl::OUString::createFromAscii( "NewTitle" );

    /////////////////////////////////////////////////////////////////////
    // Set value of the string property Title...
    /////////////////////////////////////////////////////////////////////

    try
    {
        // Set property value.
        aContent.setPropertyValue(
                    rtl::OUString::createFromAscii( "Title" ),
                    makeAny( aNewTitle ) );
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }
}


Accessing the children of a UCB Folder Content

A UCB Content that is a folder (which means that the value of the required property IsFolder is true) should support the command open. This command takes an argument of type OpenCommandArgument2. The value returned is an implementation of the service ContentResultSet. This resultset can be understood as a table, where each row contains a child content of the folder content. You may travel through the rows by using the resultset's interface XResultSet. The children may be accessed by traveling to the appropriate row and using the interface XContentAccess, which is also implemented by the resultset. You may supply a sequence< Property > as part of the argument of the open command. In this case, the resultset will contain an additional column for each property value that was requested. You may access the property values by traveling to the appropriate row and calling methods of the interface XRow. There may also other parameters be passed to the open command. Refer to the documentation of OpenCommandArgument2 for more information.

To access the children of a UCB Content:

  • Fill the OpenCommandArgument2 structure according to your needs.

  • Let the UCB Content execute the command open.

  • Access the children and the requested property values using the returned resultset.


Example 1 (C++)


using namespace com::sun::star;

{
    uno::Reference< ucb::XContent > xContent = ...

    /////////////////////////////////////////////////////////////////////
    // Open a folder content, request property values for the string
    // property Title and the boolean property IsFolder...
    /////////////////////////////////////////////////////////////////////

    // Fill argument structure...

    ucb::OpenCommandArgument2 aArg;

    aArg.Mode = ucb::OpenMode::ALL; // FOLDER, DOCUMENTS -> simple filter
    aArg.Priority = 32768; // Ignored by most implementations

    // Fill info for the properties wanted.
    uno::Sequence< beans::Property > aProps( 2 );
    aProps[ 0 ].Name   = rtl::OUString::createFromAscii( "Title" );
    aProps[ 0 ].Handle = -1; // n/a
    aProps[ 1 ].Name   = rtl::OUString::createFromAscii( "IsFolder" );
    aProps[ 1 ].Handle = -1; // n/a

    aArg.Properties = aProps;

    uno::Reference< ucb::XDynamicResultSet > xSet;
    try
    {
        // Execute command "open".
        executeCommand( xContent,
                        rtl::OUString::createFromAscii( "open" ),
                        makeAny( aArg ) >>= xSet;
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }

    if ( !xSet.is() )
        ... error ...

    uno::Reference< sdbc::XResultSet > xResultSet(
                                    xSet->getStaticResultSet() );

    if ( !xResultSet.is() )
        ... error ...

    /////////////////////////////////////////////////////////////////////
    // Iterate over children, access children and property values...
    /////////////////////////////////////////////////////////////////////

    try
    {
        // Move to begin.
        if ( xResultSet->first() )
        {
            uno::Reference< ucb::XContentAccess > xContentAccess(
                                          xResultSet, uno::UNO_QUERY );
            uno::Reference< sdbc::XRow > xRow(
                                          xResultSet, uno::UNO_QUERY );

            do
            {
                // Obtain URL of child.
                rtl::OUString aId
                    = xContentAccess->queryContentIdentifierString();

//                ucb::XContent xChild
//                    = xContentAccess->queryContent();

                // First column: Title ( column numbers are 1-based! )
                rtl::OUString aTitle = xRow->getString( 1 );
                if ( aTitle.getLength() == 0 && xRow->wasNull() )
                    ... error ...

                // Second column: IsFolder
                sal_Bool bFolder = xRow->getBoolean( 2 );
                if ( !bFolder && xRow->wasNull() )
                    ... error ...
            }
            while ( xResultSet->next() ) // next child
        }
    }
    catch ( ucb::ResultSetException const & )
    {
        ... error ...
    }
}

Example 2 (C++, using UCBHELPER library)


using namespace com::sun::star;

{
    ::ucb::Content aContent = ...

    /////////////////////////////////////////////////////////////////////
    // Open a folder content, request property values for the string
    // property Title and the boolean property IsFolder...
    /////////////////////////////////////////////////////////////////////

    // Define property name sequence.
    uno::Sequence< OUString > aProps( 2 );
    aProps[ 0 ] = rtl::OUString::createFromAscii( "Title" );
    aProps[ 1 ] = rtl::OUString::createFromAscii( "IsFolder" );

    uno::Reference< sdbc::XResultSet > xResultSet;
    try
    {
        xResultSet = aContent.createCursor(
                        aProps, ::ucb::INCLUDE_FOLDERS_AND_DOCUMENTS );
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }

    if ( !xResultSet.is() )
        ... error ...

    /////////////////////////////////////////////////////////////////////
    // Iterate over children, access children and property values...
    /////////////////////////////////////////////////////////////////////

    try
    {
        // Move to begin.
        if ( xResultSet->first() )
        {
            uno::Reference< ucb::XContentAccess > xContentAccess(
                                          xResultSet, uno::UNO_QUERY );
            uno::Reference< sdbc::XRow > xRow(
                                          xResultSet, uno::UNO_QUERY );

            do
            {
                // Obtain URL of child.
                rtl::OUString aId
                    = xContentAccess->queryContentIdentifierString();

//                ucb::XContent xChild
//                    = xContentAccess->queryContent();

                // First column: Title ( column numbers are 1-based! )
                rtl::OUString aTitle = xRow->getString( 1 );
                if ( aTitle.getLength() == 0 && xRow->wasNull() )
                    ... error ...

                // Second column: IsFolder
                sal_Bool bFolder = xRow->getBoolean( 2 );
                if ( !bFolder && xRow->wasNull() )
                    ... error ...
            }
            while ( xResultSet->next() ) // next child
        }
    }
    catch ( ucb::ResultSetException const & )
    {
        ... error ...
    }
}


Accessing (loading) the content data stream of a UCB Document Content

A UCB Content that is a document (which means that the value of the required property IsDocument is true) should support the command open. The command takes an argument of type OpenCommandArgument2. Note that this command (with the same argument type) is also used to access the children of a folder. Whether you get access to the children or the data stream (or even both, for contents that support both) is controlled by the argument's Mode member, as can be seen in the examples. If you are only interested in the data stream, you can ignore the command's return value (which will presumably be a null resultset, anyway).

The caller needs to supply the implementation of a data sink with the arguments in order to get access to the document's data stream. Generally there are two different types of data sinks: XActiveDataSink and XOutputStream.

XActiveDataSink: If this type of data sink is supplied, the caller of the command is active. The implementation of the command will supply an implementation of the interface XInputStream to the given XActiveDataSink (setInputStream) and return. Once the execute-call has returned, the caller can access the input stream (getInputStream) and read the data using that stream (readBytes, readSomeBytes).

XOutputStream: If this type of data sink is supplied, the caller of the command is passive. The implementation of the command will write all data to the output stream (writeBytes) and close it (closeOutput) after all data were successfully written. Only then will the open command return.

Which type to use highly depends on the logic of the client application. If the application can be designed so that it passively processes the data supplied by an XOutputStream, using an XOutputStream as sink is advantageous, because many content providers can implement this case efficiently without buffering any data. If, on the other hand, the application is designed so that it actively reads the data, you should use an XActiveDataSink; any necessary buffering will then take place in the implementation of the open command.


Example 1 (C++)


using namespace com::sun::star;

/////////////////////////////////////////////////////////////////////////
// XActiveDataSink interface implementation.
/////////////////////////////////////////////////////////////////////////

class MyActiveDataSink : public cppu::OWeakObject,
                         public io::XActiveDataSink
{
    uno::Reference< io::XInputStream > m_xStream;

public:
    // XInterface methods
    ... queryInterface ... acquire ... release ...

    // XActiveDataSink methods.
    virtual void SAL_CALL
    setInputStream( const uno::Reference< io::XInputStream >& aStream )
        throw( uno::RuntimeException )
    { m_xStream = aStream; }

    virtual uno::Reference< io::XInputStream > SAL_CALL
    getInputStream()
        throw( uno::RuntimeException )
    { return m_xStream; }
};

{
    uno::Reference< ucb::XContent > xContent = ...

    /////////////////////////////////////////////////////////////////////
    // Read the document data stream of a document content using a
    // XActiveDataSink implementation as data sink....
    /////////////////////////////////////////////////////////////////////

    // Fill argument structure...

    ucb::OpenCommandArgument2 aArg;
    aArg.Mode = ucb::OpenMode::DOCUMENT;
    aArg.Priority = 32768; // Ignored by most implementations

    // Create data sink implementation object.
    uno::Reference< io::XActiveDataSink > xDataSink
                                                = new MyActiveDataSink;
    aArg.Sink = xDataSink;

    try
    {
        // Execute command "open". The implementation of the command will
        // supply an XInputStream implementation to the data sink.
        executeCommand( xContent,
                        rtl::OUString::createFromAscii( "open" ),
                        makeAny( aArg ) );
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }

    // Get input stream supplied by the open command implementation.
    uno::Reference< io::XInputStream > xData
                                        = xDataSink->getInputStream();
    if ( !xData.is() )
        ... error ...

    /////////////////////////////////////////////////////////////////////
    // Read data from input stream...
    /////////////////////////////////////////////////////////////////////

    try
    {
        // Data buffer. Will be allocated by input stream implementation!
        uno::Sequence< sal_Int8 > aBuffer;

        sal_Int32 nRead = xData->readSomeBytes( aBuffer, 65536 );
        while ( nRead > 0 )
        {
            // Process data contained in buffer.
            ...

            nRead = xData->readSomeBytes( aBuffer, 65536 );
        }

        // EOF.
    }
    catch ( io::NotConnectedException const & )
    {
        ... error ...
    }
    catch ( io::BufferSizeExceededException const & )
    {
        ... error ...
    }
    catch ( io::IOException const & )
    {
        ... error ...
    }
}

Example 2 (C++, using UCBHELPER library)


using namespace com::sun::star;

/////////////////////////////////////////////////////////////////////////
// XActiveDataSink interface implementation.
/////////////////////////////////////////////////////////////////////////

class MyActiveDataSink : public cppu::OWeakObject,
                         public io::XActiveDataSink
{
    uno::Reference< io::XInputStream > m_xStream;

public:
    // XInterface methods
    ... queryInterface ... acquire ... release ...

    // XActiveDataSink methods.
    virtual void SAL_CALL
    setInputStream( const uno::Reference< io::XInputStream >& aStream )
        throw( uno::RuntimeException )
    { m_xStream = aStream; }

    virtual uno::Reference< io::XInputStream > SAL_CALL
    getInputStream()
        throw( uno::RuntimeException )
    { return m_xStream; }
};

{
    ::ucb::Content aContent = ...

    /////////////////////////////////////////////////////////////////////
    // Read the document data stream of a document content using a
    // XActiveDataSink implementation as data sink....
    /////////////////////////////////////////////////////////////////////

    uno::Reference< io::XActiveDataSink > xDataSink
                                                = new MyActiveDataSink;
    try
    {
        aContent.openStream( xDataSink );
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }

    // Get input stream supplied by the open command implementation.
    uno::Reference< io::XInputStream > xData
                                        = xDataSink->getInputStream();
    if ( !xData.is() )
        ... error ...

    /////////////////////////////////////////////////////////////////////
    // Read data from input stream...
    /////////////////////////////////////////////////////////////////////

    try
    {
        // Data buffer. Will be allocated by input stream implementation!
        uno::Sequence< sal_Int8 > aBuffer;

        sal_Int32 nRead = xData->readSomeBytes( aBuffer, 65536 );
        while ( nRead > 0 )
        {
            // Process data contained in buffer.
            ...

            nRead = xData->readSomeBytes( aBuffer, 65536 );
        }

        // EOF.
    }
    catch ( io::NotConnectedException const & )
    {
        ... error ...
    }
    catch ( io::BufferSizeExceededException const & )
    {
        ... error ...
    }
    catch ( io::IOException const & )
    {
        ... error ...
    }
}


Setting (storing) the content data stream of a UCB Document Content

A UCB Content that is a document (which means that the value of the required property IsDocument is true) should support the command insert. This command can be used to (over)write the document's data stream. The command requires an argument of type InsertCommandArgument and returns void. The caller needs to supply the implementation of an XInputStream with the command argument. This stream contains the data to be written. An additional flag indicating whether a possibly existing content (and its data) shall be overwritten may be supplied with the command argument. Implementations that are not able to detect whether there are previous data may ignore this parameter and will always write the new data!


Example 1 (C++)


using namespace com::sun::star;

{
    uno::Reference< ucb::XContent > xContent = ...
    uno::Reference< io::XInputStream > xData = ... // The data to write.

    /////////////////////////////////////////////////////////////////////
    // Write the document data stream of a document content...
    /////////////////////////////////////////////////////////////////////

    // Fill argument structure...

    ucb::InsertCommandArgument aArg;
    aArg.Data = xData;
    aArg.ReplaceExisting = true;

    try
    {
        // Execute command "insert".
        executeCommand( xContent,
                        rtl::OUString::createFromAscii( "insert" ),
                        makeAny( aArg ) );
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }
}

Example 2 (C++, using UCBHELPER library)


using namespace com::sun::star;

{
    ::ucb::Content aContent = ...
    uno::Reference< io::XInputStream > xData = ... // The data to write.

    /////////////////////////////////////////////////////////////////////
    // Write the document data stream of a document content...
    /////////////////////////////////////////////////////////////////////

    try
    {
        aContent.writeStream( xData, true /* replaceexisting */  );
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }
}


Creating a new resource

A UCB Content that implements the interface XContentCreator can act as a factory for new resources. For example, a file system folder could be a creator for other file system folders and files.

A new content object created by the XContentCreator implementation can be considered as an empty hull for a content object of a special type. So this new content object may need to be filled with some property values in order to become fully functional. For example, a file system folder could require a name, which is represented by the property "Title" in the UCB. The interface XContentCreator offers ways to determine what contents can be created and what properties need to be set to get them alive. You may also obtain information on the general kind (FOLDER, DOCUMENT, LINK) of that objects. After all required property values are set, the creation process needs to be committed. This is done using the command insert. Note that this command is always executed at the new content, not at the content creator! This is because the creator is not necessarily the parent of the new content. For a description of the insert-command refer to section Setting (storing) the content data stream of a UCB Document Content. One noticeable fact here is that the flag ReplaceExisting in the insert-command argument usually will be false (the caller generally does not want to destroy an already existing resource). The insert-command implementation will make the new content persistent in the appropriate storage medium.

To create a new resource:

  • Obtain the interface XContentCreator from a suitable UCB Content.

  • Call createNewContent at the content creator. Supply information on the type of content to create with the arguments.

  • Obtain and set the property values that are mandatory for the content just created.

  • Let the new content execute the command insert to complete the creation process.


Example 1 (C++)


using namespace com::sun::star;

{
    uno::Reference< ucb::XContent > xContent = ...

    /////////////////////////////////////////////////////////////////////
    // Create a new file system file object...
    /////////////////////////////////////////////////////////////////////

    // Obtain content creator interface.
    uno::Reference< XContentCreator > xCreator(
                                            xContent, uno::UNO_QUERY );

    if ( !xCreator.is() )
        ... error ...

    // Note: The data for aInfo may have been obtained using
    //       XContentCreator::queryCreatableContentsInfo().

    ucb::ContentInfo aInfo;
    aInfo.Type = rtl::OUString::createFromAscii(
                        "application/vnd.sun.staroffice.fsys-file" );
    aInfo.Attributes = 0;

    // Create new, empty content.
    uno::Reference< ucb::XContent > xNewContent
                        = xCreator->createNewContent( aInfo );

    if ( !xNewContent.is() )
        ... error ...

    /////////////////////////////////////////////////////////////////////
    // Set mandatory properties...
    /////////////////////////////////////////////////////////////////////

    // Obtain a name for the new file.
    rtl::OUString aFilename = ...

    // Define property value sequence.
    uno::Sequence< beans::PropertyValue > aProps( 1 );
    aProps[ 0 ].Name   = rtl::OUString::createFromAscii( "Title" );
    aProps[ 0 ].Handle = -1; // n/a
    aProps[ 0 ].Value  <<= aFilename;

    try
    {
        // Execute command "setPropertyValues".
        executeCommand( xNewContent,
                        rtl::OUString::createFromAscii(
                                            "setPropertyValues" ),
                        makeAny( aProps );
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }

    /////////////////////////////////////////////////////////////////////
    // Write the new file to disk...
    /////////////////////////////////////////////////////////////////////

    // Obtain document data for the new file.
    uno::Reference< io::XInputStream > xData = ...

    // Fill argument structure...
    ucb::InsertCommandArgument aArg;
    aArg.Data = xData;
    aArg.ReplaceExisting = false;

    try
    {
        // Execute command "insert".
        executeCommand( xNewContent,
                        rtl::OUString::createFromAscii( "insert" ),
                        makeAny( aArg ) );
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }
}

Example 2 (C++, using UCBHELPER library)


using namespace com::sun::star;

{
    ::ucb::Content aContent = ...

    /////////////////////////////////////////////////////////////////////
    // Create, setup and commit a new file system file object...
    /////////////////////////////////////////////////////////////////////

    // Obtain a name for the new file.
    rtl::OUString aFilename = ...

    // Obtain document data for the new file.
    uno::Reference< io::XInputStream > xData = ...

    uno::Sequence< rtl::OUString > aProps( 1 );
    aProps[ 0 ] = rtl::OUString::createFromAscii( "Title" );

    uno::Sequence< uno::Any > aValues( 1 );
    aValues[ 0 ] <<= aFilename;

    ::ucb::Content aNewContent;
    try
    {
        aContent.insertNewContent(
                    rtl::OUString::createFromAscii(
                        "application/vnd.sun.staroffice.fsys-file" ),
                    aProps,
                    aValues,
                    xData,
                    aNewContent ); // out parameter!
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }
}


Deleting a resource

Executing the command delete on a UCB Content will destroy the resource it represents. This command takes a boolean parameter. If it is set to true, the resource will be immediately and physically destroyed. The command will also destroy all existing sub resources of the resource to be destroyed! If false is passed to this command, then the caller only wants to delete the resource "logically." This means that the resource can be either restored or physically destroyed later. A soft-deleted Content needs to support the command undelete. This command will bring it back to life. The implementation of the delete command can ignore the parameter and may opt to always destroy the resource physically.

Note: Currently we do not have a Trash Service that could be used by UCB clients to manage soft-deleted Contents.


Example 1 (C++)


using namespace com::sun::star;

{
    uno::Reference< ucb::XContent > xContent = ...

    /////////////////////////////////////////////////////////////////////
    // Destroy a resource physically...
    /////////////////////////////////////////////////////////////////////

    try
    {
        sal_Bool bDeletePhysically = sal_True;

        // Execute command "delete".
        executeCommand( xContent,
                        rtl::OUString::createFromAscii( "delete" ),
                        makeAny( bDeletePhysically ) );
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }
}

Example 2 (C++, using UCBHELPER library)


using namespace com::sun::star;

{
    ::ucb::Content aContent = ...

    /////////////////////////////////////////////////////////////////////
    // Destroy a resource physically...
    /////////////////////////////////////////////////////////////////////

    try
    {
        sal_Bool bDeletePhysically = sal_True;

        // There is no special wrapper method for this simple command.
        // Use generic command invocation method.
        aContent.executeCommand(
                        rtl::OUString::createFromAscii( "delete" ),
                        makeAny( bDeletePhysically ) );
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }
}


Copying, Moving and Creating links to a resource

Copying, moving and creating links to a resource works a little differently from the other operations available for UCB Contents. This is because there are three UCB Contents involved in these operations (the source object, the target folder, the target object), not just one. There may even participation by two Content Providers (e.g., when moving a file located on an FTP server to the local file system of a workstation). Each implementation of the UniversalContentBroker service must support the XCommandProcessor interface. This command processor must implement the command globalTransfer that can be used to copy and move UCB Contents and to create links to UCB Contents. The command takes an argument of type GlobalTransferCommandArgument. To copy, move or create a link to a resource simply execute the globalTransfer command at the UCB.

Note: The reasons for the different handling are mainly technical. We did not want to force every single implementation of the transfer command of a UCB Content to be able to accept (nearly) all types of Contents. Instead, we wanted to have one single implementation that would be able to handle all types of Contents. However, the UCBHELPER library encapsulates this exception and offers a special method for this functionality at the Content helper class. It must be called at the UCB Content representing the target folder of the operation.


Example 1 (C++)


using namespace com::sun::star;

{
    rtl::OUString aSourceURL = ...       // URL of the source object
    rtl::OUString aTargetFolderURL = ... // URL of the target folder

    /////////////////////////////////////////////////////////////////////
    // Obtain access to UCB...
    /////////////////////////////////////////////////////////////////////

    uno::Reference< uno::XInterface > xUCB = ...

    // Obtain XCommandProcessor interface from UCB...
    uno::Reference< ucb::XCommandProcessor > xCmdProc(
                                                  xUCB, uno::UNO_QUERY );
    if ( !xProcessor.is() )
        ... error ...

    /////////////////////////////////////////////////////////////////////
    // Copy a resource to another location...
    /////////////////////////////////////////////////////////////////////

    try
    {
        ucb::GlobalTransferCommandArgument aArg;
        aArg.TransferCommandOperation = TransferCommandOperation_COPY;
        aArg.SourceURL                = aSourceURL;
        aArg.TargetURL                = aTargetFolderURL;

        // object keeps it current name
        aArg.NewTitle                 = rtl::OUString();

        // fail, if object with same name exists in target folder
        aArg.NameClash                = NameClash::ERROR;

        // Let UCB execute the command "globalTransfer".
        executeCommand( xCmdProc,
                        rtl::OUString::createFromAscii(
                                            "globalTransfer" ),
                        makeAny( aArg ) );
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }
}

Example 2 (C++, using UCBHELPER library)


using namespace com::sun::star;

{
    ::ucb::Content aSourceContent = ...       // source content
    ::ucb::Content aTargetFolderContent = ... // target folder content

    /////////////////////////////////////////////////////////////////////
    // Copy a resource...
    /////////////////////////////////////////////////////////////////////

    ::ucb::Content aNewContent;
    try
    {
        aTargetFolderContent.insertNewContent(
                                aSourceContent,
                                InsertOperation_COPY, // MOVE | LINK
                                aNewContent ); // out parameter!
    }
    catch ( ucb::CommandAbortedException const & )
    {
        ... error ...
    }
    catch ( uno::Exception const & )
    {
        ... error ...
    }
}




Author: Kai Sommerfeld ($Date: 2002/08/29 10:43:19 $)
Copyright 2001 OpenOffice.org Foundation. All Rights Reserved.



Apache Software Foundation

Copyright & License | Privacy | Contact Us | Donate | Thanks

Apache, OpenOffice, OpenOffice.org and the seagull logo are registered trademarks of The Apache Software Foundation. The Apache feather logo is a trademark of The Apache Software Foundation. Other names appearing on the site may be trademarks of their respective owners.