1. Overview

CUBA WebDAV Add-on provides the following functionalities:

  • Editing and viewing documents using desktop versions of external applications (MS Word, MS Excel, etc.).

  • Document version control. After the document is updated, a new version is created on the server side. At the same time, the component supports working with documents having both enabled and disabled versioning.

  • Granting and restricting access to certain documents.

2. Release Notes

Release 2.5.2

Release 2.5.0

  • Support for CUBA Platform 7.2.x.

Release 2.4.1

  • Fixed error on saving documents in the Libreoffice.

Release 2.4.0

  • Support for CUBA Platform 7.1.x.

3. Getting Started

3.1. Minimal Requirements

The minimum version of Microsoft Office required for opening documents via the WebDAV protocol is MS Office 2010 SP2 or higher. The minimum version of LibreOffice is 6.3.

To check which versions of Microsoft Office and Service Pack (SP) are installed on your computer, launch MS Word and open the Product Information section from File → Help.

Service Pack 2 for MS Office 2010 (and later versions) should have the following number: 14.0.7015.1000 (or greater). To update your Service Pack, follow this link.

3.2. Installation

3.2.1. Installation of Trial Version

In case you’ve got a trial version of the add-on and have a ZIP file with artifacts, follow the instructions. Please ensure you have Studio version 12 or newer installed.

  1. Create a directory called repository in the root directory of your project.

  2. Unzip the file with artifacts into this directory. You should get the following directory structure:

    structure
  3. Register the new Maven repository in the build.gradle file.

    maven {
        url './repository'
        }
    buildscript
  4. Go to CUBA → Marketplace in the main menu.

    main menu
  5. Click the icon in the upper-right corner.

    gear
  6. Enter coordinates of the latest add-on version. Copy coordinates from the Component Coordinates section on the page of the add-on on the marketplace.

    copy coordinates
  7. Add .trial at the end of the coordinates, for example:

    coordinates
  8. Click OK and Apply. The installation will start.

3.2.2. Installation of Purchased Add-on

If you have a subscription for the add-on follow the steps below. Please ensure you have Studio version 12 or newer installed.

  1. Double-click Add-ons in the CUBA project tree.

    marketplace
  2. Select Marketplace tab and find WebDAV add-on.

    webdav addon
  3. Click Install button and confirm that you have a subscription in the appeared dialog.

    subscription
  4. Click Apply & Close button and then Continue in the dialog.

    continue

WebDAV add-on will be installed in your project.

3.2.3. Manual Installation

Use this way of installation in case you build your project from the command line or your subscription does not include Studio Premium Subscription.

Adding Premium Repository

Open build.gradle file and add one more repository:

  • If the main repository is repo.cuba-platform.com, add https://repo.cuba-platform.com/content/groups/premium

    buildscript {
        // ...
        repositories {
            // ...
            maven {
                url 'https://repo.cuba-platform.com/content/groups/premium'
                credentials {
                    username(rootProject.hasProperty('premiumRepoUser') ?
                            rootProject['premiumRepoUser'] : System.getenv('CUBA_PREMIUM_USER'))
                    password(rootProject.hasProperty('premiumRepoPass') ?
                            rootProject['premiumRepoPass'] : System.getenv('CUBA_PREMIUM_PASSWORD'))
                }
            }
        }
    }
  • If the main repository is Bintray, add https://cuba-platform.bintray.com/premium

    buildscript {
        // ...
        repositories {
            // ...
            maven {
                url 'https://cuba-platform.bintray.com/premium'
                credentials {
                    username(rootProject.hasProperty('bintrayPremiumRepoUser') ?
                            rootProject['bintrayPremiumRepoUser'] : System.getenv('CUBA_PREMIUM_USER'))
                    password(rootProject.hasProperty('premiumRepoPass') ?
                            rootProject['premiumRepoPass'] : System.getenv('CUBA_PREMIUM_PASSWORD'))
                }
            }
        }
    }

Providing Credentials

Your license key consists of two parts: the first part before the dash is a repository user name, the part after the dash is a password. For example, if your key is 111111222222-abcdefabcdef, then the user name is 111111222222 and the password is abcdefabcdef. In case of Bintray, the user name must be followed by @cuba-platform.

You can provide the credentials in one of the following ways:

  • The recommended way is to create a ~/.gradle/gradle.properties file in your user home directory and set properties in it:

    premiumRepoUser=111111222222
    bintrayPremiumRepoUser=111111222222@cuba-platform
    premiumRepoPass=abcdefabcdef
  • Alternatively, you can specify the credentials in the CUBA_PREMIUM_USER and CUBA_PREMIUM_PASSWORD environment variables.

  • When you run Gradle tasks from the command line, you can also pass the properties as command-line arguments with the -P prefix, for example:

    gradlew assemble -PpremiumRepoUser=111111222222 -PpremiumRepoPass=abcdefabcdef

Adding Component

  1. In the build.gradle file specify the component artifacts in the dependencies section as follows:

    com.haulmont.webdav:webdav-global:<add-on version>

    where <add-on version> is compatible with the used version of the CUBA platform.

    Platform Version

    Add-on Version

    7.2.x

    2.5.2

    7.1.x

    2.4.0

    7.0.x

    2.3.4

    6.10.x

    2.2.1

    6.9.x

    2.1.0

    6.8.x

    2.0.0

    For example:

    dependencies {
       //...
       appComponent("com.haulmont.webdav:webdav-global:2.5.2")
    }
  2. Specify the add-on identifier com.haulmont.webdav in the web.xml files of the core and web modules in the appComponents context parameter:

    <context-param>
           <param-name>appComponents</param-name>
           <param-value>com.haulmont.cuba com.haulmont.webdav</param-value>
    </context-param>
  3. If you run Gradle tasks from the command line run gradlew assemble.

The add-on will be included in your project.

3.3. HTTPS

By default, the component uses basic authentication. Basic authentication requires an encrypted connection (https). Example settings for Tomcat can be found here.

3.4. Enabling Component

Installing the WebDAV component to the system, which is already in production use, does not entail any visible changes in the application behavior.

The component functionalities are available only for fields of the FileDescriptor and WebdavDocument types. To enable them, use one (or several if required) of the options provided below:

  • Enabling the functionalities for all fields of the FileDescriptor type.

    Set the value of the webdav.enabled property to true. After this, WebDAV will be enabled for all fields of the FileDescriptor type (for more information, refer to Application Properties).

  • Enabling the functionalities for particular fields using the @WebdavSupport annotation.

    Tip

    Using this option allows enabling WebDAV only for fields of the FileDescriptor type. However, versioning can be enabled for fields of both FileDescriptor and WebdavDocument types.

    @Table(name = "CONTRACTSYSTEM_CONTRACT")
    @Entity(name = "contractsystem$Contract")
    public class Contract extends StandardEntity {
        // ...
    
        @WebdavSupport
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "DOCUMENT_ID")
        protected FileDescriptor document;
    
        // ...
    }
  • Enabling the functionalities for fields of the WebdavDocument type. To learn how to create attributes of the WebdavDocument type, please refer to Creating Attributes of the WebdavDocument Type.

    @Table(name = "CONTRACTSYSTEM_CONTRACT")
    @Entity(name = "contractsystem$Contract")
    public class Contract extends StandardEntity {
        // ...
    
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "DOCUMENT_ID")
        protected WebdavDocument document;
    
        // ...
    }

The figure below shows how the Document field is displayed when the component functionalities are enabled.

webdav example
Tip

After enabling the WebDAV component, its functionalities are available only when working with freshly-created objects. To apply changes to the previously created objects, it is required to migrate the data. For more details, see Data Migration.

Before using the component, check that all application properties are configured properly. For more information, get acquainted with Application Properties.

If you want to use WebDAV fields in the CUBA form element, you need to add WebDAV component scheme to your screen XML file:

xmlns:webdav="http://schemas.haulmont.com/webdav/ui-component.xsd"

The following fields can be used to manage WebDAV documents:

  • webdav-document-upload - field for WebDAV document

  • file-descriptor-upload - field for FileDescriptor

The component enables you to receive a link to a document, which can be published on a web-portal or passed to third parties. When opening the link, your browser requests credentials for accessing the document/document version. After successful authorization, the document/version is opened in a desktop version of an external application.

4. Component Features

4.1. Data Model

4.1.1. WebdavSupport Annotation

The @WebdavSupport annotation defines whether the component functionality is enabled for a particular field. The annotation can be specified for fields of the FileDescriptor and WebdavDocument types.

Parameters:

  • versioning - enables versioning support for a particular field.

  • enabled - disables/enables the component functionalities for a field. Note that this parameter is notapplicable to fields of the WebdavDocument type.

4.1.2. Examples

Example 1. Setting up @WebdavSupport for a field of the FileDescriptor type.

@Table(name = "CONTRACTSYSTEM_CONTRACT")
@Entity(name = "contractsystem$Contract")
public class Contract extends StandardEntity {
   // ...

   @WebdavSupport
   @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "DOCUMENT_ID")
   protected FileDescriptor document;

   // ...
}

Example 2. Setting up @WebdavSupport for a field of the WebdavDocument type.

@Table(name = "CONTRACTSYSTEM_CONTRACT")
@Entity(name = "contractsystem$Contract")
public class Contract extends StandardEntity {
   // ...

   @OneToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "DOCUMENT_ID")
   protected WebdavDocument document;

   // ...
}

4.2. Version Control

4.2.1. Document Version Manager

Document Version Manager provides a number of functionalities for maintaining document versions. This functionality is supported only if versioning is enabled for a document.

There are two possible modes of working with the screen: editing and read only.

When editing is available, the screen is opened via the WebdavDocumentUploadField component by clicking a link with a document version number.

webdav document upload field version link

After that, the Document versions manager dialog window is opened.

document versions window

When editing is enabled, Document Version Manager supports the following operations:

  1. Creating a new document version. Clicking Upload allows selecting files to upload to the system. This can also be done by dragging and dropping a required file to the DropZone. After that, uploaded files are numbered in accordance with the number of the latest document version. Numbers of new versions are tagged with the * symbol. This means that they have been uploaded but are not linked to a document yet. Thus, version numbers can be updated after saving the changes. If the dialog window is closed without saving, then all versions tagged with * will be removed after launching the WebdavDocumentVersionsCleaner.

    document versions window drag and drop
  2. Creating a new document version based on another one. Selecting a document version and clicking the Copy to head button enables copying and numerating it in accordance with the number of the latest document version. Numbers of new versions are tagged with the * symbol. This means that they have been uploaded but are not linked to a document yet. Thus, version numbers can be updated after saving the changes. If the dialog window is closed without saving, then all versions tagged with * will be removed after launching the WebdavDocumentVersionsCleaner.

    document versions window copy to head
  3. Opening a document for editing. Every time a document is saved in an external application, its new version is sent to the database. Use the Refresh button to update the list of document versions shown in Document Version Manager.

    Tip

    Clicking Refresh deletes all unsaved document versions. Thus, if some document version was copied and not saved, then the changes are discarded.

  4. Opening a document for reading (read only). To open a document for reading, it is required to click a link with a file name.

  5. Downloading a ZIP archive with one or several document versions. The Download button contains two options for downloading selected documents/versions. The first option allows downloading documents as separate files. The Download as ZIP option enables sending all selected documents to the ZIP archive and downloading it. For the sake of convenience, file names contain -v suffixes with corresponding version numbers, e.g. example-v3.docx, document-v1.docx.

4.2.2. Conflict Resolution Policies

There are several policies intended to resolve conflicts, which may occur when collaborate editing a document. By default, RejectMergePolicy is applied.

Let us consider an example of how these policies can be helpful. For instance, two users simultaneously opened the same document in Document Version Manager and added a bunch of new versions. The first user finished working with their versions and saved the changes. After that, the second user did the same and, at that moment, the database contained versions created by both the first and the second user. However, each user can see only their versions in Document Version Manager.

This situation may cause issues with ordering and saving these conflicting document versions. In order to resolve the conflicts, the policies mentioned below can be used.

RebaseMergePolicy

RebaseMergePolicy allows putting new versions of a document after the ones, which already exist in the database. New versions are numbered in accordance with the number of the latest document version existing in the database.

Let us return to our example: two users opened the same document in Document Version Manager.

conflict base screen

The first user added a new document version.

conflict user1 added new version

After that, the second user also added a new version and saved the changes. After saving, this version is shown as the third one and we can see the version created by the first user as well.

conflict user2 added new version

CancelMyMergePolicy

If document versions have changed when working in Document Version Manager, then all versions marked with * are deleted.

CancelTheirMergePolicy

If document versions have changed when working in Document Version Manager, then all versions marked with * are saved instead of the ones added in Document Version Manager.

RejectMergePolicy

If a conflict occurs, the corresponding warning is displayed and all new versions are not saved.

4.2.3. Overriding Default Conflict Resolution Policy

If it is required to change the system behavior regarding conflicts, the following steps should be taken. Each step is illustrated with code samples describing how to change the default policy to RejectPolicyMergePolicy.

  1. Create a custom DataSupplier class inherited from WebdavDataSupplier and override the getDefaultMergePolicy method so that it returned an instance of a policy class.

    public class RejectDataSupplier extends WebdavDataSupplier {
    
        @Override
        protected MergePolicy<WebdavDocumentVersion> getDefaultMergePolicy() {
            return new RejectMergePolicy<>();
        }
    }
  2. Create a screen inherited from webdav-show-document-version-edit.xml and override it. Specify the previously created DataSupplier class in the descriptor.

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
            dataSupplier="com.haulmont.contractsystem.data.RejectDataSupplier"
            extends="com/haulmont/webdav/web/screens/documentversion/webdav-show-document-version-edit.xml">
        <layout/>
    </window>
  3. Add the screen with the webdav$WebdavShowDocumentVersion.edit identifier to the menu.

    <screen id="webdav$WebdavShowDocumentVersion.edit"
                template="com/haulmont/contractsystem/web/screens/ext-webdav-document-version-edit.xml"/>

    As a result, when a conflict occurs, the WebdavRejectMergePolicyException is thrown and the corresponding message is shown.

    conflict reject merge policy

4.3. Data Migration

4.3.1. Data Migration Overview

WebDAV functionalities are unavailable for already existing data until it is migrated.

For example, let us enable WebDAV for the document attribute of the Contract entity using the @WebdavSupport annotation (see WebdavSupport Annotation).

@Table(name = "CONTRACTSYSTEM_CONTRACT")
@Entity(name = "contractsystem$Contract")
public class Contract extends StandardEntity {

   ...

   @NotNull
   @WebdavSupport //Enable WebDav
   @OnDelete(DeletePolicy.CASCADE)
   @ManyToOne(fetch = FetchType.LAZY, optional = false)
   @JoinColumn(name = "DOCUMENT_ID")
   protected FileDescriptor document;

   ...

As it can be seen from the figure below, the Migration is required notification is displayed instead of links. This happens because after enabling or disabling the component, all previously created entities require migration. During the migration process, new instances of WebdavDocumentVersion and WebdavDocument are created for each document. And if it is skipped, then it is impossible to edit the 'document' attribute because it is considered related to the entity, which is not migrated yet.

migration 1 1
Tip

There is no need to migrate freshly-created entities.

The data migration process can be executed from Migration Screen (Menu: Administration → WebDAV → Migration Screen). On the screen, there is a list of entity attributes, which support WebDAV (attributes of the FileDescriptor and WebdavDocument types). All listed attributes are grouped into entity packages.

Warning

It is highly recommended to back up the existing database before launching the migration process.

Warning

Entities, which belong to the basic com.haulmont.cuba package, are included in the list on Migration Screen so that their further extension and use of @WebDavSupport was possible. If you do not extend these entities and/or screens related to them, please do not select them for migration.

To start migration, it is necessary to select the required fields/entities, for which WebDAV or versioning was enabled/disabled and click the Do migration button. Once the migration process is finished, a system message containing a list of entities that were created / updated / deleted appears. If some entities were not found, the 'No data for migration' notification is shown. If some fields require removal of WebdavDocument entities, then a corresponding message is displayed.

Data migration is required in the following cases:

  1. Enabling/disabling WebDav. If WebDAV is enabled for attributes of one or several entities, then during migration, new instances of WebdavDocumentVersion and WebdavDocument are created for attributes of the FileDescriptor type. Created entities may have versioning enabled or disabled. It depends on the annotation value and a global parameter. If some field has WebDAV disabled, then instances of WebdavDocumentVersion and WebdavDocument are deleted.

  2. Enabling/disabling versioning. Launching the migration after enabling/disabling versioning updates the existing instances of WebdavDocument for fields of one or several entities.

Tip

Attributes of the FileDescriptor type store the first versions of documents. After disabling WebDav and launching migration, values of these fields are changed to the latest document versions. Another important moment is that it is impossible to disable WebDAV for attributes of the WebdavDocument type (only versioning can be disabled).

In the sections below, you can find two examples of data migration: after enabling and disabling WebDav.

Data Migration After Enabling WebDav

The first example describes the process of migrating data after enabling WebDAV for the 'document' attribute of the Contract entity.

@Table(name = "CONTRACTSYSTEM_CONTRACT")
@Entity(name = "contractsystem$Contract")
public class Contract extends StandardEntity {

   ...

   @NotNull
   @WebdavSupport //Enable WebDav
   @OnDelete(DeletePolicy.CASCADE)
   @ManyToOne(fetch = FetchType.LAZY, optional = false)
   @JoinColumn(name = "DOCUMENT_ID")
   protected FileDescriptor document;

   ...

Let’s imagine that there are several instances of the Contract entity, which were created before enabling WebDav. For the sake of convenience, we add WebdavDocumentLink for each instance of 'document' in Contract Browser. For example, this can be done by using generated columns.

@Inject
protected ComponentsFactory componentsFactory;

public Component generateLinkCell(Contract entity) {
   return componentsFactory.createComponent(WebdavDocumentLink.class)
           .withFileDescriptor(entity.getDocument());
}

After adding a column, the Migration is required caption is shown instead of links related to unmigrated entities.

migration 1 2

As it can be seen from the figure below, there are no restrictions applied to new entities.

migration 1 3

Now, let’s open Migration Screen (Menu: Administration → WebDAV → Migration screen) and select the document field related to the Contract entity for migration.

migration 1 4

Launching migration is available by clicking the Migrate button. Once the process is completed, the system displays its results.

migration 1 5

As we can see, three instances of WebdavDocument which have versioning enabled were created. If we open Contract Browser again, we can see that after migration, all required links are present.

migration 1 6

4.3.2. Data Migration After Disabling WebDav

Having the previous example in consideration, let’s check how migration affects fields, for which WebDAV has been disabled. We will use the same Contract entity. Let’s assume that there are several WebDAV entities linked to the 'document' field, which were created before. To get a full picture of how the migration process works in this case, let’s upload a new document version for the Contract #3 entity — New contract #3.docx.

migration 2 1

The next step is to remove the @WebdavSupport annotation for the 'document' field of the Contract entity by selecting the field on Migration Screen and launching migration. The system shows the Confirmation dialog window saying that all WebdavDocument entities corresponding to the selected field will be removed.

migration 2 2

After confirming the operation, the migration process results are displayed.

migration 2 3

During the migration process, WebDAV documents were deleted and FileDescriptor was updated to the latest version for one entity. If we open Contract Browser again, we can see that all links are disabled.

migration 2 4

If we open the New Contract entity in the Contract Editor, we can see the latest document version.

migration 2 5

4.4. Scheduled Tasks

WebdavLockExpiredCleaner

  • Method: removeUnreferencedVersions

  • Interval: 2 hours

  • Description: Removes expired lock-objects

WebdavDocumentVersionsCleaner

  • Method: removeUnreferencedVersions

  • Interval: 1 month

  • Description: Removes WebdavDocumentVersion instances, which do not have links to documents

Tip

In order to not remove versions, which are currently being edited, the versions created less than a day ago (from the current time) are excluded from the task. For instance, if today is 10.02.18, then versions created on 09.02.18 00:00 are ignored.

4.5. Security

When enabling the WebDAV component, 4 restrictions for creating, reading, updating and removing WebdavDocumentVersion entities are created. The same set of access rights is available to a user for working with a document and corresponding document versions.

If it is required to restrict a particular user to edit or read document versions, this can be done by changing permissions applicable to a user role. Find out more here.

4.5.1. WebDAV Predefined Roles

  • WebDAV basic role - basic WebDAV role which grants access for all WebDAV related entities.

  • WebDAV documents role - grants access to WebDAV documents browser.

  • WebDAV migration role - grants access to WebDAV documents migration browser.

4.5.2. WebdavDocument Access Restrictions

Let us consider the following example. There is the 'Clients' role created in the system and it is necessary to restrict users with this role to read WebDAV documents. For this purpose, configure the 'Clients' role as it is shown in the figure below (for more details, refer to this documentation).

sec 1 1

After this, all users with the 'Clients' role will not be able to use links to WebDAV documents — the Migration is required notification will be displayed.

sec 1 2

The same notification will be shown in WebdavDocumentUploadField.

sec 1 3

4.5.3. Usage of Constraints to Restrict Access to WebdavDocument

Another example shows how to restrict access to a particular group of users. Let us consider that there is an access group called 'Users'. It is required to configure an access group in such a way that only document authors can edit documents / document versions. This can be done by creating a new constraint in Menu: Administration → Access → Constraints.

sec 2 1

Create a new restriction with the Update type for the webdav$WebdavDocument entity:

import com.haulmont.cuba.core.global.*

if (PersistenceHelper.isNew({E})) {
    return true
}

def dm = AppBeans.get(DataManager)
def document = dm.reload({E}, "webdavDocument-with-versions-view")

return document.createdBy == userSession.user.login
sec 2 2

The system checks whether the current user is a document author. If it is not the case, then the user will not be allowed to edit a document and the following notification message will be displayed.

sec 2 3

All buttons intended to manage document versions will be inactive and the document itself will not be saved on the server side after opening it in an external application.

sec 2 4

4.6. Using Digest Authentication

Digest auth example can be found in Digest authentication configuration example.

  1. Place the config in the main package in the web module, for example: com/company/app/webdav-dispatcher-spring.xml

  2. Replace default WebDAV dispatcher config by adding the property with path to new config to web-app.properties: webdav.dispatcherSpringContextConfig = com/company/app/webdav-dispatcher-spring.xml

Tip

If there are some application users created in the system before activating the WebDAV component (e.g. admin), the component functionalities are not available to them. To grant those users access, it is mandatory to change their passwords.

Please see documentation for more details.

5. Main Services

5.1. WebdavCredentialsManagementService

Designed to work with WebdavCredentials. The service is used to get credentials of a user with a local or {@code viewName} view by a user ID / login / user.

WebdavCredentials required for Digest Authentication.

5.2. WebdavDocumentsManagementService

Designed to work with WebdavDocument. The service methods allow you to:

  • receive a document by a document / file/ document version ID / FileDescriptor ID / document ID / document version;

  • restrict/grant access to a document for a certain period;

  • create / update / delete a document;

  • create / update / delete versions of a particular document.

5.3. WebdavDocumentVersionsManagementService

The service is used to work with document versions. It enables you to:

  • get the first version of a document;

  • receive the latest version of a document;

  • get a particular version of a document;

  • get all existing versions of a document;

  • create / update / delete a document versions.

5.4. WebdavMigrationService

The service methods allow executing the following operations:

  • executing the migration process;

  • getting the information about classes and properties to be migrated;

  • receiving the information about migration types (can be used only on the middleware level);

  • getting results of the migration process, e.g. defines whether some files are expected to be removed after migration.

5.5. WebdavRawLinksManagementService

It is designed to work with persistent links. Persistent links are stored in the database as instances of the WebdavLink entity and they are related to instances of either the WebdavDocument or WebdavDocumentVersion entities. For more details, please refer to the Links section.

The service methods allow you to create persistent links to a document with a default / read-only / specific context.

5.6. WebdavUrlManagementService

The service is used for getting impersistent links to documents. These links are not stored in the database and generated on the go. For more details, please refer to the Links section.

The service enables executing the following operations:

  • getting a link to the latest document version in full access/read-only mode;

  • getting a link to a particular document version in full access/read-only mode;

  • receiving information about an external application used for opening a document version.

5.7. WebdavUserDetailsService

WebdavUserDetailsService enables searching for a user by their username. In the actual implementation, the search may be case sensitive, or case insensitive, depending on how the implementation instance is configured. In this case, the returned UserDetails object may have different a username.

5.8. WebdavUserManagementService

The service is used for changing a user password.

6. UI Components

WebdavDocumentLink is a CUBA Platform UI component that provides the functionality of reading and editing documents using Microsoft Office Apps. Also, if versioning is supported for a document, a user can see all versions of a document.

Component XML name: document-link.

document link

The component features the following functionalities:

  • Opening the latest version of a document for reading/editing.

  • Opening preceding document versions in read-only mode (for more details, see Document Version Manager).

6.1.1. Work Modes

The component works in the following three modes:

  • WebDAV is disabled.

  • WebDAV is enabled, Versioning is disabled.

  • WebDAV is enabled, Versioning is enabled.

WebDAV is enabled

WebDAV is disabled

Versioning is enabled

WebdavDocumentLink is displayed without any restrictions

In this mode WebdavDocumentLink is displayed as an empty element

Versioning is disabled

WebdavDocumentLink does not show a link to the latest document version

In this mode WebdavDocumentLink is displayed as an empty element

6.1.2. Declarative Creation

To use the WebDAV components in XML, it is required to specify the http://schemas.haulmont.com/webdav/ui-component.xsd scheme file in the required screen descriptor. During this step, it is important to specify the name of a namespace where component tags are stored, e.g. xmlns:webdav="http://schemas.haulmont.com/webdav/ui-component.xsd. In the example below, the namespace is determined by the word webdav.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
       caption="msg://screenCaption"
       class="com.haulmont.contractsystem.web.demo.Demo"
       messagesPack="com.haulmont.contractsystem.web.demo"
       xmlns:webdav="http://schemas.haulmont.com/webdav/ui-component.xsd">
   <dsContext>
       <collectionDatasource id="contractsDs"
                             class="com.haulmont.contractsystem.entity.Contract"
                             view="contract-view">
           <query>
               <![CDATA[select e from contractsystem$Contract e]]>
           </query>
       </collectionDatasource>
   </dsContext>

   <layout >
   ...

       <webdav:document-link id="webdavLink"
                             datasource="contractsDs"
                             property="fileDescriptor"/>

   ...
   </layout>

</window>

Attributes

  • webdavDocumentId — a unique identifier of WebdavDocument to be displayed.

  • fileDescriptorId — an ID of FileDescriptor to be displayed. The latest version of a document is shown.

  • showVersion — indicates whether a link is shown on the version control screen. The default value of this parameter depends on versioning: if it is enabled for a document, then a link is shown.

  • datasource — a datasource name to be shown. A link leads to an entity from a datasource.

  • property — a name of a property from a datasource. Possible values: WebdavDocument or FileDescriptor.

Tip

document-link are inherited from linkButton and contain all parent properties.

6.1.3. Manual Creation

Use ComponentsFactory to create WebdavDocumentLink:

WebdavDocumentLink documentLink = componentsFactory.createComponent(WebdavDocumentLink.class);

After obtaining a WebdavDocumentLink instance, it requires configuring. For this purpose, you can use one of the methods described below:

  • withFileDescriptor(FileDescriptor fileDescriptor) — requires specifying a FileDescriptor instance related to a document version.

  • withFileDescriptorId(UUID fileDescriptorId) — requires specifying an identifier of FileDescriptor related to a document version.

  • withWebdavDocumentVersion(WebdavDocumentVersion webdavDocumentVersion) — requires specifying a version of WebdavDocumentVersion.

  • withWebdavDocumentVersionId(UUID webdavDocumentVersionId) — requires specifying webdavDocumentVersionId.

  • withWebdavDocument(WebdavDocument webdavDocument) — requires specifying a document.

  • withWebdavDocumentId(UUID webdavDocumentId) — requires specifying a document identifier.

Configuration Examples

Creating a link to a document version using a FileDescriptor object:

WebdavDocumentLink documentLink = componentsFactory.createComponent(WebdavDocumentLink.class)
                                                   .withFileDescriptor(...);

The example below describes how to create a link to a document using the WebdavDocument object:

WebdavDocumentLink documentLink = componentsFactory.createComponent(WebdavDocumentLink.class)
                                                   .withWebdavDocument(...);

WebdavDocumentVersionLink is a CUBA Platform UI component that enables to open a particular document version using Microsoft Office Apps in the read-only mode. The component displays a file name of a certain document version.

Component XML name: document-version-link.

document version link

6.2.1. Work Modes

The component works in the following three modes:

  • WebDAV is disabled.

  • WebDAV is enabled, Versioning is disabled.

  • WebDAV is enabled, Versioning is enabled.

WebDAV is enabled

WebDAV is disabled

Versioning is enabled

WebdavDocumentVersionLink is displayed without any restrictions

In this mode WebdavDocumentVersionLink is displayed as an empty element

Versioning is disabled

WebdavDocumentVersionLink is displayed without any restrictions

In this mode WebdavDocumentVersionLink is displayed as an empty element

6.2.2. Declarative Creation

To use the WebDAV components in XML, it is required to specify the http://schemas.haulmont.com/webdav/ui-component.xsd scheme file in a required screen descriptor. During this step, it is important to specify the name of a namespace where component tags are stored, e.g. xmlns:webdav="http://schemas.haulmont.com/webdav/ui-component.xsd. In the example below, the namespace is determined by the word webdav.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
       caption="msg://screenCaption"
       class="com.haulmont.contractsystem.web.demo.Demo"
       messagesPack="com.haulmont.contractsystem.web.demo"
       xmlns:webdav="http://schemas.haulmont.com/webdav/ui-component.xsd">
   <dsContext>
       <collectionDatasource id="contractsDs"
                             class="com.haulmont.contractsystem.entity.Contract"
                             view="contract-view">
           <query>
               <![CDATA[select e from contractsystem$Contract e]]>
           </query>
       </collectionDatasource>
   </dsContext>

   <layout >
   ...

       <webdav:document-version-link id="webdavVersionLink"
                                     datasource="contractsDs"
                                     property="fileDescriptor"/>

   ...
   </layout>

</window>

Attributes

  • webdavDocumentVersionId — an ID of WebdavDocumentVersion for displaying.

  • webdavDocumentId — an ID of WebdavDocumentVersion for displaying. A value can be used only in combination with naturalVersionId.

  • naturalVersionId — a natural version number. A value can be used only in combination with a document version identifier.

  • fileDescriptorId — an ID of FileDescriptor to be displayed. The latest version of a document is shown.

  • datasource — a datasource name that is used for displaying an entity from a datasource.

  • property — a property from a datasource. Possible values: WebdavDocumentVersionLink or FileDescriptor.

Tip

document-version-link are inherited from linkButton and contain all parent properties.

6.2.3. Manual Creation

Use ComponentsFactory to create WebdavDocumentVersionLink:

WebdavDocumentVersionLink documentVersionLink = componentsFactory.createComponent(WebdavDocumentVersionLink.class);

After obtaining a WebdavDocumentVersionLink instance, it requires configuring. For this purpose, you can use one of the methods described below:

  • withWebdavDocumentVersion(WebdavDocumentVersion webdav DocumentVersion) - requires specifying a current version of WebdavDocumentVersion.

  • withWebdavDocumentVersionId(UUID webdavDocumentVersionId) — requires specifying a document identifier.

  • withFileDescriptor(FileDescriptor fileDescriptor) — requires specifying a FileDescriptor instance related to a document version.

  • withFileDescriptorId(UUID fileDescriptorId) — requires specifying an identifier of FileDescriptor related to a document version.

  • withWebdavDocument(WebdavDocument webdavDocument) — this method has to be combined with withNaturalVersionId(Long naturalVersionId). The combination of these two methods allows identifying a document and natural ID of a document version.

  • withWebdavDocumentId(UUID webdavDocumentId) — this method has to be combined with withNaturalVersionId(Long naturalVersionId). The combination of these two methods allows identifying a document and natural ID of a document version.

Configuration Examples

Creating a link to a document version using the WebdavDocumentVersion object:

WebdavDocumentVersionLink documentVersionLink = componentsFactory.createComponent(WebdavDocumentVersionLink.class)
                                                                 .withDocumentVersion(...);

Creating a link to a document version using the WebdavDocument object and a document version natural ID:

WebdavDocumentVersionLink documentVersionLink = componentsFactory.createComponent(WebdavDocumentVersionLink.class)
                                                                 .withDocument(...)
                                                                 .withNaturalVersionId(...);

6.3. WebdavDocumentUploadField

WebdavDocumentUploadField is a CUBA Platform UI component which is designed to work with documents.

Component XML name: webdav-document-upload.

The component features the following functionalities:

  • Uploading a file to create a new document or a document version.

  • Opening a document for reading/editing.

  • Downloading the latest or preceding document versions.

  • Creating new document versions based on previous ones.

6.3.1. Work Modes

The component works in the following three modes:

  • WebDAV is disabled.

  • WebDAV is enabled, Versioning is disabled.

  • WebDAV is enabled, Versioning is enabled.

WebDAV is enabled

WebDAV is disabled

Versioning is enabled

WebdavDocumentUploadField is displayed without any restrictions

WebdavDocumentUploadField cannot be used

Versioning is disabled

WebdavDocumentUploadField does not show a link to the latest document version.

WebdavDocumentUploadField cannot be used

6.3.2. Declarative Creation

To use the WebDAV components in XML, it is required to specify the http://schemas.haulmont.com/webdav/ui-component.xsd scheme file in the required screen descriptor. During this step, it is important to specify the name of a namespace where component tags are stored, e.g. xmlns:webdav="http://schemas.haulmont.com/webdav/ui-component.xsd. In the example below, the namespace is determined by the word webdav.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
       caption="msg://screenCaption"
       class="com.haulmont.contractsystem.web.demo.Demo"
       messagesPack="com.haulmont.contractsystem.web.demo"
       xmlns:webdav="http://schemas.haulmont.com/webdav/ui-component.xsd">
   <dsContext>
       <collectionDatasource id="contractsDs"
                             class="com.haulmont.contractsystem.entity.Contract"
                             view="contract-view">
           <query>
               <![CDATA[select e from contractsystem$Contract e]]>
           </query>
       </collectionDatasource>
   </dsContext>

   <layout >
   ...

       <webdav:webdav-document-upload id="webdavUpload"
                        datasource="contractsDs"
                        property="fileDescriptor"/>

   ...
   </layout>

</window>

Attributes

  • showDownloadButton — indicates if the Download button is shown or not. By default, the button is shown only for FieldGroup.

  • downloadButtonCaption — a caption of the Download button.

  • downloadButtonIcon — a custom icon for the Download button. If it is set, then the button caption is not shown.

  • downloadButtonDescription — a mouseover tooltip for the Download button.

Tip

w-upload is inherited from CUBA upload and contains all parent properties.

6.3.3. Manual Creation

API for WebdavDocumentUploadField is similar to API for FileUploadField. To learn more, please refer to the FileUploadField section of CUBA documentation.

Configuration Examples

Creating a field to a document using the WebdavDocumentUploadField object:

WebdavDocumentUploadField uploadField = componentsFactory.createComponent(WebdavDocumentUploadField.class);
uploadField.setDatasource(...);

6.4. Using WebDAV in FileMultiUploadField

The AppComponent does not contain a UI component similar to FileMultiUploadField. However, it is possible to support this functionality by configuring the following example from the CUBA documentation.

@Inject
private FileMultiUploadField multiUploadField;
@Inject
private FileUploadingAPI fileUploadingAPI;
@Inject
private DataSupplier dataSupplier;

// webdav: begin
@Inject
protected WebdavDocumentsManagementService documentsService;
// webdav: end

@Override
public void init(Map<String, Object> params) {
   multiUploadField.addQueueUploadCompleteListener(() -> {
       for (Map.Entry<UUID, String> entry : multiUploadField.getUploadsMap().entrySet()) {
           UUID fileId = entry.getKey();
           String fileName = entry.getValue();
           FileDescriptor fd = fileUploadingAPI.getFileDescriptor(fileId, fileName);
           // save file to FileStorage
           try {
               fileUploadingAPI.putFileIntoStorage(fileId, fd);
           } catch (FileStorageException e) {
               new RuntimeException("Error saving file to FileStorage", e);
           }
           // save file descriptor to database
           FileDescriptor committed = dataSupplier.commit(fd);

           // webdav: begin
           // create and save WebdavDocument
           documentsService.createNonVersioningDocumentByFileDescriptor(committed);
           // webdav: end
       }
       showNotification("Uploaded files: " + multiUploadField.getUploadsMap().values(), NotificationType.HUMANIZED);
       multiUploadField.clearUploads();
   });

   multiUploadField.addFileUploadErrorListener(event ->
           showNotification("File upload error", NotificationType.HUMANIZED));
}

Appendix A: Application Properties

General Properties

webdav.enabled

Enables the component functionalities for all fields (those that do not have the @WebdavSupport annotation) related to a document. If the value of this property is changed, a system administrator should migrate the data.

Default value: false

Stored in the database.

Interface: WebdavConfig

webdav.versioningEnabled

Enables the versioning functionality for all fields (those that do not have the @WebdavSupport annotation) related to a document. If the value of this property is changed, a system administrator should migrate the data.

Default value: true

Stored in the database.

Interface: WebdavConfig

webdav.applications

Allows matching which document formats can be opened via various external applications. For each application you can configure a set of file extensions in the "extensions" block. For example:

"ms-powerpoint":{"name":"Microsoft PowerPoint","protocols":{"writable":"ms-powerpoint:ofe%7Cu%7C","read_only":"ms-powerpoint:ofv%7Cu%7C"},"extensions":["ppt","pptx"]

Considering the example given above, we can conclude that if the user tries opening a document with the *.ppt extension, it will be opened in Microsoft PowerPoint.

Default value: {"ms-word":{"name":"Microsoft Word","protocols":{"writable":"ms-word:ofe%7Cu%7C","read_only":"ms-word:ofv%7Cu%7C"},"extensions":["docx","doc","rtf"]},"ms-excel":{"name":"Microsoft Excel","protocols":{"writable":"ms-excel:ofe%7Cu%7C","read_only":"ms-excel:ofv%7Cu%7C"},"extensions":["xls","xlsx"]},"ms-powerpoint":{"name":"Microsoft PowerPoint","protocols":{"writable":"ms-powerpoint:ofe%7Cu%7C","read_only":"ms-powerpoint:ofv%7Cu%7C"},"extensions":["ppt","pptx"]}}

Stored in the database.

Interface: WebdavConfig

Example value for LibreOffice: {"vnd.libreoffice.command":{"name":"LibreOffice","protocols":{"writable":"vnd.libreoffice.command:ofe|u|","read_only":"vnd.libreoffice.command:ofv|u|"},"extensions":["odt", "ods", "odp", "doc", "docx", "xls", "xlsx", "ppt", "pptx"]}}

Link Generator

Use the application properties described below to configure document downloading/opening:

webdav.useUrlPrefix

Uses full url prefix instead of webdav.server.* parameters.

Default value: true

Stored in the database.

Interface: WebdavConfig

webdav.urlPrefix

Prefix for WebDAV document link.

Default value: https://localhost:8443/app/webdav

Stored in the database.

Interface: WebdavConfig

webdav.server.protocol (deprecated)

Server connection protocol.

Default value: https

Stored in the database.

Interface: WebdavServerConfig

Available values: http, https

webdav.server.hostname (deprecated)

Host name and address.

Default value: localhost

Stored in the database.

Interface: WebdavServerConfig

webdav.server.port (deprecated)

Port, on which the server is running.

Default value: 8443

Stored in the database.

Interface: WebdavServerConfig

webdav.server.modulePrefix (deprecated)

Application address.

Default value: app

Stored in the database.

Interface: WebdavServerConfig

webdav.server.dispatcherPath (deprecated)

Dispatcher servlet address.

Default value: webdav

Stored in the database.

Interface: WebdavServerConfig

As a result, values of all aforementioned properties form the following address: https://localhost:8443/app/webdav/

Appendix B: Creating Attributes of the WebdavDocument Type

In order to add an attribute of the WebdavDocument type the following steps should be made:

  1. Open your project in CUBA Studio.

  2. Double-click the required entity in the CUBA project tree and go to the Design tab.

    entity designer
  3. Click New in the Attributes section. After this, the New Attribute dialog window is opened.

    creating attribute
  4. Select the ASSOCIATION value in the Attribute type field. Specify WebdavDocument as a value of the Type field. Fill in the required fields and click Add to confirm the creation of a new attribute.

Appendix C: Digest authentication configuration example

webdav-dispatcher-spring.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:security="http://www.springframework.org/schema/security"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-4.3.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-4.2.xsd
           http://www.springframework.org/schema/mvc
           http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:annotation-config/>
    <context:component-scan base-package="com.haulmont.webdav.webdav"/>

    <mvc:annotation-driven conversion-service="conversionService"/>

    <bean id="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"
          class="com.haulmont.webdav.webdav.WebdavRequestMappingHandlerMapping"/>

    <bean id="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"
          class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="webdav_PropFindRequestHttpToPropFindRequestPropertiesConverter"/>
                <ref bean="webdav_PropFindResponseObjectToPropFindResponseHttpConverter"/>
                <ref bean="webdav_LockRequestHttpToLockRequestPredicateConverter"/>
                <ref bean="webdav_LockInfoWithResourceUriToLockResponseHttpConverter"/>
                <ref bean="stringHttpMessageConverter"/>
                <ref bean="byteArrayHttpMessageConverter"/>
                <ref bean="resourceHttpMessageConverter"/>
            </list>
        </property>
    </bean>

    <bean id="exceptionHandlerExceptionResolver"
          class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver">
        <property name="messageConverters">
            <list>
                <ref bean="webdav_WebdavExceptionHttpConverter"/>
            </list>
        </property>
    </bean>

    <bean id="compositeExceptionResolver"
          class="org.springframework.web.servlet.handler.HandlerExceptionResolverComposite">
        <property name="exceptionResolvers">
            <list>
                <ref bean="exceptionHandlerExceptionResolver"/>
            </list>
        </property>
        <property name="order" value="0"/>
    </bean>

    <bean id="conversionService"
          class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <ref bean="webdav_WebdavDocumentVersionToListOfNodesConverter"/>
                <ref bean="webdav_LockInfoWithResourceUriToElementConverter"/>
                <ref bean="webdav_LockInfoIdToStringConverter"/>
            </set>
        </property>
    </bean>

    <bean id="stringHttpMessageConverter"
          class="org.springframework.http.converter.StringHttpMessageConverter"/>

    <bean id="byteArrayHttpMessageConverter"
          class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>

    <bean id="resourceHttpMessageConverter"
          class="org.springframework.http.converter.ResourceHttpMessageConverter"/>

    <bean id="webdav_WebdavDigestAuthenticationFilter" class=
            "com.haulmont.webdav.webdav.servlet.WebdavDigestAuthenticationFilter">
        <property name="userDetailsService" ref="webdav_UserDetailsServiceAdapter"/>
        <property name="authenticationEntryPoint" ref="webdav_DigestEntryPoint"/>
        <property name="passwordAlreadyEncoded" value="true"/>
    </bean>

    <bean id="webdav_DigestEntryPoint" class=
            "com.haulmont.webdav.webdav.servlet.WebdavDigestAuthenticationEntryPoint">
        <property name="realmName" value="webdav"/>
        <property name="key" value="acegi"/>
        <property name="nonceValiditySeconds" value="10"/>
    </bean>

    <bean id="passwordEncoder" class="org.springframework.security.crypto.password.NoOpPasswordEncoder"/>

    <security:authentication-manager id="authManager">
        <security:authentication-provider user-service-ref="webdav_UserDetailsServiceAdapter">
            <security:password-encoder ref="passwordEncoder"/>
        </security:authentication-provider>
    </security:authentication-manager>

    <security:http use-expressions="true"
                   create-session="stateless"
                   entry-point-ref="webdav_DigestEntryPoint">
        <security:intercept-url pattern="/**" access="isAuthenticated()"/>

        <security:anonymous enabled="false"/>
        <security:csrf disabled="true"/>

        <security:custom-filter ref="webdav_WebdavFilter" after="LOGIN_PAGE_FILTER"/>
        <security:custom-filter ref="webdav_WebdavDigestAuthenticationFilter" before="DIGEST_AUTH_FILTER"/>
        <security:custom-filter ref="webdav_ConnectorSpringSecurityAndCubaSecurityFilter" after="DIGEST_AUTH_FILTER"/>
    </security:http>

    <bean id="httpFirewall"
          class="org.springframework.security.web.firewall.StrictHttpFirewall">
        <property name="allowedHttpMethods" value="GET,HEAD,LOCK,OPTIONS,PROPFIND,PUT,UNLOCK"/>
    </bean>

    <security:http-firewall ref="httpFirewall"/>
</beans>