You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openmeetings.apache.org by so...@apache.org on 2023/12/21 05:06:05 UTC
(openmeetings) 29/29: [OPENMEETINGS-2756] the build seems to be fixed
This is an automated email from the ASF dual-hosted git repository.
solomax pushed a commit to branch jakarta-spring-6
in repository https://gitbox.apache.org/repos/asf/openmeetings.git
commit b7d01a1ed9233718932c53753a5114f4977769bd
Author: Maxim Solodovnik <so...@apache.org>
AuthorDate: Thu Dec 21 12:05:23 2023 +0700
[OPENMEETINGS-2756] the build seems to be fixed
---
.../src/main/java/module-info.java | 3 +-
openmeetings-service/pom.xml | 8 +-
.../src/main/java/module-info.java | 9 +-
.../jackrabbit/webdav/AbstractLocatorFactory.java | 403 +++++
.../webdav/ContentCodingAwareRequest.java | 39 +
.../apache/jackrabbit/webdav/DavCompliance.java | 72 +
.../org/apache/jackrabbit/webdav/DavConstants.java | 154 ++
.../org/apache/jackrabbit/webdav/DavException.java | 175 +++
.../jackrabbit/webdav/DavLocatorFactory.java | 72 +
.../org/apache/jackrabbit/webdav/DavMethods.java | 410 ++++++
.../org/apache/jackrabbit/webdav/DavResource.java | 334 +++++
.../jackrabbit/webdav/DavResourceFactory.java | 46 +
.../jackrabbit/webdav/DavResourceIterator.java | 39 +
.../jackrabbit/webdav/DavResourceIteratorImpl.java | 85 ++
.../jackrabbit/webdav/DavResourceLocator.java | 115 ++
.../jackrabbit/webdav/DavServletRequest.java | 199 +++
.../jackrabbit/webdav/DavServletResponse.java | 149 ++
.../org/apache/jackrabbit/webdav/DavSession.java | 62 +
.../jackrabbit/webdav/DavSessionProvider.java | 48 +
.../org/apache/jackrabbit/webdav/MultiStatus.java | 193 +++
.../jackrabbit/webdav/MultiStatusResponse.java | 486 ++++++
.../java/org/apache/jackrabbit/webdav/Status.java | 125 ++
.../apache/jackrabbit/webdav/WebdavRequest.java | 36 +
.../jackrabbit/webdav/WebdavRequestContext.java | 30 +
.../jackrabbit/webdav/WebdavRequestImpl.java | 1324 +++++++++++++++++
.../apache/jackrabbit/webdav/WebdavResponse.java | 42 +
.../jackrabbit/webdav/WebdavResponseImpl.java | 392 +++++
.../jackrabbit/webdav/bind/BindConstants.java | 52 +
.../apache/jackrabbit/webdav/bind/BindInfo.java | 108 ++
.../jackrabbit/webdav/bind/BindServletRequest.java | 65 +
.../jackrabbit/webdav/bind/BindableResource.java | 50 +
.../jackrabbit/webdav/bind/ParentElement.java | 111 ++
.../apache/jackrabbit/webdav/bind/ParentSet.java | 45 +
.../apache/jackrabbit/webdav/bind/RebindInfo.java | 108 ++
.../apache/jackrabbit/webdav/bind/UnbindInfo.java | 90 ++
.../jackrabbit/webdav/bind/package-info.java | 18 +
.../webdav/client/methods/BaseDavRequest.java | 219 +++
.../jackrabbit/webdav/client/methods/HttpBind.java | 54 +
.../webdav/client/methods/HttpCheckin.java | 51 +
.../webdav/client/methods/HttpCheckout.java | 51 +
.../jackrabbit/webdav/client/methods/HttpCopy.java | 59 +
.../webdav/client/methods/HttpDelete.java | 43 +
.../webdav/client/methods/HttpLabel.java | 57 +
.../jackrabbit/webdav/client/methods/HttpLock.java | 107 ++
.../webdav/client/methods/HttpMerge.java | 55 +
.../webdav/client/methods/HttpMkcol.java | 51 +
.../webdav/client/methods/HttpMkworkspace.java | 51 +
.../jackrabbit/webdav/client/methods/HttpMove.java | 56 +
.../webdav/client/methods/HttpOptions.java | 79 +
.../webdav/client/methods/HttpOrderpatch.java | 53 +
.../jackrabbit/webdav/client/methods/HttpPoll.java | 58 +
.../webdav/client/methods/HttpPropfind.java | 77 +
.../webdav/client/methods/HttpProppatch.java | 104 ++
.../webdav/client/methods/HttpRebind.java | 54 +
.../webdav/client/methods/HttpReport.java | 66 +
.../webdav/client/methods/HttpSearch.java | 54 +
.../webdav/client/methods/HttpSubscribe.java | 88 ++
.../webdav/client/methods/HttpUnbind.java | 54 +
.../webdav/client/methods/HttpUnlock.java | 55 +
.../webdav/client/methods/HttpUnsubscribe.java | 53 +
.../webdav/client/methods/HttpUpdate.java | 54 +
.../webdav/client/methods/HttpVersionControl.java | 51 +
.../webdav/client/methods/XmlEntity.java | 68 +
.../webdav/client/methods/package-info.java | 31 +
.../jackrabbit/webdav/header/CodedUrlHeader.java | 113 ++
.../jackrabbit/webdav/header/DepthHeader.java | 128 ++
.../jackrabbit/webdav/header/FieldValueParser.java | 55 +
.../apache/jackrabbit/webdav/header/Header.java | 27 +
.../apache/jackrabbit/webdav/header/IfHeader.java | 905 ++++++++++++
.../jackrabbit/webdav/header/LabelHeader.java | 61 +
.../jackrabbit/webdav/header/OverwriteHeader.java | 75 +
.../webdav/header/PollTimeoutHeader.java | 52 +
.../jackrabbit/webdav/header/TimeoutHeader.java | 104 ++
.../jackrabbit/webdav/header/package-info.java | 18 +
.../apache/jackrabbit/webdav/io/InputContext.java | 78 +
.../jackrabbit/webdav/io/InputContextImpl.java | 98 ++
.../apache/jackrabbit/webdav/io/OutputContext.java | 82 ++
.../jackrabbit/webdav/io/OutputContextImpl.java | 88 ++
.../apache/jackrabbit/webdav/io/package-info.java | 18 +
.../jackrabbit/webdav/lock/AbstractActiveLock.java | 86 ++
.../jackrabbit/webdav/lock/AbstractLockEntry.java | 47 +
.../apache/jackrabbit/webdav/lock/ActiveLock.java | 124 ++
.../jackrabbit/webdav/lock/DefaultActiveLock.java | 147 ++
.../jackrabbit/webdav/lock/LockDiscovery.java | 233 +++
.../apache/jackrabbit/webdav/lock/LockEntry.java | 39 +
.../apache/jackrabbit/webdav/lock/LockInfo.java | 237 +++
.../apache/jackrabbit/webdav/lock/LockManager.java | 87 ++
.../org/apache/jackrabbit/webdav/lock/Scope.java | 122 ++
.../jackrabbit/webdav/lock/SimpleLockManager.java | 233 +++
.../jackrabbit/webdav/lock/SupportedLock.java | 166 +++
.../org/apache/jackrabbit/webdav/lock/Type.java | 129 ++
.../jackrabbit/webdav/lock/package-info.java | 18 +
.../webdav/observation/DefaultEventType.java | 148 ++
.../jackrabbit/webdav/observation/EventBundle.java | 29 +
.../webdav/observation/EventDiscovery.java | 121 ++
.../jackrabbit/webdav/observation/EventType.java | 30 +
.../jackrabbit/webdav/observation/Filter.java | 74 +
.../webdav/observation/ObservationConstants.java | 101 ++
.../observation/ObservationDavServletRequest.java | 54 +
.../observation/ObservationDavServletResponse.java | 45 +
.../webdav/observation/ObservationResource.java | 72 +
.../webdav/observation/Subscription.java | 49 +
.../webdav/observation/SubscriptionDiscovery.java | 139 ++
.../webdav/observation/SubscriptionInfo.java | 242 +++
.../webdav/observation/SubscriptionManager.java | 69 +
.../webdav/observation/package-info.java | 18 +
.../jackrabbit/webdav/ordering/OrderPatch.java | 212 +++
.../webdav/ordering/OrderingConstants.java | 106 ++
.../webdav/ordering/OrderingDavServletRequest.java | 55 +
.../webdav/ordering/OrderingResource.java | 47 +
.../jackrabbit/webdav/ordering/OrderingType.java | 52 +
.../jackrabbit/webdav/ordering/Position.java | 164 +++
.../jackrabbit/webdav/ordering/package-info.java | 18 +
.../org/apache/jackrabbit/webdav/package-info.java | 18 +
.../webdav/property/AbstractDavProperty.java | 163 ++
.../jackrabbit/webdav/property/DavProperty.java | 71 +
.../webdav/property/DavPropertyIterator.java | 34 +
.../webdav/property/DavPropertyName.java | 206 +++
.../webdav/property/DavPropertyNameIterator.java | 28 +
.../webdav/property/DavPropertyNameSet.java | 203 +++
.../jackrabbit/webdav/property/DavPropertySet.java | 300 ++++
.../webdav/property/DefaultDavProperty.java | 144 ++
.../jackrabbit/webdav/property/HrefProperty.java | 159 ++
.../jackrabbit/webdav/property/PropContainer.java | 120 ++
.../jackrabbit/webdav/property/PropEntry.java | 25 +
.../jackrabbit/webdav/property/PropfindInfo.java | 84 ++
.../jackrabbit/webdav/property/ProppatchInfo.java | 128 ++
.../jackrabbit/webdav/property/ResourceType.java | 205 +++
.../jackrabbit/webdav/property/package-info.java | 18 +
.../jackrabbit/webdav/search/QueryGrammerSet.java | 144 ++
.../jackrabbit/webdav/search/SearchConstants.java | 91 ++
.../jackrabbit/webdav/search/SearchInfo.java | 271 ++++
.../jackrabbit/webdav/search/SearchResource.java | 55 +
.../jackrabbit/webdav/search/package-info.java | 18 +
.../jackrabbit/webdav/security/AclProperty.java | 262 ++++
.../jackrabbit/webdav/security/AclResource.java | 70 +
.../webdav/security/AclRestrictionsProperty.java | 107 ++
.../security/CurrentUserPrivilegeSetProperty.java | 90 ++
.../jackrabbit/webdav/security/Principal.java | 189 +++
.../jackrabbit/webdav/security/Privilege.java | 204 +++
.../webdav/security/SecurityConstants.java | 110 ++
.../webdav/security/SupportedPrivilege.java | 139 ++
.../security/SupportedPrivilegeSetProperty.java | 95 ++
.../jackrabbit/webdav/security/package-info.java | 18 +
.../security/report/AbstractSecurityReport.java | 82 ++
.../webdav/security/report/AclPrincipalReport.java | 96 ++
.../security/report/PrincipalMatchReport.java | 115 ++
.../security/report/PrincipalSearchReport.java | 184 +++
.../security/report/SearchablePropertyReport.java | 204 +++
.../webdav/security/report/package-info.java | 18 +
.../webdav/server/AbstractWebdavServlet.java | 1557 ++++++++++++++++++++
.../webdav/server/WebdavRequestContextHolder.java | 46 +
.../webdav/server/WebdavRequestContextImpl.java | 35 +
.../jackrabbit/webdav/server/package-info.java | 18 +
.../webdav/transaction/TransactionConstants.java | 125 ++
.../transaction/TransactionDavServletRequest.java | 51 +
.../webdav/transaction/TransactionInfo.java | 105 ++
.../webdav/transaction/TransactionResource.java | 59 +
.../webdav/transaction/TxActiveLock.java | 93 ++
.../jackrabbit/webdav/transaction/TxLockEntry.java | 72 +
.../webdav/transaction/TxLockManager.java | 65 +
.../webdav/transaction/package-info.java | 18 +
.../apache/jackrabbit/webdav/util/CSRFUtil.java | 168 +++
.../apache/jackrabbit/webdav/util/EncodeUtil.java | 220 +++
.../jackrabbit/webdav/util/HttpDateFormat.java | 64 +
.../webdav/util/HttpDateTimeFormatter.java | 152 ++
.../webdav/util/LinkHeaderFieldParser.java | 197 +++
.../jackrabbit/webdav/util/package-info.java | 18 +
.../webdav/version/ActivityResource.java | 98 ++
.../webdav/version/BaselineResource.java | 81 +
.../jackrabbit/webdav/version/DeltaVConstants.java | 374 +++++
.../jackrabbit/webdav/version/DeltaVResource.java | 111 ++
.../webdav/version/DeltaVServletRequest.java | 84 ++
.../jackrabbit/webdav/version/LabelInfo.java | 188 +++
.../webdav/version/LabelSetProperty.java | 63 +
.../jackrabbit/webdav/version/MergeInfo.java | 182 +++
.../jackrabbit/webdav/version/OptionsInfo.java | 126 ++
.../jackrabbit/webdav/version/OptionsResponse.java | 144 ++
.../webdav/version/SupportedMethodSetProperty.java | 63 +
.../jackrabbit/webdav/version/UpdateInfo.java | 243 +++
.../webdav/version/VersionControlledResource.java | 363 +++++
.../webdav/version/VersionHistoryResource.java | 73 +
.../jackrabbit/webdav/version/VersionResource.java | 213 +++
.../webdav/version/VersionableResource.java | 64 +
.../webdav/version/WorkspaceResource.java | 94 ++
.../jackrabbit/webdav/version/package-info.java | 18 +
.../webdav/version/report/AbstractReport.java | 59 +
.../version/report/CompareBaselineReport.java | 188 +++
.../version/report/ExpandPropertyReport.java | 266 ++++
.../report/LatestActivityVersionReport.java | 151 ++
.../version/report/LocateByHistoryReport.java | 175 +++
.../jackrabbit/webdav/version/report/Report.java | 62 +
.../webdav/version/report/ReportInfo.java | 263 ++++
.../webdav/version/report/ReportType.java | 190 +++
.../version/report/SupportedReportSetProperty.java | 119 ++
.../webdav/version/report/VersionTreeReport.java | 187 +++
.../webdav/version/report/package-info.java | 18 +
.../webdav/xml/DavDocumentBuilderFactory.java | 87 ++
.../org/apache/jackrabbit/webdav/xml/DomUtil.java | 839 +++++++++++
.../jackrabbit/webdav/xml/ElementIterator.java | 170 +++
.../apache/jackrabbit/webdav/xml/Namespace.java | 97 ++
.../apache/jackrabbit/webdav/xml/ResultHelper.java | 458 ++++++
.../jackrabbit/webdav/xml/XmlSerializable.java | 38 +
.../apache/jackrabbit/webdav/xml/package-info.java | 18 +
.../apache/jackrabbit/webdav/statuscode.properties | 62 +
openmeetings-util/src/main/java/module-info.java | 4 +-
openmeetings-web/src/main/java/module-info.java | 9 +-
.../org/apache/openmeetings/ldap/TestLdap.java | 2 -
pom.xml | 20 +-
209 files changed, 26536 insertions(+), 24 deletions(-)
diff --git a/openmeetings-install/src/main/java/module-info.java b/openmeetings-install/src/main/java/module-info.java
index e7aa2a2c2..2ee926d43 100644
--- a/openmeetings-install/src/main/java/module-info.java
+++ b/openmeetings-install/src/main/java/module-info.java
@@ -24,8 +24,10 @@ module org.apache.openmeetings.install {
requires com.github.openjson;
+ requires org.apache.commons.cli;
requires org.apache.commons.io;
requires org.apache.commons.lang3;
+ requires org.apache.commons.text;
requires org.apache.openjpa;
@@ -45,7 +47,6 @@ module org.apache.openmeetings.install {
requires spring.web;
requires java.desktop;
- requires commons.cli;
requires quartz;
requires xstream;
diff --git a/openmeetings-service/pom.xml b/openmeetings-service/pom.xml
index d3524fab7..4384c2e72 100644
--- a/openmeetings-service/pom.xml
+++ b/openmeetings-service/pom.xml
@@ -53,9 +53,9 @@
<groupId>com.github.caldav4j</groupId>
<artifactId>caldav4j</artifactId>
</dependency>
- <dependency>
+ <!--dependency> FIXME TODO have to be placed back as soon as `jackrabbit.webdav` will be jackarta compatible
<groupId>org.apache.jackrabbit</groupId>
- <artifactId>jackrabbit-webdav-jakarta</artifactId>
- </dependency>
-</dependencies>
+ <artifactId>jackrabbit-webdav</artifactId>
+ </dependency-->
+ </dependencies>
</project>
diff --git a/openmeetings-service/src/main/java/module-info.java b/openmeetings-service/src/main/java/module-info.java
index 16b3d8aba..e2e2ededb 100644
--- a/openmeetings-service/src/main/java/module-info.java
+++ b/openmeetings-service/src/main/java/module-info.java
@@ -26,7 +26,14 @@ module org.apache.openmeetings.service {
exports org.apache.openmeetings.service.room;
exports org.apache.openmeetings.service.scheduler;
+ //FIXME TODO temporary
+ exports org.apache.jackrabbit.webdav;
+ exports org.apache.jackrabbit.webdav.xml;
+ exports org.apache.jackrabbit.webdav.property;
+ exports org.apache.jackrabbit.webdav.client.methods;
+
requires org.apache.commons.lang3;
+ requires org.apache.commons.text;
requires transitive org.apache.openmeetings.db;
requires org.apache.openmeetings.core;
@@ -45,7 +52,7 @@ module org.apache.openmeetings.service {
requires org.apache.httpcomponents.httpcore;
requires org.apache.httpcomponents.httpclient;
- requires jackrabbit.webdav.jakarta;
+ //requires jackrabbit.webdav; FIXME TODO have to be placed back as soon as `jackrabbit.webdav` will be jackarta compatible
requires caldav4j;
requires java.xml;
requires org.mnode.ical4j.core;
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/AbstractLocatorFactory.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/AbstractLocatorFactory.java
new file mode 100644
index 000000000..36b0a68e1
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/AbstractLocatorFactory.java
@@ -0,0 +1,403 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import org.apache.jackrabbit.webdav.util.EncodeUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@code AbstractLocatorFactory} is an implementation of the DavLocatorFactory
+ * interface that defines how a given URI is split to workspace path and
+ * resource path and how it's implementation of {@code DavResourceLocator}
+ * builds the href. In contrast, the conversion from repository path to
+ * resource path and vice versa is left to subclasses.
+ */
+public abstract class AbstractLocatorFactory implements DavLocatorFactory {
+
+ private static Logger log = LoggerFactory.getLogger(AbstractLocatorFactory.class);
+
+ private final String pathPrefix;
+
+ /**
+ * Create a new factory
+ *
+ * @param pathPrefix Prefix, that needs to be removed in order to retrieve
+ * the path of the repository item from a given {@code DavResourceLocator}.
+ */
+ public AbstractLocatorFactory(String pathPrefix) {
+ this.pathPrefix = pathPrefix;
+ }
+
+ //--------------------------------------------------< DavLocatorFactory >---
+ /**
+ * Create a new {@code DavResourceLocator}. Any leading prefix and
+ * path-prefix (as defined with the constructor) are removed from the
+ * given request handle. The same applies for trailing '/'. The remaining
+ * String is called the 'resource handle' and it's first segment is treated
+ * as workspace name. If resource handle (and therefore workspace name)
+ * are missing, both values are set to {@code null}.
+ * <p>
+ * Examples:
+ *
+ * <pre>
+ * http://www.foo.bar/ (path prefix missing)
+ * -> workspace path = null
+ * -> resource path = null
+ * -> href = http://www.foo.bar/pathPrefix/
+ *
+ * http://www.foo.bar/pathPrefix/
+ * -> workspace path = null
+ * -> resource path = null
+ * -> href = http://www.foo.bar/pathPrefix/
+ *
+ * http://www.foo.bar/pathPrefix/wspName
+ * -> workspace path = /wspName
+ * -> resource path = /wspName
+ * -> href = http://www.foo.bar/pathPrefix/wspName
+ *
+ * http://www.foo.bar/pathPrefix/wspName/anypath
+ * -> workspace path = /wspName
+ * -> resource path = /wspName/anypath
+ * -> href = http://www.foo.bar/pathPrefix/wspName/anypath
+ * </pre>
+ *
+ * NOTE: If the given href is an absolute URI it must start with the
+ * specified prefix.
+ *
+ * @param prefix
+ * @param href
+ * @return a new {@code DavResourceLocator}
+ * @throws IllegalArgumentException if the given href is {@code null}
+ */
+ public DavResourceLocator createResourceLocator(String prefix, String href) {
+ if (href == null) {
+ throw new IllegalArgumentException("Request handle must not be null.");
+ }
+
+ // build prefix string and remove all prefixes from the given href.
+ StringBuffer b = new StringBuffer("");
+ if (prefix != null && prefix.length() > 0) {
+ b.append(prefix);
+ if (href.startsWith(prefix)) {
+ href = href.substring(prefix.length());
+ }
+ }
+ if (pathPrefix != null && pathPrefix.length() > 0) {
+ if (!b.toString().endsWith(pathPrefix)) {
+ b.append(pathPrefix);
+ }
+ if (href.startsWith(pathPrefix)) {
+ href = href.substring(pathPrefix.length());
+ }
+ }
+
+ // remove trailing "/" that is present with collections
+ if (href.endsWith("/")) {
+ href = href.substring(0, href.length() - 1);
+ }
+
+ String resourcePath;
+ String workspacePath;
+
+ // an empty requestHandle (after removal of the "/") signifies a request
+ // to the root that does not represent a repository item.
+ if ("".equals(href)) {
+ resourcePath = null;
+ workspacePath = null;
+ } else {
+ resourcePath = EncodeUtil.unescape(href);
+ // retrieve wspPath: look for the first slash ignoring the leading one
+ int pos = href.indexOf('/', 1);
+ if (pos == -1) {
+ // request to a 'workspace' resource
+ workspacePath = resourcePath;
+ } else {
+ // separate the workspace path from the resource path.
+ workspacePath = EncodeUtil.unescape(href.substring(0, pos));
+ }
+ }
+
+ log.trace("createResourceLocator: prefix='" + prefix + "' href='" + href + "' -> prefix='" + b.toString()
+ + "' workspacePath='" + workspacePath + "' resourcePath='" + resourcePath + "'");
+ return new DavResourceLocatorImpl(b.toString(), workspacePath, resourcePath, this);
+ }
+
+ /**
+ * Like {@link #createResourceLocator(String, String)}, but by setting
+ * {@code forDestination} to {@code true} any special processing of URI
+ * suffixes can be disabled.
+ */
+ public DavResourceLocator createResourceLocator(String prefix, String href, boolean forDestination) {
+ return createResourceLocator(prefix, href);
+ }
+
+ /**
+ * Create a new {@code DavResourceLocator} from the specified prefix,
+ * workspace path and resource path, without modifying the specified Strings.
+ * Note, that it is expected that the resource path starts with the
+ * given workspace path unless both values are {@code null}.
+ *
+ * @param prefix
+ * @param workspacePath path or the workspace containing this resource or
+ * {@code null}.
+ * @param resourcePath Path of the resource or {@code null}. Any non
+ * null value must start with the specified workspace path.
+ * @return a new {@code DavResourceLocator}
+ * @see DavLocatorFactory#createResourceLocator(String, String, String)
+ */
+ public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String resourcePath) {
+ return createResourceLocator(prefix, workspacePath, resourcePath, true);
+ }
+
+ /**
+ * Create a new {@code DavResourceLocator} from the specified prefix,
+ * workspace path and resource path. If {@code isResourcePath} is set
+ * to {@code false}, the given 'resourcePath' is converted by calling
+ * {@link #getResourcePath(String, String)}. Otherwise the same restriction
+ * applies as for {@link #createResourceLocator(String, String, String)}.
+ *
+ * @param prefix
+ * @param workspacePath
+ * @param path
+ * @param isResourcePath
+ * @return
+ * @see DavLocatorFactory#createResourceLocator(String, String, String, boolean)
+ */
+ public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String path, boolean isResourcePath) {
+ String resourcePath = (isResourcePath) ? path : getResourcePath(path, workspacePath);
+ return new DavResourceLocatorImpl(prefix, workspacePath, resourcePath, this);
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ * Subclasses must defined how the repository path is built from the given
+ * resource and workspace path.
+ *
+ * @param resourcePath
+ * @param wspPath
+ * @return
+ */
+ protected abstract String getRepositoryPath(String resourcePath, String wspPath);
+
+ /**
+ * Subclasses must defined how the resource path is built from the given
+ * repository and workspace path.
+ *
+ * @param repositoryPath
+ * @param wspPath
+ * @return
+ */
+ protected abstract String getResourcePath(String repositoryPath, String wspPath);
+
+ //--------------------------------------------------------< DavResource >---
+ /**
+ * Private inner class {@code DavResourceLocatorImpl} implementing
+ * the {@code DavResourceLocator} interface.
+ */
+ private class DavResourceLocatorImpl implements DavResourceLocator {
+
+ private final String prefix;
+ private final String workspacePath;
+ private final String resourcePath;
+ private final AbstractLocatorFactory factory;
+
+ private final String href;
+
+ /**
+ * Create a new {@code DavResourceLocatorImpl}.
+ *
+ * @param prefix
+ * @param workspacePath
+ * @param resourcePath
+ */
+ private DavResourceLocatorImpl(String prefix, String workspacePath, String resourcePath, AbstractLocatorFactory factory) {
+
+ this.prefix = prefix;
+ this.workspacePath = workspacePath;
+ this.resourcePath = resourcePath;
+ this.factory = factory;
+
+ StringBuffer buf = new StringBuffer(prefix);
+ // NOTE: no need to append the workspace path, since it must
+ // be part of the resource path.
+ if (resourcePath != null && resourcePath.length() > 0) {
+ // check if condition is really met
+ if (!resourcePath.startsWith(workspacePath)) {
+ throw new IllegalArgumentException("Resource path '" + resourcePath + "' does not start with workspace path '" + workspacePath + "'.");
+ }
+ buf.append(EncodeUtil.escapePath(resourcePath));
+ }
+ int length = buf.length();
+ if (length == 0 || (length > 0 && buf.charAt(length - 1) != '/')) {
+ buf.append("/");
+ }
+ this.href = buf.toString();
+ }
+
+ /**
+ * Return the prefix used to build the href String. This includes the initial
+ * hrefPrefix as well a the path prefix.
+ *
+ * @return prefix String used to build the href.
+ */
+ public String getPrefix() {
+ return prefix;
+ }
+
+ /**
+ * Returns the resource path which always starts with the workspace
+ * path, if a workspace resource exists. For the top most resource
+ * (request handle '/'), {@code null} is returned.
+ *
+ * @return resource path or {@code null}
+ * @see org.apache.jackrabbit.webdav.DavResourceLocator#getResourcePath()
+ */
+ public String getResourcePath() {
+ return resourcePath;
+ }
+
+ /**
+ * Return the workspace path or {@code null} if this locator object
+ * represents the '/' request handle.
+ *
+ * @return workspace path or {@code null}
+ * @see org.apache.jackrabbit.webdav.DavResourceLocator#getWorkspacePath()
+ */
+ public String getWorkspacePath() {
+ return workspacePath;
+ }
+
+ /**
+ * Return the workspace name or {@code null} if this locator object
+ * represents the '/' request handle, which does not contain a workspace
+ * path.
+ *
+ * @return workspace name or {@code null}
+ * @see org.apache.jackrabbit.webdav.DavResourceLocator#getWorkspaceName()
+ */
+ public String getWorkspaceName() {
+ if (workspacePath != null && workspacePath.length() > 0) {
+ return workspacePath.substring(1);
+ }
+ return null;
+ }
+
+ /**
+ * Returns true if the specified locator object refers to a resource within
+ * the same workspace.
+ *
+ * @param locator
+ * @return true if the workspace name obtained from the given locator
+ * refers to the same workspace as the workspace name of this locator.
+ * @see DavResourceLocator#isSameWorkspace(org.apache.jackrabbit.webdav.DavResourceLocator)
+ */
+ public boolean isSameWorkspace(DavResourceLocator locator) {
+ return (locator == null) ? false : isSameWorkspace(locator.getWorkspaceName());
+ }
+
+ /**
+ * Returns true if the specified string equals to this workspace name or
+ * if both names are null.
+ *
+ * @param workspaceName
+ * @return true if the workspace name is equal to this workspace name.
+ * @see DavResourceLocator#isSameWorkspace(String)
+ */
+ public boolean isSameWorkspace(String workspaceName) {
+ String thisWspName = getWorkspaceName();
+ return (thisWspName == null) ? workspaceName == null : thisWspName.equals(workspaceName);
+ }
+
+ /**
+ * Returns an 'href' consisting of prefix and resource path (which starts
+ * with the workspace path). It assures a trailing '/' in case the href
+ * is used for collection. Note, that the resource path is
+ * {@link org.apache.jackrabbit.webdav.util.EncodeUtil#escapePath(String) escaped}.
+ *
+ * @param isCollection
+ * @return href String representing the text of the href element
+ * @see org.apache.jackrabbit.webdav.DavConstants#XML_HREF
+ * @see DavResourceLocator#getHref(boolean)
+ */
+ public String getHref(boolean isCollection) {
+ return (isCollection) ? href : href.substring(0, href.length() - 1);
+ }
+
+ /**
+ * Returns true if the 'workspacePath' field is {@code null}.
+ *
+ * @return true if the 'workspacePath' field is {@code null}.
+ * @see org.apache.jackrabbit.webdav.DavResourceLocator#isRootLocation()
+ */
+ public boolean isRootLocation() {
+ return getWorkspacePath() == null;
+ }
+
+ /**
+ * Return the factory that created this locator.
+ *
+ * @return factory
+ * @see org.apache.jackrabbit.webdav.DavResourceLocator#getFactory()
+ */
+ public DavLocatorFactory getFactory() {
+ return factory;
+ }
+
+ /**
+ * Uses {@link AbstractLocatorFactory#getRepositoryPath(String, String)}
+ * to build the repository path.
+ *
+ * @see DavResourceLocator#getRepositoryPath()
+ */
+ public String getRepositoryPath() {
+ return factory.getRepositoryPath(getResourcePath(), getWorkspacePath());
+ }
+
+ /**
+ * Computes the hash code from the href, that is built from the prefix,
+ * the workspace name and the resource path all of them representing
+ * final instance fields.
+ *
+ * @return the hash code
+ */
+ @Override
+ public int hashCode() {
+ return href.hashCode();
+ }
+
+ /**
+ * Returns true, if the given object is a {@code DavResourceLocatorImpl}
+ * with the same hash code.
+ *
+ * @param obj the object to compare to
+ * @return {@code true} if the 2 objects are equal;
+ * {@code false} otherwise
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof DavResourceLocatorImpl) {
+ DavResourceLocatorImpl other = (DavResourceLocatorImpl) obj;
+ return hashCode() == other.hashCode();
+ }
+ return false;
+ }
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/ContentCodingAwareRequest.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/ContentCodingAwareRequest.java
new file mode 100644
index 000000000..27a24b7f9
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/ContentCodingAwareRequest.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+public interface ContentCodingAwareRequest {
+
+ /**
+ * Element name for signaling "must be supported content coding"
+ */
+ public final QName PRECONDITION_SUPPORTED = new QName("http://www.day.com/jcr/webdav/1.0", "supported-content-coding", "dcr");
+
+ /**
+ * @return value suitable for Accept response field
+ */
+ public String getAcceptableCodings();
+
+ /**
+ * @return content codings used in request
+ */
+ public List<String> getRequestContentCodings();
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavCompliance.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavCompliance.java
new file mode 100644
index 000000000..de09b5b60
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavCompliance.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+/**
+ * <code>DavCompliance</code> defines constants for the various compliance
+ * classes defined RFC 2518, RFC 4918 and it's extensions.
+ */
+public final class DavCompliance {
+
+ /**
+ * Avoid instantiation
+ */
+ private DavCompliance() {}
+
+ // RFC 2518
+ public static final String _1_ = "1";
+ public static final String _2_ = "2";
+
+ // RFC 4918
+ public static final String _3_ = "3";
+
+ // RFC 3253
+ public static final String ACTIVITY = "activity";
+ public static final String BASELINE = "baseline";
+ public static final String CHECKOUT_IN_PLACE = "checkout-in-place";
+ public static final String LABEL = "label";
+ public static final String MERGE = "merge";
+ public static final String UPDATE = "update";
+ public static final String VERSION_CONTROL = "version-control";
+ public static final String VERSION_CONTROLLED_COLLECTION = "version-controlled-collection";
+ public static final String VERSION_HISTORY = "version-history";
+ public static final String WORKING_RESOURCE = "working-resource";
+ public static final String WORKSPACE = "workspace";
+
+ // RFC 3648
+ public static final String ORDERED_COLLECTIONS = "ordered-collections";
+
+ // RFC 3744
+ public static final String ACCESS_CONTROL = "access-control";
+
+ // RFC 5842
+ public static final String BIND = "bind";
+
+ // no RFC
+ public static final String OBSERVATION = "observation";
+
+ public static String concatComplianceClasses(String[] complianceClasses) {
+ StringBuffer b = new StringBuffer();
+ for (int i = 0; i < complianceClasses.length; i++) {
+ if (i > 0) {
+ b.append(",");
+ }
+ b.append(complianceClasses[i]);
+ }
+ return b.toString();
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavConstants.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavConstants.java
new file mode 100644
index 000000000..a50b1cd2a
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavConstants.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import org.apache.jackrabbit.webdav.util.HttpDateFormat;
+import org.apache.jackrabbit.webdav.xml.Namespace;
+
+import java.text.DateFormat;
+
+/**
+ * <code>DavConstants</code> provide constants for request and response
+ * headers, XML elements and property names defined by
+ * <a href="http://www.webdav.org/specs/rfc2518.html">RFC 2518</a>. In addition,
+ * common date formats (creation date and modification time) are included.
+ */
+public interface DavConstants {
+
+ /**
+ * Default Namespace constant
+ */
+ public static final Namespace NAMESPACE = Namespace.getNamespace("D", "DAV:");
+
+ //--------------------------------< Headers (Names and Value Constants) >---
+ public static final String HEADER_DAV = "DAV";
+ public static final String HEADER_DESTINATION = "Destination";
+ public static final String HEADER_IF = "If";
+ public static final String HEADER_AUTHORIZATION = "Authorization";
+ public static final String HEADER_CONTENT_TYPE = "Content-Type";
+ public static final String HEADER_CONTENT_LENGTH = "Content-Length";
+ public static final String HEADER_CONTENT_LANGUAGE = "Content-Language";
+ public static final String HEADER_ETAG = "ETag";
+ public static final String HEADER_LAST_MODIFIED = "Last-Modified";
+
+ //--------------------------------------------------< Lock-Token Header >---
+ public static final String HEADER_LOCK_TOKEN = "Lock-Token";
+ public static final String OPAQUE_LOCK_TOKEN_PREFIX = "opaquelocktoken:";
+
+ //-----------------------------------------------------< Timeout Header >---
+ public static final String HEADER_TIMEOUT = "Timeout";
+ public static final String TIMEOUT_INFINITE = "Infinite";
+ // RFC 2518: timeout value for TimeType "Second" MUST NOT be greater than 2^32-1
+ public static final long INFINITE_TIMEOUT = Integer.MAX_VALUE;
+ public static final long UNDEFINED_TIMEOUT = Integer.MIN_VALUE;
+
+ //---------------------------------------------------< Overwrite Header >---
+ public static final String HEADER_OVERWRITE = "Overwrite";
+
+ //-------------------------------------------------------< Depth Header >---
+ public static final String HEADER_DEPTH = "Depth";
+ public static final String DEPTH_INFINITY_S = "infinity";
+ public static final int DEPTH_INFINITY = Integer.MAX_VALUE;
+ public static final int DEPTH_0 = 0;
+ public static final int DEPTH_1 = 1;
+
+ //---< XML Element, Attribute Names >---------------------------------------
+ public static final String XML_ALLPROP = "allprop";
+ public static final String XML_COLLECTION = "collection";
+ public static final String XML_DST = "dst";
+ public static final String XML_HREF = "href";
+ public static final String XML_INCLUDE = "include";
+ public static final String XML_KEEPALIVE = "keepalive";
+ public static final String XML_LINK = "link";
+ public static final String XML_MULTISTATUS = "multistatus";
+ public static final String XML_OMIT = "omit";
+ public static final String XML_PROP = "prop";
+ public static final String XML_PROPERTYBEHAVIOR = "propertybehavior";
+ public static final String XML_PROPERTYUPDATE = "propertyupdate";
+ public static final String XML_PROPFIND = "propfind";
+ public static final String XML_PROPNAME = "propname";
+ public static final String XML_PROPSTAT = "propstat";
+ public static final String XML_REMOVE = "remove";
+ public static final String XML_RESPONSE = "response";
+ public static final String XML_RESPONSEDESCRIPTION = "responsedescription";
+ public static final String XML_SET = "set";
+ public static final String XML_SOURCE = "source";
+ public static final String XML_STATUS = "status";
+
+ //------------------------------------------------------------< locking >---
+ public static final String XML_ACTIVELOCK = "activelock";
+ public static final String XML_DEPTH = "depth";
+ public static final String XML_LOCKTOKEN = "locktoken";
+ public static final String XML_TIMEOUT = "timeout";
+ public static final String XML_LOCKSCOPE = "lockscope";
+ public static final String XML_EXCLUSIVE = "exclusive";
+ public static final String XML_SHARED = "shared";
+ public static final String XML_LOCKENTRY = "lockentry";
+ public static final String XML_LOCKINFO = "lockinfo";
+ public static final String XML_LOCKTYPE = "locktype";
+ public static final String XML_WRITE = "write";
+ public static final String XML_OWNER = "owner";
+ /**
+ * The <code>lockroot</code> XML element
+ * @see <a href="http://www.webdav.org/specs/rfc4918.html#ELEMENT_lockroot">RFC 4918</a>
+ */
+ public static final String XML_LOCKROOT = "lockroot";
+
+ //-----------------------------------------------------< Property Names >---
+ /*
+ * Webdav property names as defined by RFC 2518<br>
+ * Note: Microsoft webdav clients as well as Webdrive request additional
+ * property (e.g. href, name, owner, isRootLocation, isCollection) within the
+ * default namespace, which are are ignored by this implementation, except
+ * for the 'isCollection' property, needed for XP built-in clients.
+ */
+ public static final String PROPERTY_CREATIONDATE = "creationdate";
+ public static final String PROPERTY_DISPLAYNAME = "displayname";
+ public static final String PROPERTY_GETCONTENTLANGUAGE = "getcontentlanguage";
+ public static final String PROPERTY_GETCONTENTLENGTH = "getcontentlength";
+ public static final String PROPERTY_GETCONTENTTYPE = "getcontenttype";
+ public static final String PROPERTY_GETETAG = "getetag";
+ public static final String PROPERTY_GETLASTMODIFIED = "getlastmodified";
+ public static final String PROPERTY_LOCKDISCOVERY = "lockdiscovery";
+ public static final String PROPERTY_RESOURCETYPE = "resourcetype";
+ public static final String PROPERTY_SOURCE = "source";
+ public static final String PROPERTY_SUPPORTEDLOCK = "supportedlock";
+
+ //-------------------------------------------------< PropFind Constants >---
+ public static final int PROPFIND_BY_PROPERTY = 0;
+ public static final int PROPFIND_ALL_PROP = 1;
+ public static final int PROPFIND_PROPERTY_NAMES = 2;
+ public static final int PROPFIND_ALL_PROP_INCLUDE = 3; // RFC 4918, Section 9.1
+
+ //----------------------------------------------< Date Format Constants >---
+ /**
+ * Marker for undefined modification or creation time.
+ */
+ public static long UNDEFINED_TIME = -1;
+
+ /**
+ * modificationDate date format per RFC 1123.<br>
+ * NOTE: Access to <code>DateFormat</code> isn't thread save.
+ */
+ public static DateFormat modificationDateFormat = HttpDateFormat.modificationDateFormat();
+
+ /**
+ * Simple date format for the creation date ISO representation (partial).<br>
+ * NOTE: Access to <code>DateFormat</code> isn't thread save.
+ */
+ public static DateFormat creationDateFormat = HttpDateFormat.creationDateFormat();
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavException.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavException.java
new file mode 100644
index 000000000..1c7c611db
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavException.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import org.apache.jackrabbit.webdav.xml.DomUtil;
+import org.apache.jackrabbit.webdav.xml.XmlSerializable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ * <code>DavException</code> extends the {@link Exception} class in order
+ * to simplify handling of exceptional situations occurring during processing
+ * of WebDAV requests and provides possibility to retrieve an Xml representation
+ * of the error.
+ */
+public class DavException extends Exception implements XmlSerializable {
+
+ private static Logger log = LoggerFactory.getLogger(DavException.class);
+ private static Properties statusPhrases = new Properties();
+ static {
+ try {
+ statusPhrases.load(DavException.class.getResourceAsStream("statuscode.properties"));
+ } catch (IOException e) {
+ log.error("Failed to load status properties: " + e.getMessage());
+ }
+ }
+
+ public static final String XML_ERROR = "error";
+
+ private int errorCode = DavServletResponse.SC_INTERNAL_SERVER_ERROR;
+ private Element errorCondition;
+
+ /**
+ * Create a new <code>DavException</code>.
+ *
+ * @param errorCode integer specifying any of the status codes defined by
+ * {@link DavServletResponse}.
+ * @param message Human readable error message.
+ * @see DavException#DavException(int, String, Throwable, Element)
+ */
+ public DavException(int errorCode, String message) {
+ this(errorCode, message, null, null);
+ }
+
+ /**
+ * Create a new <code>DavException</code>.
+ *
+ * @param errorCode integer specifying any of the status codes defined by
+ * {@link DavServletResponse}.
+ * @param cause Cause of this DavException
+ * @see DavException#DavException(int, String, Throwable, Element)
+ */
+ public DavException(int errorCode, Throwable cause) {
+ this(errorCode, null, cause, null);
+ }
+
+ /**
+ * Create a new <code>DavException</code>.
+ *
+ * @param errorCode integer specifying any of the status codes defined by
+ * {@link DavServletResponse}.
+ * @see DavException#DavException(int, String, Throwable, Element)
+ */
+ public DavException(int errorCode) {
+ this(errorCode, statusPhrases.getProperty(String.valueOf(errorCode)), null, null);
+ }
+
+ /**
+ * Create a new <code>DavException</code>.
+ *
+ * @param errorCode integer specifying any of the status codes defined by
+ * {@link DavServletResponse}.
+ * @param message Human readable error message.
+ * @param cause Cause of this <code>DavException</code>.
+ * @param errorCondition Xml element providing detailed information about
+ * the error. If the condition is not <code>null</code>, {@link #toXml(Document)}
+ */
+ public DavException(int errorCode, String message, Throwable cause, Element errorCondition) {
+ super(message, cause);
+ this.errorCode = errorCode;
+ this.errorCondition = errorCondition;
+ log.debug("DavException: (" + errorCode + ") " + message);
+ }
+
+ /**
+ * Return the error code attached to this <code>DavException</code>.
+ *
+ * @return errorCode
+ */
+ public int getErrorCode() {
+ return errorCode;
+ }
+
+ /**
+ * Return the status phrase corresponding to the error code attached to
+ * this <code>DavException</code>.
+ *
+ * @return status phrase corresponding to the error code.
+ * @see #getErrorCode()
+ */
+ public String getStatusPhrase() {
+ return getStatusPhrase(errorCode);
+ }
+
+ /**
+ * Returns the status phrase for the given error code.
+ *
+ * @param errorCode
+ * @return status phrase corresponding to the given error code.
+ */
+ public static String getStatusPhrase(int errorCode) {
+ return statusPhrases.getProperty(errorCode + "");
+ }
+
+ /**
+ * @return true if a error condition has been specified, false otherwise.
+ */
+ public boolean hasErrorCondition() {
+ return errorCondition != null;
+ }
+
+ /**
+ * Return the error condition attached to this <code>DavException</code>.
+ *
+ * @return errorCondition
+ */
+ public Element getErrorCondition() {
+ return errorCondition;
+ }
+
+ /**
+ * Returns a DAV:error element containing the error condition or
+ * <code>null</code> if no specific condition is available. See
+ * <a href="http://www.ietf.org/rfc/rfc3253.txt">RFC 3253</a>
+ * Section 1.6 "Method Preconditions and Postconditions" for additional
+ * information.
+ *
+ * @param document
+ * @return A DAV:error element indicating the error cause or <code>null</code>.
+ * @see org.apache.jackrabbit.webdav.xml.XmlSerializable#toXml(Document)
+ */
+ public Element toXml(Document document) {
+ if (hasErrorCondition()) {
+ Element error;
+ if (DomUtil.matches(errorCondition, XML_ERROR, DavConstants.NAMESPACE)) {
+ error = (Element) document.importNode(errorCondition, true);
+ } else {
+ error = DomUtil.createElement(document, XML_ERROR, DavConstants.NAMESPACE);
+ error.appendChild(document.importNode(errorCondition, true));
+ }
+ return error;
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavLocatorFactory.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavLocatorFactory.java
new file mode 100644
index 000000000..db4ca0a9b
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavLocatorFactory.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+/**
+ * <code>DavLocatorFactory</code>...
+ */
+public interface DavLocatorFactory {
+
+ /**
+ * Create a new <code>DavResourceLocator</code>.
+ *
+ * @param prefix String consisting of [scheme:][//authority][path] where
+ * path defines the (imaginary) path to the {@link DavResourceLocator#isRootLocation root location}.
+ * @param href of the resource to be created. The given string may start with
+ * the 'prefix'. Please note, that in contrast to
+ * {@link DavLocatorFactory#createResourceLocator(String, String, String)} the
+ * href is expected to be URL encoded.
+ * @return a new resource locator.
+ */
+ public DavResourceLocator createResourceLocator(String prefix, String href);
+
+ /**
+ * Create a new <code>DavResourceLocator</code>. This methods corresponds to
+ * {@link DavLocatorFactory#createResourceLocator(String, String, String, boolean)}
+ * with the flag set to true.
+ *
+ * @param prefix String consisting of [scheme:][//authority][path] where
+ * path defines the path to the {@link DavResourceLocator#isRootLocation root location}.
+ * @param workspacePath the first segment of the URIs path indicating the
+ * workspace. The implementation may allow a empty String if workspaces
+ * are not supported.
+ * @param resourcePath the URL decoded resource path.
+ * @return a new resource locator.
+ */
+ public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String resourcePath);
+
+ /**
+ *
+ * @param prefix String consisting of [scheme:][//authority][path] where
+ * path defines the path to the {@link DavResourceLocator#isRootLocation root location}.
+ * @param workspacePath the first segment of the URIs path indicating the
+ * workspace. The implementation may allow a empty String if workspaces
+ * are not supported.
+ * @param path the URL decoded path.
+ * @param isResourcePath If true this method returns the same as
+ * {@link DavLocatorFactory#createResourceLocator(String, String, String)},
+ * otherwise the given path is treated as internal repository path.
+ * The implementation may choose to implement a conversion of the repository
+ * path to a valid resource path, e.g. (un)escaping of certain characters, due
+ * to incompatibility with the URI definition (or vice versa). Note that
+ * {@link DavResourceLocator#getRepositoryPath()} should in this case implement
+ * the reverse operation.
+ * @return a new resource locator.
+ * @see DavResourceLocator#getRepositoryPath()
+ */
+ public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String path, boolean isResourcePath);
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavMethods.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavMethods.java
new file mode 100644
index 000000000..003d7976d
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavMethods.java
@@ -0,0 +1,410 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * <code>DavMethods</code> defines constants for the WebDAV METHODS.
+ */
+public final class DavMethods {
+
+ /**
+ * Avoid instantiation
+ */
+ private DavMethods() {}
+
+ /**
+ * A map of WebDAV METHODS
+ */
+ private static Map<String, Integer> methodMap = new HashMap<String, Integer>();
+
+ /**
+ * An array of method codes that are affected by a Label header
+ * @see org.apache.jackrabbit.webdav.version.DeltaVConstants#HEADER_LABEL
+ */
+ private static int[] labelMethods;
+
+ /**
+ * An array of method codes defined by RFC 3253 (deltaV)
+ */
+ private static int[] deltaVMethods;
+
+ /**
+ * The webdav OPTIONS method and public constant
+ */
+ public static final int DAV_OPTIONS = 1;
+ public static final String METHOD_OPTIONS = "OPTIONS";
+
+ /**
+ * The webdav GET method and public constant
+ */
+ public static final int DAV_GET = DAV_OPTIONS + 1;
+ public static final String METHOD_GET = "GET";
+
+ /**
+ * The webdav HEAD method and public constant
+ */
+ public static final int DAV_HEAD = DAV_GET + 1;
+ public static final String METHOD_HEAD = "HEAD";
+
+
+ /**
+ * The webdav POST method and public constant
+ */
+ public static final int DAV_POST = DAV_HEAD + 1;
+ public static final String METHOD_POST = "POST";
+
+
+ /** The webdav DELETE method and public constant */
+ public static final int DAV_DELETE = DAV_POST + 1;
+ public static final String METHOD_DELETE = "DELETE";
+
+
+ /** The webdav PUT method and public constant */
+ public static final int DAV_PUT = DAV_DELETE + 1;
+ public static final String METHOD_PUT = "PUT";
+
+
+ /**
+ * The webdav PROPFIND method and public constant as defined by
+ * <a href="http://www.ietf.org/rfc/rfc2518.txt">RFC 2518</a>.
+ */
+ public static final int DAV_PROPFIND = DAV_PUT + 1;
+ public static final String METHOD_PROPFIND = "PROPFIND";
+
+
+ /**
+ * The webdav PROPPATCH method and public constant as defined by
+ * <a href="http://www.ietf.org/rfc/rfc2518.txt">RFC 2518</a>
+ */
+ public static final int DAV_PROPPATCH = DAV_PROPFIND + 1;
+ public static final String METHOD_PROPPATCH = "PROPPATCH";
+
+
+ /**
+ * The webdav MKCOL (make collection) method and public constant as defined by
+ * <a href="http://www.ietf.org/rfc/rfc2518.txt">RFC 2518</a>
+ */
+ public static final int DAV_MKCOL = DAV_PROPPATCH + 1;
+ public static final String METHOD_MKCOL = "MKCOL";
+
+
+ /**
+ * The webdav COPY method and public constant as defined by
+ * <a href="http://www.ietf.org/rfc/rfc2518.txt">RFC 2518</a>
+ */
+ public static final int DAV_COPY = DAV_MKCOL + 1;
+ public static final String METHOD_COPY = "COPY";
+
+
+ /**
+ * The webdav MOVE method and public constant as defined by
+ * <a href="http://www.ietf.org/rfc/rfc2518.txt">RFC 2518</a>
+ */
+ public static final int DAV_MOVE = DAV_COPY + 1;
+ public static final String METHOD_MOVE = "MOVE";
+
+
+ /**
+ * The webdav LOCK method and public constant as defined by
+ * <a href="http://www.ietf.org/rfc/rfc2518.txt">RFC 2518</a>
+ */
+ public static final int DAV_LOCK = DAV_MOVE + 1;
+ public static final String METHOD_LOCK = "LOCK";
+
+
+ /**
+ * The webdav UNLOCK method and public constant as defined by
+ * <a href="http://www.ietf.org/rfc/rfc2518.txt">RFC 2518</a>
+ */
+ public static final int DAV_UNLOCK = DAV_LOCK + 1;
+ public static final String METHOD_UNLOCK = "UNLOCK";
+
+
+ /**
+ * The webdav ORDERPATCH method and public constant
+ * defined by <a href="http://www.ietf.org/rfc/rfc3648.txt">RFC 3648</a>.
+ */
+ public static final int DAV_ORDERPATCH = DAV_UNLOCK + 1;
+ public static final String METHOD_ORDERPATCH = "ORDERPATCH";
+
+
+ /**
+ * The webdav SUBSCRIBE method and public constant.<br>
+ * NOTE: This method is not defined by any of the Webdav RFCs
+ */
+ public static final int DAV_SUBSCRIBE = DAV_ORDERPATCH + 1;
+ public static final String METHOD_SUBSCRIBE = "SUBSCRIBE";
+
+
+ /**
+ * The webdav UNSUBSCRIBE method and public constant<br>
+ * NOTE: This method is not defined by any of the Webdav RFCs
+ */
+ public static final int DAV_UNSUBSCRIBE = DAV_SUBSCRIBE + 1;
+ public static final String METHOD_UNSUBSCRIBE = "UNSUBSCRIBE";
+
+
+ /**
+ * The webdav POLL method and public constant<br>
+ * NOTE: This method is not defined by any of the Webdav RFCs
+ */
+ public static final int DAV_POLL = DAV_UNSUBSCRIBE + 1;
+ public static final String METHOD_POLL = "POLL";
+
+
+ /**
+ * The webdav SEARCH method and public constant as defined by the
+ * Webdav Search internet draft.
+ */
+ public static final int DAV_SEARCH = DAV_POLL + 1;
+ public static final String METHOD_SEARCH = "SEARCH";
+
+
+ /**
+ * The webdav REPORT method and public constant defined by
+ * <a href="http://www.ietf.org/rfc/rfc3253.txt">RFC 3253</a>
+ */
+ public static final int DAV_REPORT = DAV_SEARCH + 1;
+ public static final String METHOD_REPORT = "REPORT";
+
+
+ /**
+ * The webdav VERSION-CONTROL method and public constant defined by
+ * <a href="http://www.ietf.org/rfc/rfc3253.txt">RFC 3253</a>
+ */
+ public static final int DAV_VERSION_CONTROL = DAV_REPORT + 1;
+ public static final String METHOD_VERSION_CONTROL = "VERSION-CONTROL";
+
+ /**
+ * The webdav CHECKIN method and public constant defined by
+ * <a href="http://www.ietf.org/rfc/rfc3253.txt">RFC 3253</a>
+ */
+ public static final int DAV_CHECKIN = DAV_VERSION_CONTROL + 1;
+ public static final String METHOD_CHECKIN = "CHECKIN";
+
+ /**
+ * The webdav CHECKOUT method and public constant defined by
+ * <a href="http://www.ietf.org/rfc/rfc3253.txt">RFC 3253</a>
+ */
+ public static final int DAV_CHECKOUT = DAV_CHECKIN + 1;
+ public static final String METHOD_CHECKOUT = "CHECKOUT";
+
+ /**
+ * The webdav UNCHECKOUT method and public constant defined by
+ * <a href="http://www.ietf.org/rfc/rfc3253.txt">RFC 3253</a>
+ */
+ public static final int DAV_UNCHECKOUT = DAV_CHECKOUT + 1;
+ public static final String METHOD_UNCHECKOUT = "UNCHECKOUT";
+
+ /**
+ * The webdav LABEL method and public constant defined by
+ * <a href="http://www.ietf.org/rfc/rfc3253.txt">RFC 3253</a>
+ */
+ public static final int DAV_LABEL = DAV_UNCHECKOUT + 1;
+ public static final String METHOD_LABEL = "LABEL";
+
+ /**
+ * The webdav MERGE method and public constant defined by
+ * <a href="http://www.ietf.org/rfc/rfc3253.txt">RFC 3253</a>
+ */
+ public static final int DAV_MERGE = DAV_LABEL + 1;
+ public static final String METHOD_MERGE = "MERGE";
+
+ /**
+ * The webdav UPDATE method and public constant defined by
+ * <a href="http://www.ietf.org/rfc/rfc3253.txt">RFC 3253</a>
+ */
+ public static final int DAV_UPDATE = DAV_MERGE + 1;
+ public static final String METHOD_UPDATE = "UPDATE";
+
+ /**
+ * The webdav MKWORKSPACE method and public constant defined by
+ * <a href="http://www.ietf.org/rfc/rfc3253.txt">RFC 3253</a>
+ */
+ public static final int DAV_MKWORKSPACE = DAV_UPDATE + 1;
+ public static final String METHOD_MKWORKSPACE = "MKWORKSPACE";
+
+ /**
+ * The webdav BASELINE-CONTROL method and public constant defined by
+ * <a href="http://www.ietf.org/rfc/rfc3253.txt">RFC 3253</a>
+ */
+ public static final int DAV_BASELINE_CONTROL = DAV_MKWORKSPACE + 1;
+ public static final String METHOD_BASELINE_CONTROL = "BASELINE-CONTROL";
+
+ /**
+ * The webdav MKACTIVITY method and public constant defined by
+ * <a href="http://www.ietf.org/rfc/rfc3253.txt">RFC 3253</a>
+ */
+ public static final int DAV_MKACTIVITY = DAV_BASELINE_CONTROL + 1;
+ public static final String METHOD_MKACTIVITY = "MKACTIVITY";
+
+ /**
+ * The webdav ACL method and public constant defined by
+ * <a href="http://www.ietf.org/rfc/rfc3744.txt">RFC 3744</a>
+ */
+ public static final int DAV_ACL = DAV_MKACTIVITY + 1;
+ public static final String METHOD_ACL = "ACL";
+
+ /**
+ * The webdav REBIND method and public constant defined by
+ * the BIND specification
+ */
+ public static final int DAV_REBIND = DAV_ACL + 1;
+ public static final String METHOD_REBIND = "REBIND";
+
+ /**
+ * The webdav UNBIND method and public constant defined by
+ * the BIND specification
+ */
+ public static final int DAV_UNBIND = DAV_REBIND + 1;
+ public static final String METHOD_UNBIND = "UNBIND";
+
+ /**
+ * The webdav BIND method and public constant defined by
+ * the BIND specification
+ */
+ public static final int DAV_BIND = DAV_UNBIND + 1;
+ public static final String METHOD_BIND = "BIND";
+
+ /**
+ * Returns webdav method type code, error result <= 0
+ * Valid type codes > 0
+ */
+ public static int getMethodCode(String method) {
+ Integer code = methodMap.get(method.toUpperCase(Locale.ROOT));
+ if (code != null) {
+ return code;
+ }
+ return 0;
+ }
+
+ /**
+ * Static initializer for methodTable map
+ */
+ private static void addMethodCode(String method, int code) {
+ methodMap.put(method, code);
+ }
+
+ /**
+ * Webdav Method table
+ */
+ static {
+ addMethodCode(METHOD_OPTIONS, DAV_OPTIONS);
+ addMethodCode(METHOD_GET, DAV_GET);
+ addMethodCode(METHOD_HEAD, DAV_HEAD);
+ addMethodCode(METHOD_POST, DAV_POST);
+ addMethodCode(METHOD_PUT, DAV_PUT);
+ addMethodCode(METHOD_DELETE, DAV_DELETE);
+ addMethodCode(METHOD_PROPFIND, DAV_PROPFIND);
+ addMethodCode(METHOD_PROPPATCH, DAV_PROPPATCH);
+ addMethodCode(METHOD_MKCOL, DAV_MKCOL);
+ addMethodCode(METHOD_COPY, DAV_COPY);
+ addMethodCode(METHOD_MOVE, DAV_MOVE);
+ addMethodCode(METHOD_LOCK, DAV_LOCK);
+ addMethodCode(METHOD_UNLOCK, DAV_UNLOCK);
+ addMethodCode(METHOD_ORDERPATCH, DAV_ORDERPATCH);
+ addMethodCode(METHOD_SUBSCRIBE, DAV_SUBSCRIBE);
+ addMethodCode(METHOD_UNSUBSCRIBE, DAV_UNSUBSCRIBE);
+ addMethodCode(METHOD_POLL, DAV_POLL);
+ addMethodCode(METHOD_SEARCH, DAV_SEARCH);
+ addMethodCode(METHOD_REPORT, DAV_REPORT);
+ addMethodCode(METHOD_VERSION_CONTROL, DAV_VERSION_CONTROL);
+ addMethodCode(METHOD_CHECKIN, DAV_CHECKIN);
+ addMethodCode(METHOD_CHECKOUT, DAV_CHECKOUT);
+ addMethodCode(METHOD_UNCHECKOUT, DAV_UNCHECKOUT);
+ addMethodCode(METHOD_LABEL, DAV_LABEL);
+ addMethodCode(METHOD_MERGE, DAV_MERGE);
+ addMethodCode(METHOD_UPDATE, DAV_UPDATE);
+ addMethodCode(METHOD_MKWORKSPACE, DAV_MKWORKSPACE);
+ addMethodCode(METHOD_BASELINE_CONTROL, DAV_BASELINE_CONTROL);
+ addMethodCode(METHOD_MKACTIVITY, DAV_MKACTIVITY);
+ addMethodCode(METHOD_ACL, DAV_ACL);
+ addMethodCode(METHOD_REBIND, DAV_REBIND);
+ addMethodCode(METHOD_UNBIND, DAV_UNBIND);
+ addMethodCode(METHOD_BIND, DAV_BIND);
+
+ labelMethods = new int[] { DAV_GET, DAV_HEAD, DAV_OPTIONS, DAV_PROPFIND,
+ DAV_LABEL, DAV_COPY };
+
+ deltaVMethods = new int[] { DAV_REPORT, DAV_VERSION_CONTROL, DAV_CHECKIN,
+ DAV_CHECKOUT, DAV_UNCHECKOUT, DAV_LABEL,
+ DAV_MERGE, DAV_UPDATE, DAV_MKWORKSPACE,
+ DAV_BASELINE_CONTROL, DAV_MKACTIVITY };
+ }
+
+ /**
+ * Returns <code>true</code> if the request is to create a resource.
+ * True for <code>PUT</code>, <code>POST</code>, <code>MKCOL</code>
+ * and <code>MKWORKSPACE</code> requests.
+ *
+ * @return true if request method is to create (or replace) a resource
+ */
+ public static boolean isCreateRequest(DavServletRequest request) {
+ int methodCode = getMethodCode(request.getMethod());
+ return ( methodCode == DAV_PUT ||
+ methodCode == DAV_POST ||
+ methodCode == DAV_MKCOL ||
+ methodCode == DAV_MKWORKSPACE);
+ }
+
+ /**
+ * Returns <code>true</code> if the request is to create a collection resource.
+ * True for <code>MKCOL</code> and <code>MKWORKSPACE</code> requests.
+ *
+ * @return true if request method is to create a new collection resource
+ */
+ public static boolean isCreateCollectionRequest(DavServletRequest request) {
+ int methodCode = getMethodCode(request.getMethod());
+ return (methodCode == DAV_MKCOL || methodCode == DAV_MKWORKSPACE);
+ }
+
+ /**
+ * Returns true, if the specified method is affected by a Label header
+ *
+ * @param request
+ * @return
+ */
+ public static boolean isMethodAffectedByLabel(DavServletRequest request) {
+ int code = getMethodCode(request.getMethod());
+ for (int labelMethod : labelMethods) {
+ if (code == labelMethod) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true, if the specified method is defined by RFC 3253
+ *
+ * @param request
+ * @return true, if the specified method is defined by RFC 3253
+ */
+ public static boolean isDeltaVMethod(DavServletRequest request) {
+ int code = getMethodCode(request.getMethod());
+ for (int deltaVMethod : deltaVMethods) {
+ if (code == deltaVMethod) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavResource.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavResource.java
new file mode 100644
index 000000000..6e70a4206
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavResource.java
@@ -0,0 +1,334 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import org.apache.jackrabbit.webdav.io.InputContext;
+import org.apache.jackrabbit.webdav.io.OutputContext;
+import org.apache.jackrabbit.webdav.lock.ActiveLock;
+import org.apache.jackrabbit.webdav.lock.LockInfo;
+import org.apache.jackrabbit.webdav.lock.LockManager;
+import org.apache.jackrabbit.webdav.lock.Scope;
+import org.apache.jackrabbit.webdav.lock.Type;
+import org.apache.jackrabbit.webdav.property.DavProperty;
+import org.apache.jackrabbit.webdav.property.DavPropertyName;
+import org.apache.jackrabbit.webdav.property.DavPropertySet;
+import org.apache.jackrabbit.webdav.property.PropEntry;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * <code>DavResource</code> provides standard WebDAV functionality as specified
+ * by <a href="http://www.ietf.org/rfc/rfc2518.txt">RFC 2518</a>.
+ */
+public interface DavResource {
+
+ /**
+ * String constant representing the WebDAV 1 and 2 method set.
+ */
+ public static final String METHODS = "OPTIONS, GET, HEAD, TRACE, PROPFIND, PROPPATCH, MKCOL, COPY, PUT, DELETE, MOVE, LOCK, UNLOCK";
+
+ /**
+ * Returns a comma separated list of all compliance classes the given
+ * resource is fulfilling.
+ *
+ * @return compliance classes
+ */
+ public String getComplianceClass();
+
+ /**
+ * Returns a comma separated list of all METHODS supported by the given
+ * resource.
+ *
+ * @return METHODS supported by this resource.
+ */
+ public String getSupportedMethods();
+
+ /**
+ * Returns true if this webdav resource represents an existing repository item.
+ *
+ * @return true, if the resource represents an existing repository item.
+ */
+ public boolean exists();
+
+ /**
+ * Returns true if this webdav resource has the resourcetype 'collection'.
+ *
+ * @return true if the resource represents a collection resource.
+ */
+ public boolean isCollection();
+
+ /**
+ * Returns the display name of this resource.
+ *
+ * @return display name.
+ */
+ public String getDisplayName();
+
+ /**
+ * Returns the {@link DavResourceLocator locator} object for this webdav resource,
+ * which encapsulates the information for building the complete 'href'.
+ *
+ * @return the locator for this resource.
+ * @see #getResourcePath()
+ * @see #getHref()
+ */
+ public DavResourceLocator getLocator();
+
+ /**
+ * Returns the path of the hierarchy element defined by this <code>DavResource</code>.
+ * This method is a shortcut for <code>DavResource.getLocator().getResourcePath()</code>.
+ *
+ * @return path of the element defined by this <code>DavResource</code>.
+ */
+ public String getResourcePath();
+
+ /**
+ * Returns the absolute href of this resource as returned in the
+ * multistatus response body.
+ *
+ * @return href
+ */
+ public String getHref();
+
+ /**
+ * Return the time of the last modification or -1 if the modification time
+ * could not be retrieved.
+ *
+ * @return time of last modification or -1.
+ */
+ public long getModificationTime();
+
+ /**
+ * Spools the resource properties and ev. content to the specified context
+ * (e.g. to respond to a 'GET' or 'HEAD' request). The context could e.g.
+ * wrap the servlet response.
+ *
+ * @param outputContext The output context.
+ * @throws IOException If an error occurs.
+ */
+ public void spool(OutputContext outputContext) throws IOException;
+
+ /**
+ * Returns an array of all {@link DavPropertyName property names} available
+ * on this resource.
+ *
+ * @return an array of property names.
+ */
+ public DavPropertyName[] getPropertyNames();
+
+ /**
+ * Return the webdav property with the specified name.
+ *
+ * @param name name of the webdav property
+ * @return the {@link DavProperty} with the given name or <code>null</code>
+ * if the property does not exist.
+ */
+ public DavProperty<?> getProperty(DavPropertyName name);
+
+ /**
+ * Returns all webdav properties present on this resource that will be
+ * return upon a {@link DavConstants#PROPFIND_ALL_PROP} request. The
+ * implementation may in addition expose other (protected or calculated)
+ * properties which should be marked accordingly (see also
+ * {@link org.apache.jackrabbit.webdav.property.DavProperty#isInvisibleInAllprop()}.
+ *
+ * @return a {@link DavPropertySet} containing at least all properties
+ * of this resource that are exposed in 'allprop' PROPFIND request.
+ */
+ public DavPropertySet getProperties();
+
+ /**
+ * Add/Set the specified property on this resource.
+ *
+ * @param property
+ * @throws DavException if an error occurs
+ */
+ public void setProperty(DavProperty<?> property) throws DavException;
+
+ /**
+ * Remove the specified property from this resource.
+ *
+ * @param propertyName
+ * @throws DavException if an error occurs
+ */
+ public void removeProperty(DavPropertyName propertyName) throws DavException;
+
+ /**
+ * Set/add and remove the specified properties from this resource.
+ *
+ * @param changeList list containing {@link DavPropertyName} objects (for
+ * properties to be removed) and {@link DavProperty} objects (for
+ * properties to be added/set).
+ * @return multistatus response listing the status resulting from
+ * setting and/or removing the specified properties, in order to allow a
+ * detailed multistatus response.
+ * @throws DavException if an error occurred. This may be the case if the
+ * general state of the resource prevents any properties to be set or removed
+ * (e.g. due to a lock).
+ */
+ public MultiStatusResponse alterProperties(List<? extends PropEntry> changeList) throws DavException;
+
+ /**
+ * Retrieve the resource this resource is internal member of.
+ *
+ * @return resource this resource is an internal member of. In case this resource
+ * is the root <code>null</code> is returned.
+ */
+ public DavResource getCollection();
+
+ /**
+ * Add the given resource as an internal member to this resource.
+ *
+ * @param resource {@link DavResource} to be added as internal member.
+ * @param inputContext Context providing the properties and content for the
+ * internal member to be created or replaced.
+ * @throws DavException
+ */
+ public void addMember(DavResource resource, InputContext inputContext) throws DavException;
+
+ /**
+ * Returns an iterator over all internal members.
+ *
+ * @return a {@link DavResourceIterator} over all internal members.
+ */
+ public DavResourceIterator getMembers();
+
+ /**
+ * Removes the specified member from this resource.
+ *
+ * @throws DavException
+ */
+ public void removeMember(DavResource member) throws DavException;
+
+ /**
+ * Move this DavResource to the given destination resource
+ *
+ * @param destination
+ * @throws DavException
+ */
+ public void move(DavResource destination) throws DavException;
+
+ /**
+ * Copy this DavResource to the given destination resource
+ *
+ * @param destination
+ * @param shallow
+ * @throws DavException
+ */
+ public void copy(DavResource destination, boolean shallow) throws DavException;
+
+ /**
+ * Returns true, if the this resource allows locking. NOTE, that this method
+ * does not define, whether a lock/unlock can be successfully executed.
+ *
+ * @return true, if this resource supports any locking.
+ * @param type
+ * @param scope
+ */
+ public boolean isLockable(Type type, Scope scope);
+
+ /**
+ * Returns true if a lock applies to this resource. This may be either a
+ * lock on this resource itself or a deep lock inherited from a collection
+ * above this resource.<br>
+ * Note, that true is returned whenever a lock applies to that resource even
+ * if the lock is expired or not effective due to the fact that the request
+ * provides the proper lock token.
+ *
+ * @return true if a lock applies to this resource.
+ * @param type
+ */
+ public boolean hasLock(Type type, Scope scope);
+
+ /**
+ * Return the lock present on this webdav resource or <code>null</code>
+ * if the resource is either not locked or not lockable at all. Note, that
+ * a resource may have a lock that is inherited by a deep lock enforced on
+ * one of its 'parent' resources.
+ *
+ * @return lock information of this resource or <code>null</code> if this
+ * resource has no lock applying it. If an error occurs while retrieving the
+ * lock information <code>null</code> is returned as well.
+ * @param type
+ */
+ public ActiveLock getLock(Type type, Scope scope) ;
+
+ /**
+ * Returns an array of all locks applied to the given resource.
+ *
+ * @return array of locks. The array is empty if there are no locks applied
+ * to this resource.
+ */
+ public ActiveLock[] getLocks();
+
+ /**
+ * Lock this webdav resource with the information retrieve from the request
+ * and return the resulting lockdiscovery object.
+ *
+ * @param reqLockInfo lock info as retrieved from the request.
+ * @return lockdiscovery object to be returned in the response. If the lock
+ * could not be obtained a <code>DavException</code> is thrown.
+ * @throws DavException if the lock could not be obtained.
+ */
+ public ActiveLock lock(LockInfo reqLockInfo) throws DavException;
+
+ /**
+ * Refresh an existing lock by resetting the timeout.
+ *
+ * @param reqLockInfo lock info as retrieved from the request.
+ * @param lockToken identifying the lock to be refreshed.
+ * @return lockdiscovery object to be returned in the response body. If the lock
+ * could not be refreshed a <code>DavException</code> is thrown.
+ * @throws DavException if the lock could not be refreshed.
+ */
+ public ActiveLock refreshLock(LockInfo reqLockInfo, String lockToken) throws DavException;
+
+ /**
+ * Remove the lock identified by the included lock token from this resource.
+ * This method will return false if the unlocking did not succeed.
+ *
+ * @param lockToken identifying the lock to be removed.
+ * @throws DavException if the lock could not be removed.
+ */
+ public void unlock(String lockToken) throws DavException;
+
+ /**
+ * Add an external {@link LockManager} to this resource. This method may
+ * throw {@link UnsupportedOperationException} if the resource does handle
+ * locking itself.
+ *
+ * @param lockmgr
+ * @see LockManager
+ */
+ public void addLockManager(LockManager lockmgr);
+
+ /**
+ * Return the <code>DavResourceFactory</code> that created this resource.
+ *
+ * @return the factory that created this resource.
+ */
+ public DavResourceFactory getFactory();
+
+ /**
+ * Retrieve the <code>DavSession</code> associated with this resource.
+ *
+ * @return session object associated with this resource.
+ */
+ public DavSession getSession();
+}
+
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavResourceFactory.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavResourceFactory.java
new file mode 100644
index 000000000..b015fe330
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavResourceFactory.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+/**
+ * <code>DavResourceFactory</code> interface defines a single method for creating
+ * {@link DavResource} objects.
+ */
+public interface DavResourceFactory {
+
+ /**
+ * Create a {@link DavResource} object from the given locator, request and response
+ * objects.
+ *
+ * @param locator locator of the resource
+ * @param request
+ * @param response
+ * @return a new <code>DavResource</code> object.
+ * @throws DavException
+ */
+ public DavResource createResource(DavResourceLocator locator, DavServletRequest request, DavServletResponse response) throws DavException;
+
+ /**
+ * Create a new {@link DavResource} object from the given locator and session.
+ *
+ * @param locator
+ * @param session
+ * @return a new <code>DavResource</code> object.
+ * @throws DavException
+ */
+ public DavResource createResource(DavResourceLocator locator, DavSession session) throws DavException;
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavResourceIterator.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavResourceIterator.java
new file mode 100644
index 000000000..e625b28ad
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavResourceIterator.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import java.util.Iterator;
+
+/**
+ * DavResourceIterator extends the <code>Iterator</code> interface. Additional
+ * METHODS allow to retrieve the next {@link DavResource} from the iterator
+ * and the iterators size.
+ */
+public interface DavResourceIterator extends Iterator<DavResource> {
+
+ /**
+ * Returns the next {@link DavResource} in the iterator
+ * @return the next {@link DavResource}
+ */
+ public DavResource nextResource();
+
+ /**
+ * Return the number of {@link DavResource}s in the iterator.
+ * @return number of elements in the iterator.
+ */
+ public int size();
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavResourceIteratorImpl.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavResourceIteratorImpl.java
new file mode 100644
index 000000000..3f43b7a9a
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavResourceIteratorImpl.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Collections;
+
+/**
+ * <code>DavResourceIteratorImpl</code> implementation of the {@link DavResourceIterator}
+ * interface.<br>
+ * NOTE: {@link #remove()} is not implemented.
+ */
+public class DavResourceIteratorImpl implements DavResourceIterator {
+
+ private static Logger log = LoggerFactory.getLogger(DavResourceIteratorImpl.class);
+
+ public static final DavResourceIterator EMPTY = new DavResourceIteratorImpl(Collections.<DavResource>emptyList());
+
+ private Iterator<DavResource> it;
+ private int size;
+
+ /**
+ * Create a new DavResourceIterator from the specified list.
+ * @param list
+ */
+ public DavResourceIteratorImpl(List<DavResource> list) {
+ it = list.iterator();
+ size = list.size();
+ }
+
+ /**
+ * @see DavResourceIterator#hasNext()
+ */
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+
+ /**
+ * @see DavResourceIterator#next()
+ */
+ public DavResource next() {
+ return it.next();
+ }
+
+ /**
+ * @see DavResourceIterator#nextResource()
+ */
+ public DavResource nextResource() {
+ return next();
+ }
+
+ /**
+ * Returns the size of the initial list.
+ *
+ * @see DavResourceIterator#size()
+ */
+ public int size() {
+ return size;
+ }
+
+ /**
+ * @see DavResourceIterator#remove()
+ */
+ public void remove() {
+ throw new UnsupportedOperationException("Remove not allowed with DavResourceIteratorImpl");
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavResourceLocator.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavResourceLocator.java
new file mode 100644
index 000000000..2a9b82270
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavResourceLocator.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+/**
+ * <code>DavResourceLocator</code>...
+ */
+public interface DavResourceLocator {
+
+ /**
+ * Return the prefix used to build the complete href of the resource as
+ * required for the {@link DavConstants#XML_HREF href Xml} element.
+ * This includes scheme and host information as well as constant prefixes.
+ * However, this must not include workspace prefix.
+ *
+ * @return prefix needed in order to build the href from a resource path.
+ * @see #getResourcePath()
+ */
+ public String getPrefix();
+
+ /**
+ * Return the resource path.
+ *
+ * @return resource path
+ */
+ public String getResourcePath();
+
+ /**
+ * Return the path of the workspace the resource identified by this
+ * locator is member of.
+ *
+ * @return path of the workspace
+ */
+ public String getWorkspacePath();
+
+ /**
+ * Return the name of the workspace the resource identified by this
+ * locator is member of.
+ *
+ * @return workspace name
+ */
+ public String getWorkspaceName();
+
+ /**
+ * Returns true if the specified locator refers to a resource within the
+ * same workspace.
+ *
+ * @param locator
+ * @return true if both paths are in the same workspace.
+ */
+ public boolean isSameWorkspace(DavResourceLocator locator);
+
+ /**
+ * Returns true if the specified workspace name equals to the workspace
+ * name defined with this locator.
+ *
+ * @param workspaceName
+ * @return true if workspace names are equal.
+ */
+ public boolean isSameWorkspace(String workspaceName);
+
+ /**
+ * Return the 'href' representation of this locator object. The implementation
+ * should perform an URL encoding of the resource path.
+ *
+ * @param isCollection
+ * @return 'href' representation of this path
+ * @see DavConstants#XML_HREF
+ * @see DavResource#getHref()
+ */
+ public String getHref(boolean isCollection);
+
+ /**
+ * Returns true if this <code>DavResourceLocator</code> represents the root
+ * locator that would be requested with 'hrefPrefix'+'pathPrefix' with or
+ * without a trailing '/'.
+ *
+ * @return true if this locator object belongs to the root resource.
+ */
+ public boolean isRootLocation();
+
+ /**
+ * Return the locator factory that created this locator.
+ *
+ * @return the locator factory
+ */
+ public DavLocatorFactory getFactory();
+
+ /**
+ * An implementation may choose to circumvent the incompatibility of a
+ * repository path with the URI path by applying an appropriate conversion.
+ * This utility method allows to retrieve this transformed repository path.
+ * By default this method should return the same as {@link #getResourcePath()}
+ *
+ * @return a repository compatible form if the resource path.
+ * @see DavLocatorFactory#createResourceLocator(String, String, String, boolean)
+ * that allows to build a valid <code>DavResourceLocator</code> from a given
+ * repository path.
+ */
+ public String getRepositoryPath();
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavServletRequest.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavServletRequest.java
new file mode 100644
index 000000000..e26f0cdcb
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavServletRequest.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import org.apache.jackrabbit.webdav.lock.LockInfo;
+import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
+import org.apache.jackrabbit.webdav.property.DavProperty;
+import org.apache.jackrabbit.webdav.property.DavPropertyName;
+import org.apache.jackrabbit.webdav.property.PropEntry;
+import org.w3c.dom.Document;
+
+import jakarta.servlet.http.HttpServletRequest;
+import java.util.List;
+
+/**
+ * <code>DavServletRequest</code> extends the HttpServletRequest by Webdav
+ * specific METHODS.
+ */
+public interface DavServletRequest extends HttpServletRequest {
+
+ /**
+ * Sets the <code>DavSession</code> to this request.
+ *
+ * @param session
+ */
+ public void setDavSession(DavSession session);
+
+ /**
+ * Returns the {@link DavSession} created for this request.
+ *
+ * @return session for this resource
+ */
+ public DavSession getDavSession();
+
+ /**
+ * Return the locator of the requested {@link DavResource resource}.
+ *
+ * @return locator of the requested {@link DavResource resource}.
+ */
+ public DavResourceLocator getRequestLocator();
+
+ /**
+ * Parse the {@link DavConstants#HEADER_DESTINATION Destination header}
+ * and return the locator of the corresponding {@link DavResource resource}.
+ *
+ * @return locator of the resource specified with the Destination header.
+ * @see DavConstants#HEADER_DESTINATION
+ */
+ public DavResourceLocator getDestinationLocator() throws DavException;
+
+ /**
+ * Returns true if the {@link DavConstants#HEADER_OVERWRITE Overwrite header}
+ * is set to 'T' thus instructing the server to overwrite the state of a
+ * non-null destination resource during a COPY or MOVE. A Overwrite header
+ * value of 'F' will return false.
+ *
+ * @return true if the Overwrite header is set to 'T', false if it is set
+ * to 'F'.
+ * @see DavConstants#HEADER_OVERWRITE
+ */
+ public boolean isOverwrite();
+
+ /**
+ * Return the integer representation of the given {@link DavConstants#HEADER_DEPTH
+ * Depth header}. 'Infinity' is represented by {@link DavConstants#DEPTH_INFINITY}.
+ *
+ * @return integer representation of the {@link DavConstants#HEADER_DEPTH
+ * Depth header}.
+ * @see DavConstants#HEADER_DEPTH
+ */
+ public int getDepth();
+
+ /**
+ * Returns the integer representation of the {@link DavConstants#HEADER_DEPTH
+ * Depth header} or the given defaultValue, if the Depth header is missing.
+ *
+ * @param defaultValue to be returned if no Depth header is present.
+ * @return integer representation of the {@link DavConstants#HEADER_DEPTH
+ * Depth header} or the given defaultValue.
+ * @see DavConstants#HEADER_DEPTH
+ */
+ public int getDepth(int defaultValue);
+
+ /**
+ * Returns the token present in the {@link DavConstants#HEADER_LOCK_TOKEN
+ * Lock-Token Header} or <code>null</code> if no such header is available.<br>
+ * Note: The 'Lock-Token' header is sent with UNLOCK requests and with
+ * lock responses only. For any other request that may be affected by a lock
+ * the 'If' header field is responsible.
+ *
+ * @return the token present in the Lock-Token header.
+ * @see DavConstants#HEADER_LOCK_TOKEN
+ */
+ public String getLockToken();
+
+ /**
+ * Return the timeout requested in the {@link DavConstants#HEADER_TIMEOUT
+ * Timeout header} as <code>long</code>. The representation of the
+ * 'Infinite' timeout is left to the implementation.
+ *
+ * @return long value representation of the Timeout header.
+ * @see DavConstants#HEADER_TIMEOUT
+ * @see DavConstants#TIMEOUT_INFINITE
+ */
+ public long getTimeout();
+
+ /**
+ * Parse the Xml request body and return a {@link org.w3c.dom.Document}.
+ *
+ * @return Document representing the Xml request body or <code>null</code>
+ * if no request body is present.
+ * @throws DavException If the request body cannot be parsed into an Xml
+ * Document.
+ */
+ public Document getRequestDocument() throws DavException;
+
+ /**
+ * Return the type of PROPFIND request as indicated by the PROPFIND request
+ * body.
+ *
+ * @return type of PROPFIND request
+ * @see DavConstants#PROPFIND_ALL_PROP
+ * @see DavConstants#PROPFIND_BY_PROPERTY
+ * @see DavConstants#PROPFIND_PROPERTY_NAMES
+ * @see DavConstants#PROPFIND_ALL_PROP_INCLUDE
+ * @throws DavException If the propfind type could not be determined due to
+ * an invalid request body.
+ */
+ public int getPropFindType() throws DavException;
+
+ /**
+ * Return the set of properties the client requested with a PROPFIND request
+ * or an empty set if the type of PROPFIND request was {@link DavConstants#PROPFIND_ALL_PROP}
+ * or {@link DavConstants#PROPFIND_PROPERTY_NAMES}.
+ *
+ * @return set of properties the client requested with a PROPFIND request
+ * @throws DavException In case of invalid request body
+ */
+ public DavPropertyNameSet getPropFindProperties() throws DavException;
+
+ /**
+ * Return a {@link List} of property change operations. Each entry
+ * is either of type {@link DavPropertyName}, indicating a <remove>
+ * operation, or of type {@link DavProperty}, indicating a <set>
+ * operation. Note that ordering is significant here.
+ *
+ * @return {@link List} of property change operations
+ * @throws DavException In case of invalid request body
+ */
+ public List<? extends PropEntry> getPropPatchChangeList() throws DavException;
+
+ /**
+ * Return the parsed 'lockinfo' request body, the {@link DavConstants#HEADER_TIMEOUT
+ * Timeout header} and the {@link DavConstants#HEADER_DEPTH Depth header}
+ * of a LOCK request as <code>LockInfo</code> object.
+ *
+ * @return <code>LockInfo</code> object encapsulating the information
+ * present in the LOCK request.
+ * @see DavConstants#HEADER_TIMEOUT
+ * @see DavConstants#HEADER_DEPTH
+ * @see DavConstants#XML_LOCKINFO
+ * @throws DavException
+ */
+ public LockInfo getLockInfo() throws DavException;
+
+ /**
+ * Returns true, if the {@link DavConstants#HEADER_IF If header} present
+ * with the request matches the given resource.
+ *
+ * @param resource
+ * @return true, if the test is successful, false otherwise.
+ */
+ public boolean matchesIfHeader(DavResource resource);
+
+ /**
+ * Returns true, if the {@link DavConstants#HEADER_IF If header} present
+ * with the request matches to the given href, token and eTag.
+ *
+ * @param href
+ * @param token
+ * @param eTag
+ * @return true, if the test is successful, false otherwise.
+ */
+ public boolean matchesIfHeader(String href, String token, String eTag);
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavServletResponse.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavServletResponse.java
new file mode 100644
index 000000000..452b974e6
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavServletResponse.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import org.apache.jackrabbit.webdav.lock.ActiveLock;
+import org.apache.jackrabbit.webdav.xml.XmlSerializable;
+
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * <code>WebdavResponse</code> extends the HttpServletResponse by
+ * Webdav specific status codes and METHODS.
+ */
+public interface DavServletResponse extends HttpServletResponse {
+
+ /**
+ * The 102 (Processing) status code is an interim response used to
+ * inform the client that the server has accepted the complete request,
+ * but has not yet completed it.
+ */
+ int SC_PROCESSING = 102;
+
+ /**
+ * Status code (207) indicating that the response requires
+ * providing status for multiple independent operations.
+ */
+ int SC_MULTI_STATUS = 207;
+
+ /**
+ * The 422 (Unprocessable Entity) status code means the server understands
+ * the content type of the request entity (hence a 415(Unsupported Media Type)
+ * status code is inappropriate), and the syntax of the request entity is
+ * correct (thus a 400 (Bad Request) status code is inappropriate) but was
+ * unable to process the contained instructions. For example, this error
+ * condition may occur if an XML request body contains well-formed (i.e.,
+ * syntactically correct), but semantically erroneous XML instructions.
+ */
+ int SC_UNPROCESSABLE_ENTITY = 422;
+
+ /**
+ * Status code (423) indicating the destination resource of a
+ * method is locked, and either the request did not contain a
+ * valid Lock-Info header, or the Lock-Info header identifies
+ * a lock held by another principal.
+ */
+ int SC_LOCKED = 423;
+
+ /**
+ * Status code (424) indicating that the method could not be
+ * performed on the resource, because the requested action depended
+ * on another action which failed.
+ */
+ int SC_FAILED_DEPENDENCY = 424;
+
+ /**
+ * Status code (507) indicating that the resource does not have
+ * sufficient space to record the state of the resource after the
+ * execution of this method.
+ */
+ int SC_INSUFFICIENT_SPACE_ON_RESOURCE = 507;
+
+ /**
+ * Send a response body given more detailed information about the error
+ * occurred.
+ *
+ * @param error
+ * @throws IOException
+ */
+ public void sendError(DavException error) throws IOException;
+
+ /**
+ * Send the multistatus response to the client. A multistatus response
+ * is returned in response to a successful PROPFIND and PROPPATCH request.
+ * In addition multistatus response is required response in case a COPY,
+ * MOVE, DELETE, LOCK or PROPPATCH request fails.
+ *
+ * @param multistatus
+ * @throws IOException
+ * @see #SC_MULTI_STATUS
+ */
+ public void sendMultiStatus(MultiStatus multistatus) throws IOException;
+
+ /**
+ * Send the multistatus response to the client. A multistatus response
+ * is returned in response to a successful PROPFIND and PROPPATCH request.
+ * In addition multistatus response is required response in case a COPY,
+ * MOVE, DELETE, LOCK or PROPPATCH request fails.
+ *
+ * @param multistatus
+ * @param acceptableContentCodings content codings accepted by the client
+ * @throws IOException
+ * @see #SC_MULTI_STATUS
+ */
+ default void sendMultiStatus(MultiStatus multistatus, List<String> acceptableContentCodings) throws IOException {
+ sendMultiStatus(multistatus);
+ }
+
+ /**
+ * Send the lock response for a successful LOCK request, that was intended
+ * to refresh an existing lock. The locks array must contain at least
+ * a single element; the <code>ActiveLock</code> objects are then
+ * included in the lockdiscovery property of the response body as required
+ * by RFC 2518.
+ *
+ * @param locks
+ * @throws IOException
+ * @see DavConstants#PROPERTY_LOCKDISCOVERY
+ */
+ public void sendRefreshLockResponse(ActiveLock[] locks) throws IOException;
+
+ /**
+ * Generic method to return an Xml response body.
+ *
+ * @param serializable object that can be converted to the root Xml element
+ * of the document to be sent as response body.
+ * @param status Status code to be used with {@link #setStatus(int)}.
+ * @throws IOException
+ */
+ public void sendXmlResponse(XmlSerializable serializable, int status) throws IOException;
+
+ /**
+ * Generic method to return an Xml response body.
+ *
+ * @param serializable object that can be converted to the root Xml element
+ * of the document to be sent as response body.
+ * @param status Status code to be used with {@link #setStatus(int)}.
+ * @param acceptableContentCodings content codings accepted by the client
+ * @throws IOException
+ */
+ default void sendXmlResponse(XmlSerializable serializable, int status, List<String> acceptableContentCodings) throws IOException {
+ sendXmlResponse(serializable, status);
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavSession.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavSession.java
new file mode 100644
index 000000000..90cc43e0a
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavSession.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+/**
+ * <code>DavSession</code> allows to pass session information between request,
+ * response and resource(s).
+ */
+public interface DavSession {
+
+ /**
+ * Adds a reference to this <code>DavSession</code> indicating that this
+ * session must not be discarded after completion of the current request.
+ *
+ * @param reference to be added.
+ */
+ public void addReference(Object reference);
+
+ /**
+ * Releasing a reference to this <code>DavSession</code>. If no more
+ * references are present, this session may be discarded.
+ *
+ * @param reference to be removed.
+ */
+ public void removeReference(Object reference);
+
+ /**
+ * Adds a lock token to this <code>DavSession</code>.
+ *
+ * @param token
+ */
+ public void addLockToken(String token);
+
+ /**
+ * Returns the lock tokens of this <code>DavSession</code>.
+ *
+ * @return
+ */
+ public String[] getLockTokens();
+
+ /**
+ * Removes a lock token from this <code>DavSession</code>.
+ *
+ * @param token
+ */
+ public void removeLockToken(String token);
+
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavSessionProvider.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavSessionProvider.java
new file mode 100644
index 000000000..ff1f7062d
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/DavSessionProvider.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+/**
+ * <code>DavSessionProvider</code> is an interface for components that
+ * can initiate and complete {@link DavSession}s. A provider is
+ * responsible for supplying references from a {@link WebdavRequest}
+ * to a {@link DavSession} when acquired and removing the references
+ * when released.
+
+ */
+public interface DavSessionProvider {
+
+ /**
+ * Acquires a DavSession. Upon success, the WebdavRequest will
+ * reference that session.
+ *
+ * A session will not be available if an exception is thrown.
+ *
+ * @param request
+ * @return <code>true</code> if the session was attached to the request;
+ * <code>false</code> otherwise.
+ * @throws DavException if a problem occurred while obtaining the session
+ */
+ public boolean attachSession(WebdavRequest request) throws DavException;
+
+ /**
+ * Releases the reference from the request to the session.
+ *
+ * @param request
+ */
+ public void releaseSession(WebdavRequest request);
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/MultiStatus.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/MultiStatus.java
new file mode 100644
index 000000000..79536b628
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/MultiStatus.java
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
+import org.apache.jackrabbit.webdav.xml.DomUtil;
+import org.apache.jackrabbit.webdav.xml.ElementIterator;
+import org.apache.jackrabbit.webdav.xml.XmlSerializable;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * MultiStatus representing the content of a multistatus response body and
+ * allows to retrieve the Xml representation.
+ */
+public class MultiStatus implements DavConstants, XmlSerializable {
+
+ /**
+ * Map collecting the responses for this multistatus, where every href must
+ * only occur one single time.
+ */
+ private Map<String, MultiStatusResponse> responses = new LinkedHashMap<String, MultiStatusResponse>();
+
+ /**
+ * A general response description at the multistatus top level is used to
+ * provide a general message describing the overarching nature of the response.
+ * If this value is available an application may use it instead of
+ * presenting the individual response descriptions contained within the
+ * responses.
+ */
+ private String responseDescription;
+
+ /**
+ * Add response(s) to this multistatus, in order to build a multistatus for
+ * responding to a PROPFIND request.
+ *
+ * @param resource The resource to add property from
+ * @param propNameSet The requested property names of the PROPFIND request
+ * @param propFindType
+ * @param depth
+ */
+ public void addResourceProperties(DavResource resource, DavPropertyNameSet propNameSet,
+ int propFindType, int depth) {
+ addResponse(new MultiStatusResponse(resource, propNameSet, propFindType));
+ if (depth > 0 && resource.isCollection()) {
+ DavResourceIterator iter = resource.getMembers();
+ while (iter.hasNext()) {
+ addResourceProperties(iter.nextResource(), propNameSet, propFindType, depth-1);
+ }
+ }
+ }
+
+ /**
+ * Add response(s) to this multistatus, in order to build a multistatus e.g.
+ * in order to respond to a PROPFIND request. Please note, that in terms
+ * of PROPFIND, this method would correspond to a
+ * {@link DavConstants#PROPFIND_BY_PROPERTY} propfind type.
+ *
+ * @param resource The resource to add property from
+ * @param propNameSet The requested property names of the PROPFIND request
+ * @param depth
+ * @see #addResourceProperties(DavResource, DavPropertyNameSet, int, int) for
+ * the corresponding method that allows to specify the type.
+ */
+ public void addResourceProperties(DavResource resource, DavPropertyNameSet propNameSet,
+ int depth) {
+ addResourceProperties(resource, propNameSet, PROPFIND_BY_PROPERTY, depth);
+ }
+
+ /**
+ * Add response(s) to this multistatus, in order to build a multistatus
+ * as returned for COPY, MOVE, LOCK or DELETE requests resulting in an error
+ * with a resource other than the resource identified in the Request-URI.
+ *
+ * @param resource
+ * @param status
+ * @param depth
+ */
+ public void addResourceStatus(DavResource resource, int status, int depth) {
+ addResponse(new MultiStatusResponse(resource.getHref(), status));
+ if (depth > 0 && resource.isCollection()) {
+ DavResourceIterator iter = resource.getMembers();
+ while (iter.hasNext()) {
+ addResourceStatus(iter.nextResource(), status, depth-1);
+ }
+ }
+ }
+
+ /**
+ * Add a <code>MultiStatusResponse</code> element to this <code>MultiStatus</code>
+ * <p>
+ * This method is synchronized to avoid the problem described in
+ * <a href="https://issues.apache.org/jira/browse/JCR-2755">JCR-2755</a>.
+ *
+ * @param response
+ */
+ public synchronized void addResponse(MultiStatusResponse response) {
+ responses.put(response.getHref(), response);
+ }
+
+ /**
+ * Returns the multistatus responses present as array.
+ * <p>
+ * This method is synchronized to avoid the problem described in
+ * <a href="https://issues.apache.org/jira/browse/JCR-2755">JCR-2755</a>.
+ *
+ * @return array of all {@link MultiStatusResponse responses} present in this
+ * multistatus.
+ */
+ public synchronized MultiStatusResponse[] getResponses() {
+ return responses.values().toArray(new MultiStatusResponse[responses.size()]);
+ }
+
+ /**
+ * Set the response description.
+ *
+ * @param responseDescription
+ */
+ public void setResponseDescription(String responseDescription) {
+ this.responseDescription = responseDescription;
+ }
+
+ /**
+ * Returns the response description.
+ *
+ * @return responseDescription
+ */
+ public String getResponseDescription() {
+ return responseDescription;
+ }
+
+ /**
+ * Return the Xml representation of this <code>MultiStatus</code>.
+ *
+ * @return Xml document
+ * @param document
+ */
+ public Element toXml(Document document) {
+ Element multistatus = DomUtil.createElement(document, XML_MULTISTATUS, NAMESPACE);
+ for (MultiStatusResponse resp : getResponses()) {
+ multistatus.appendChild(resp.toXml(document));
+ }
+ if (responseDescription != null) {
+ Element respDesc = DomUtil.createElement(document, XML_RESPONSEDESCRIPTION, NAMESPACE, responseDescription);
+ multistatus.appendChild(respDesc);
+ }
+ return multistatus;
+ }
+
+ /**
+ * Build a <code>MultiStatus</code> from the specified xml element.
+ *
+ * @param multistatusElement
+ * @return new <code>MultiStatus</code> instance.
+ * @throws IllegalArgumentException if the given document is <code>null</code>
+ * or does not provide the required element.
+ */
+ public static MultiStatus createFromXml(Element multistatusElement) {
+ if (!DomUtil.matches(multistatusElement, XML_MULTISTATUS, NAMESPACE)) {
+ throw new IllegalArgumentException("DAV:multistatus element expected.");
+ }
+
+ MultiStatus multistatus = new MultiStatus();
+
+ ElementIterator it = DomUtil.getChildren(multistatusElement, XML_RESPONSE, NAMESPACE);
+ while (it.hasNext()) {
+ Element respElem = it.nextElement();
+ MultiStatusResponse response = MultiStatusResponse.createFromXml(respElem);
+ multistatus.addResponse(response);
+ }
+
+ // optional response description on the multistatus element
+ multistatus.setResponseDescription(DomUtil.getChildText(multistatusElement, XML_RESPONSEDESCRIPTION, NAMESPACE));
+ return multistatus;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/MultiStatusResponse.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/MultiStatusResponse.java
new file mode 100644
index 000000000..a0a5d0d7c
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/MultiStatusResponse.java
@@ -0,0 +1,486 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import org.apache.jackrabbit.webdav.property.DavProperty;
+import org.apache.jackrabbit.webdav.property.DavPropertyName;
+import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
+import org.apache.jackrabbit.webdav.property.DavPropertySet;
+import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
+import org.apache.jackrabbit.webdav.property.PropContainer;
+import org.apache.jackrabbit.webdav.xml.DomUtil;
+import org.apache.jackrabbit.webdav.xml.ElementIterator;
+import org.apache.jackrabbit.webdav.xml.XmlSerializable;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * <code>MultiStatusResponse</code> represents the DAV:multistatus element defined
+ * by RFC 2518:
+ * <pre>
+ * <!ELEMENT response (href, ((href*, status)|(propstat+)), responsedescription?) >
+ * <!ELEMENT status (#PCDATA) >
+ * <!ELEMENT propstat (prop, status, responsedescription?) >
+ * <!ELEMENT responsedescription (#PCDATA) >
+ * <!ELEMENT prop ANY >
+ * </pre>
+ */
+public class MultiStatusResponse implements XmlSerializable, DavConstants {
+
+ private static final int TYPE_PROPSTAT = 0;
+ private static final int TYPE_HREFSTATUS = 1;
+
+ /**
+ * The type of MultiStatusResponse
+ */
+ private final int type;
+
+ /**
+ * The content the 'href' element for this response
+ */
+ private final String href;
+
+ /**
+ * An optional response description.
+ */
+ private final String responseDescription;
+
+ /**
+ * Type of MultiStatus response: Href + Status
+ */
+ private Status status;
+
+ /**
+ * Type of MultiStatus response: PropStat Hashmap containing all status
+ */
+ private HashMap<Integer, PropContainer> statusMap = new HashMap<Integer, PropContainer>();
+
+ private MultiStatusResponse(String href, String responseDescription, int type) {
+ if (!isValidHref(href)) {
+ throw new IllegalArgumentException("Invalid href ('" + href + "')");
+ }
+ this.href = href;
+ this.responseDescription = responseDescription;
+ this.type = type;
+ }
+
+ /**
+ * Constructs an WebDAV multistatus response
+ *
+ * @param href
+ * @param status
+ * @param responseDescription
+ */
+ public MultiStatusResponse(String href, Status status, String responseDescription) {
+ this(href, responseDescription, TYPE_HREFSTATUS);
+ if (status == null) {
+ throw new IllegalArgumentException("Status must not be null in case of a multistatus reponse that consists of href + status only.");
+ }
+ this.status = status;
+ }
+
+ /**
+ * Constructs an WebDAV multistatus response for a given resource. This
+ * would be used by COPY, MOVE, DELETE, LOCK that require a multistatus in
+ * case of error with a resource other than the resource identified in the
+ * Request-URI.<br>
+ * The response description is set to <code>null</code>.
+ *
+ * @param href
+ * @param statusCode
+ */
+ public MultiStatusResponse(String href, int statusCode) {
+ this(href, statusCode, null);
+ }
+
+ /**
+ * Constructs an WebDAV multistatus response for a given resource. This
+ * would be used by COPY, MOVE, DELETE, LOCK that require a multistatus in
+ * case of error with a resource other than the resource identified in the
+ * Request-URI.
+ *
+ * @param href
+ * @param statusCode
+ * @param responseDescription
+ */
+ public MultiStatusResponse(String href, int statusCode, String responseDescription) {
+ this(href, new Status(statusCode), responseDescription);
+ }
+
+ /**
+ * Constructs an empty WebDAV multistatus response of type 'PropStat'
+ */
+ public MultiStatusResponse(String href, String responseDescription) {
+ this(href, responseDescription, TYPE_PROPSTAT);
+ }
+
+ /**
+ * Constructs a WebDAV multistatus response and retrieves the resource
+ * properties according to the given <code>DavPropertyNameSet</code>.
+ *
+ * @param resource
+ * @param propNameSet
+ */
+ public MultiStatusResponse(DavResource resource, DavPropertyNameSet propNameSet) {
+ this(resource, propNameSet, PROPFIND_BY_PROPERTY);
+ }
+
+ /**
+ * Constructs a WebDAV multistatus response and retrieves the resource
+ * properties according to the given <code>DavPropertyNameSet</code>. It
+ * adds all known property to the '200' set, while unknown properties are
+ * added to the '404' set.
+ * <p>
+ * Note, that the set of property names is ignored in case of a {@link
+ * #PROPFIND_ALL_PROP} and {@link #PROPFIND_PROPERTY_NAMES} propFindType.
+ *
+ * @param resource The resource to retrieve the property from
+ * @param propNameSet The property name set as obtained from the request
+ * body.
+ * @param propFindType any of the following values: {@link
+ * #PROPFIND_ALL_PROP}, {@link #PROPFIND_BY_PROPERTY}, {@link
+ * #PROPFIND_PROPERTY_NAMES}, {@link #PROPFIND_ALL_PROP_INCLUDE}
+ */
+ public MultiStatusResponse(
+ DavResource resource, DavPropertyNameSet propNameSet,
+ int propFindType) {
+ this(resource.getHref(), null, TYPE_PROPSTAT);
+
+ if (propFindType == PROPFIND_PROPERTY_NAMES) {
+ // only property names requested
+ PropContainer status200 = getPropContainer(DavServletResponse.SC_OK, true);
+ for (DavPropertyName propName : resource.getPropertyNames()) {
+ status200.addContent(propName);
+ }
+ } else {
+ // all or a specified set of property and their values requested.
+ PropContainer status200 = getPropContainer(DavServletResponse.SC_OK, false);
+
+ // Collection of missing property names for 404 responses
+ Set<DavPropertyName> missing = new HashSet<DavPropertyName>(propNameSet.getContent());
+
+ // Add requested properties or all non-protected properties,
+ // or non-protected properties plus requested properties (allprop/include)
+ if (propFindType == PROPFIND_BY_PROPERTY) {
+ // add explicitly requested properties (proptected or non-protected)
+ for (DavPropertyName propName : propNameSet) {
+ DavProperty<?> prop = resource.getProperty(propName);
+ if (prop != null) {
+ status200.addContent(prop);
+ missing.remove(propName);
+ }
+ }
+ } else {
+ // add all non-protected properties
+ for (DavProperty<?> property : resource.getProperties()) {
+ boolean allDeadPlusRfc4918LiveProperties =
+ propFindType == PROPFIND_ALL_PROP
+ || propFindType == PROPFIND_ALL_PROP_INCLUDE;
+ boolean wasRequested = missing.remove(property.getName());
+
+ if ((allDeadPlusRfc4918LiveProperties
+ && !property.isInvisibleInAllprop())
+ || wasRequested) {
+ status200.addContent(property);
+ }
+ }
+
+ // try if missing properties specified in the include section
+ // can be obtained using resource.getProperty
+ if (propFindType == PROPFIND_ALL_PROP_INCLUDE && !missing.isEmpty()) {
+ for (DavPropertyName propName : new HashSet<DavPropertyName>(missing)) {
+ DavProperty<?> prop = resource.getProperty(propName);
+ if (prop != null) {
+ status200.addContent(prop);
+ missing.remove(propName);
+ }
+ }
+ }
+ }
+
+ if (!missing.isEmpty() && propFindType != PROPFIND_ALL_PROP) {
+ PropContainer status404 = getPropContainer(DavServletResponse.SC_NOT_FOUND, true);
+ for (DavPropertyName propName : missing) {
+ status404.addContent(propName);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the href
+ *
+ * @return href
+ * @see MultiStatusResponse#getHref()
+ */
+ public String getHref() {
+ return href;
+ }
+
+ /**
+ * @return responseDescription
+ * @see MultiStatusResponse#getResponseDescription()
+ */
+ public String getResponseDescription() {
+ return responseDescription;
+ }
+
+ /**
+ * Return an array listing all 'status' available is this response object.
+ * Note, that a the array contains a single element if this
+ * <code>MultiStatusResponse</code> defines an response consisting of
+ * href and status elements.
+ *
+ * @return
+ */
+ public Status[] getStatus() {
+ Status[] sts;
+ if (type == TYPE_PROPSTAT) {
+ sts = new Status[statusMap.size()];
+ Iterator<Integer> iter = statusMap.keySet().iterator();
+ for (int i = 0; iter.hasNext(); i++) {
+ Integer statusKey = iter.next();
+ sts[i] = new Status(statusKey);
+ }
+ } else {
+ sts = new Status[] {status};
+ }
+ return sts;
+ }
+
+ /**
+ * @return {@code true} if the response is of type "propstat" (containing information about individual properties)
+ */
+ public boolean isPropStat() {
+ return this.type == TYPE_PROPSTAT;
+ }
+
+ /**
+ * @param document
+ * @see org.apache.jackrabbit.webdav.xml.XmlSerializable#toXml(org.w3c.dom.Document)
+ */
+ public Element toXml(Document document) {
+ Element response = DomUtil.createElement(document, XML_RESPONSE, NAMESPACE);
+ // add '<href>'
+ response.appendChild(DomUtil.hrefToXml(getHref(), document));
+ if (type == TYPE_PROPSTAT) {
+ // add '<propstat>' elements
+ for (Integer statusKey : statusMap.keySet()) {
+ Status st = new Status(statusKey);
+ PropContainer propCont = statusMap.get(statusKey);
+ if (!propCont.isEmpty()) {
+ Element propstat = DomUtil.createElement(document, XML_PROPSTAT, NAMESPACE);
+ propstat.appendChild(propCont.toXml(document));
+ propstat.appendChild(st.toXml(document));
+ response.appendChild(propstat);
+ }
+ }
+ } else {
+ // add a single '<status>' element
+ // NOTE: a href+status response cannot be created with 'null' status
+ response.appendChild(status.toXml(document));
+ }
+ // add the optional '<responsedescription>' element
+ String description = getResponseDescription();
+ if (description != null) {
+ Element desc = DomUtil.createElement(document, XML_RESPONSEDESCRIPTION, NAMESPACE);
+ DomUtil.setText(desc, description);
+ response.appendChild(desc);
+ }
+ return response;
+ }
+ //----------------------------------------------< type specific methods >---
+ /**
+ * Adds a property to this response '200' propstat set.
+ *
+ * @param property the property to add
+ */
+ public void add(DavProperty<?> property) {
+ checkType(TYPE_PROPSTAT);
+ PropContainer status200 = getPropContainer(DavServletResponse.SC_OK, false);
+ status200.addContent(property);
+ }
+
+ /**
+ * Adds a property name to this response '200' propstat set.
+ *
+ * @param propertyName the property name to add
+ */
+ public void add(DavPropertyName propertyName) {
+ checkType(TYPE_PROPSTAT);
+ PropContainer status200 = getPropContainer(DavServletResponse.SC_OK, true);
+ status200.addContent(propertyName);
+ }
+
+ /**
+ * Adds a property to this response
+ *
+ * @param property the property to add
+ * @param status the status of the response set to select
+ */
+ public void add(DavProperty<?> property, int status) {
+ checkType(TYPE_PROPSTAT);
+ PropContainer propCont = getPropContainer(status, false);
+ propCont.addContent(property);
+ }
+
+ /**
+ * Adds a property name to this response
+ *
+ * @param propertyName the property name to add
+ * @param status the status of the response set to select
+ */
+ public void add(DavPropertyName propertyName, int status) {
+ checkType(TYPE_PROPSTAT);
+ PropContainer propCont = getPropContainer(status, true);
+ propCont.addContent(propertyName);
+ }
+
+ /**
+ * @param status
+ * @return
+ */
+ private PropContainer getPropContainer(int status, boolean forNames) {
+ PropContainer propContainer = statusMap.get(status);
+ if (propContainer == null) {
+ if (forNames) {
+ propContainer = new DavPropertyNameSet();
+ } else {
+ propContainer = new DavPropertySet();
+ }
+ statusMap.put(status, propContainer);
+ }
+ return propContainer;
+ }
+
+ private void checkType(int type) {
+ if (this.type != type) {
+ throw new IllegalStateException("The given MultiStatusResponse is not of the required type.");
+ }
+ }
+
+ /**
+ * Get properties present in this response for the given status code. In
+ * case this MultiStatusResponse does not represent a 'propstat' response,
+ * always an empty {@link DavPropertySet} will be returned.
+ *
+ * @param status
+ * @return property set
+ */
+ public DavPropertySet getProperties(int status) {
+ if (statusMap.containsKey(status)) {
+ PropContainer mapEntry = statusMap.get(status);
+ if (mapEntry != null && mapEntry instanceof DavPropertySet) {
+ return (DavPropertySet) mapEntry;
+ }
+ }
+ return new DavPropertySet();
+ }
+
+ /**
+ * Get property names present in this response for the given status code. In
+ * case this MultiStatusResponse does not represent a 'propstat' response,
+ * always an empty {@link DavPropertyNameSet} will be returned.
+ *
+ * @param status
+ * @return property names
+ */
+ public DavPropertyNameSet getPropertyNames(int status) {
+ if (statusMap.containsKey(status)) {
+ PropContainer mapEntry = statusMap.get(status);
+ if (mapEntry != null) {
+ if (mapEntry instanceof DavPropertySet) {
+ DavPropertyNameSet set = new DavPropertyNameSet();
+ for (DavPropertyName name : ((DavPropertySet) mapEntry).getPropertyNames()) {
+ set.add(name);
+ }
+ return set;
+ } else {
+ // is already a DavPropertyNameSet
+ return (DavPropertyNameSet) mapEntry;
+ }
+ }
+ }
+ return new DavPropertyNameSet();
+ }
+
+ /**
+ * Build a new response object from the given xml element.
+ *
+ * @param responseElement
+ * @return new <code>MultiStatusResponse</code> instance
+ * @throws IllegalArgumentException if the specified element is
+ * <code>null</code> or not a DAV:response element or if the mandatory
+ * DAV:href child is missing.
+ */
+ public static MultiStatusResponse createFromXml(Element responseElement) {
+ if (!DomUtil.matches(responseElement, XML_RESPONSE, NAMESPACE)) {
+ throw new IllegalArgumentException("DAV:response element required.");
+ }
+ String href = DomUtil.getChildTextTrim(responseElement, XML_HREF, NAMESPACE);
+ if (href == null) {
+ throw new IllegalArgumentException("DAV:response element must contain a DAV:href element expected.");
+ }
+ String statusLine = DomUtil.getChildText(responseElement, XML_STATUS, NAMESPACE);
+ String responseDescription = DomUtil.getChildText(responseElement, XML_RESPONSEDESCRIPTION, NAMESPACE);
+
+ MultiStatusResponse response;
+ if (statusLine != null) {
+ Status status = Status.parse(statusLine);
+ response = new MultiStatusResponse(href, status, responseDescription);
+ } else {
+ response = new MultiStatusResponse(href, responseDescription, TYPE_PROPSTAT);
+ // read propstat elements
+ ElementIterator it = DomUtil.getChildren(responseElement, XML_PROPSTAT, NAMESPACE);
+ while (it.hasNext()) {
+ Element propstat = it.nextElement();
+ String propstatus = DomUtil.getChildText(propstat, XML_STATUS, NAMESPACE);
+ Element prop = DomUtil.getChildElement(propstat, XML_PROP, NAMESPACE);
+ if (propstatus != null && prop != null) {
+ int statusCode = Status.parse(propstatus).getStatusCode();
+ ElementIterator propIt = DomUtil.getChildren(prop);
+ while (propIt.hasNext()) {
+ Element el = propIt.nextElement();
+ /*
+ always build dav property from the given element, since
+ distinction between prop-names and properties not having
+ a value is not possible.
+ retrieval of the set of 'property names' is possible from
+ the given prop-set by calling DavPropertySet#getPropertyNameSet()
+ */
+ DavProperty<?> property = DefaultDavProperty.createFromXml(el);
+ response.add(property, statusCode);
+ }
+ }
+ }
+ }
+ return response;
+ }
+
+ /**
+ * @param href
+ * @return false if the given href is <code>null</code> or empty string.
+ */
+ private static boolean isValidHref(String href) {
+ return href != null && !"".equals(href);
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/Status.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/Status.java
new file mode 100644
index 000000000..4357416cc
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/Status.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import java.util.Locale;
+
+import org.apache.jackrabbit.webdav.xml.DomUtil;
+import org.apache.jackrabbit.webdav.xml.XmlSerializable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * <code>Status</code> encapsulating the 'status' present in multistatus
+ * responses.
+ */
+public class Status implements DavConstants, XmlSerializable{
+
+ private static Logger log = LoggerFactory.getLogger(Status.class);
+
+ private final String version;
+ private final int code;
+ private final String phrase;
+
+ public Status(int code) {
+ version = "HTTP/1.1";
+ this.code = code;
+ phrase = DavException.getStatusPhrase(code);
+ }
+
+ public Status(String version, int code, String phrase) {
+ this.version = version;
+ this.code = code;
+ this.phrase = phrase;
+ }
+
+ public int getStatusCode() {
+ return code;
+ }
+
+ /**
+ * @see XmlSerializable#toXml(Document)
+ */
+ public Element toXml(Document document) {
+ String statusLine = version + " " + code + " " + phrase;
+ Element e = DomUtil.createElement(document, XML_STATUS, NAMESPACE);
+ DomUtil.setText(e, statusLine);
+ return e;
+ }
+
+ /**
+ * Parse the given status line and return a new <code>Status</code> object.
+ *
+ * @param statusLine
+ * @return a new <code>Status</code>
+ */
+ public static Status parse(String statusLine) {
+ if (statusLine == null) {
+ throw new IllegalArgumentException("Unable to parse status line from null xml element.");
+ }
+ Status status;
+
+ // code copied from org.apache.commons.httpclient.StatusLine
+ int length = statusLine.length();
+ int at = 0;
+ int start = 0;
+ try {
+ while (Character.isWhitespace(statusLine.charAt(at))) {
+ ++at;
+ ++start;
+ }
+ if (!"HTTP".equals(statusLine.substring(at, at += 4))) {
+ log.warn("Status-Line '" + statusLine + "' does not start with HTTP");
+ }
+ //handle the HTTP-Version
+ at = statusLine.indexOf(' ', at);
+ if (at <= 0) {
+ log.warn("Unable to parse HTTP-Version from the status line: '" + statusLine + "'");
+ }
+ String version = (statusLine.substring(start, at)).toUpperCase(Locale.ROOT);
+ //advance through spaces
+ while (statusLine.charAt(at) == ' ') {
+ at++;
+ }
+ //handle the Status-Code
+ int code;
+ int to = statusLine.indexOf(' ', at);
+ if (to < 0) {
+ to = length;
+ }
+ try {
+ code = Integer.parseInt(statusLine.substring(at, to));
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Unable to parse status code from status line: '" + statusLine + "'");
+ }
+ //handle the Reason-Phrase
+ String phrase = "";
+ at = to + 1;
+ if (at < length) {
+ phrase = statusLine.substring(at).trim();
+ }
+
+ status = new Status(version, code, phrase);
+
+ } catch (StringIndexOutOfBoundsException e) {
+ throw new IllegalArgumentException("Status-Line '" + statusLine + "' is not valid");
+ }
+ return status;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/WebdavRequest.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/WebdavRequest.java
new file mode 100644
index 000000000..09aa79f88
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/WebdavRequest.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import org.apache.jackrabbit.webdav.observation.ObservationDavServletRequest;
+import org.apache.jackrabbit.webdav.ordering.OrderingDavServletRequest;
+import org.apache.jackrabbit.webdav.transaction.TransactionDavServletRequest;
+import org.apache.jackrabbit.webdav.version.DeltaVServletRequest;
+import org.apache.jackrabbit.webdav.bind.BindServletRequest;
+
+/**
+ * The empty <code>WebdavRequest</code> interface collects the functionality
+ * defined by {@link org.apache.jackrabbit.webdav.DavServletRequest} encapsulating
+ * the core Webdav specification (RFC 2518) as well as the various extensions
+ * used for observation and transaction support, ordering of collections, search
+ * and versioning.
+ */
+public interface WebdavRequest extends DavServletRequest,
+ ObservationDavServletRequest, OrderingDavServletRequest,
+ TransactionDavServletRequest, DeltaVServletRequest,
+ BindServletRequest {
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/WebdavRequestContext.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/WebdavRequestContext.java
new file mode 100644
index 000000000..c1de4183c
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/WebdavRequestContext.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+/**
+ * Interface providing the minimum WebDAV request information associated with the current thread of execution.
+ */
+public interface WebdavRequestContext {
+
+ /**
+ * Return the current {@link WebdavRequest} instance associated with the current thread of execution.
+ * @return the current {@link WebdavRequest} instance associated with the current thread of execution
+ */
+ public WebdavRequest getRequest();
+
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/WebdavRequestImpl.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/WebdavRequestImpl.java
new file mode 100644
index 000000000..493531394
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/WebdavRequestImpl.java
@@ -0,0 +1,1324 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.InflaterInputStream;
+
+import jakarta.servlet.AsyncContext;
+import jakarta.servlet.DispatcherType;
+import jakarta.servlet.ReadListener;
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.ServletConnection;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletInputStream;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
+import jakarta.servlet.http.HttpUpgradeHandler;
+import jakarta.servlet.http.Part;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.jackrabbit.webdav.bind.BindInfo;
+import org.apache.jackrabbit.webdav.bind.RebindInfo;
+import org.apache.jackrabbit.webdav.bind.UnbindInfo;
+import org.apache.jackrabbit.webdav.header.CodedUrlHeader;
+import org.apache.jackrabbit.webdav.header.DepthHeader;
+import org.apache.jackrabbit.webdav.header.IfHeader;
+import org.apache.jackrabbit.webdav.header.LabelHeader;
+import org.apache.jackrabbit.webdav.header.OverwriteHeader;
+import org.apache.jackrabbit.webdav.header.PollTimeoutHeader;
+import org.apache.jackrabbit.webdav.header.TimeoutHeader;
+import org.apache.jackrabbit.webdav.lock.ActiveLock;
+import org.apache.jackrabbit.webdav.lock.LockInfo;
+import org.apache.jackrabbit.webdav.lock.Scope;
+import org.apache.jackrabbit.webdav.lock.Type;
+import org.apache.jackrabbit.webdav.observation.ObservationConstants;
+import org.apache.jackrabbit.webdav.observation.SubscriptionInfo;
+import org.apache.jackrabbit.webdav.ordering.OrderPatch;
+import org.apache.jackrabbit.webdav.ordering.OrderingConstants;
+import org.apache.jackrabbit.webdav.ordering.Position;
+import org.apache.jackrabbit.webdav.property.DavProperty;
+import org.apache.jackrabbit.webdav.property.DavPropertyName;
+import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
+import org.apache.jackrabbit.webdav.property.DavPropertySet;
+import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
+import org.apache.jackrabbit.webdav.property.PropEntry;
+import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet;
+import org.apache.jackrabbit.webdav.transaction.TransactionConstants;
+import org.apache.jackrabbit.webdav.transaction.TransactionInfo;
+import org.apache.jackrabbit.webdav.version.LabelInfo;
+import org.apache.jackrabbit.webdav.version.MergeInfo;
+import org.apache.jackrabbit.webdav.version.OptionsInfo;
+import org.apache.jackrabbit.webdav.version.UpdateInfo;
+import org.apache.jackrabbit.webdav.version.report.ReportInfo;
+import org.apache.jackrabbit.webdav.xml.DomUtil;
+import org.apache.jackrabbit.webdav.xml.ElementIterator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+/**
+ * <code>WebdavRequestImpl</code>...
+ */
+public class WebdavRequestImpl implements WebdavRequest, DavConstants, ContentCodingAwareRequest {
+
+ private static Logger log = LoggerFactory.getLogger(WebdavRequestImpl.class);
+
+ private final HttpServletRequest httpRequest;
+ private final DavLocatorFactory factory;
+ private final IfHeader ifHeader;
+ private final String hrefPrefix;
+
+ private DavSession session;
+
+ private int propfindType = PROPFIND_ALL_PROP;
+ private DavPropertyNameSet propfindProps;
+ private DavPropertySet proppatchSet;
+ private List<PropEntry> proppatchList;
+
+ /**
+ * Creates a new <code>DavServletRequest</code> with the given parameters.
+ */
+ public WebdavRequestImpl(HttpServletRequest httpRequest, DavLocatorFactory factory) {
+ this(httpRequest, factory, true);
+ }
+
+ /**
+ * Creates a new <code>DavServletRequest</code> with the given parameters.
+ *
+ * @param httpRequest
+ * @param factory
+ * @param createAbsoluteURI defines if we must create a absolute URI. if false a absolute path will be created
+ */
+ public WebdavRequestImpl(HttpServletRequest httpRequest, DavLocatorFactory factory, boolean createAbsoluteURI) {
+ this.httpRequest = httpRequest;
+ this.factory = factory;
+ this.ifHeader = new IfHeader(httpRequest);
+
+ String host = getHeader("Host");
+ String scheme = getScheme();
+ String uriPrefix = scheme + "://" + host + getContextPath();
+ this.hrefPrefix = createAbsoluteURI ? uriPrefix : getContextPath();
+ }
+
+ /**
+ * Sets the session field and adds all lock tokens present with either the
+ * Lock-Token header or the If header to the given session object.
+ *
+ * @param session
+ * @see DavServletRequest#setDavSession(DavSession)
+ */
+ public void setDavSession(DavSession session) {
+ this.session = session;
+ // set lock-tokens from header to the current session
+ if (session != null) {
+ String lt = getLockToken();
+ if (lt != null) {
+ session.addLockToken(lt);
+ }
+ // add all token present in the the If header to the session as well.
+ Iterator<String> it = ifHeader.getAllTokens();
+ while (it.hasNext()) {
+ String ifHeaderToken = it.next();
+ session.addLockToken(ifHeaderToken);
+ }
+ }
+ }
+
+ /**
+ * @see DavServletRequest#getDavSession()
+ */
+ public DavSession getDavSession() {
+ return session;
+ }
+
+ /**
+ * Return a <code>DavResourceLocator</code> representing the request handle.
+ *
+ * @return locator of the requested resource
+ * @see DavServletRequest#getRequestLocator()
+ */
+ public DavResourceLocator getRequestLocator() {
+ String path = getRequestURI();
+ String ctx = getContextPath();
+ if (path.startsWith(ctx)) {
+ path = path.substring(ctx.length());
+ }
+ return factory.createResourceLocator(hrefPrefix, path);
+ }
+
+ /**
+ * Parse the destination header field and return the path of the destination
+ * resource.
+ *
+ * @return path of the destination resource.
+ * @throws DavException
+ * @see #HEADER_DESTINATION
+ * @see DavServletRequest#getDestinationLocator
+ */
+ public DavResourceLocator getDestinationLocator() throws DavException {
+ return getHrefLocator(httpRequest.getHeader(HEADER_DESTINATION), true);
+ }
+
+ private DavResourceLocator getHrefLocator(String href, boolean forDestination) throws DavException {
+ String ref = href;
+ if (ref != null) {
+ //href should be a Simple-ref production as defined in RFC4918, so it is either an absolute URI
+ //or an absolute path
+ try {
+ URI uri = new URI(ref).normalize(); // normalize path (see JCR-3174)
+ String auth = uri.getAuthority();
+ ref = uri.getRawPath();
+ if (auth == null) {
+ //verify that href is an absolute path
+ if (ref.startsWith("//") || !ref.startsWith("/")) {
+ log.warn("expected absolute path but found " + ref);
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ } else if (!auth.equals(httpRequest.getHeader("Host"))) {
+ //this looks like an unsupported cross-server operation, but of course a reverse-proxy
+ //might have rewritten the Host header. Since we can't find out, we have to reject anyway.
+ //Better use absolute paths in DAV:href elements!
+ throw new DavException(DavServletResponse.SC_FORBIDDEN);
+ }
+ } catch (URISyntaxException e) {
+ log.warn("malformed uri: " + href, e);
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ // cut off the context path
+ String contextPath = httpRequest.getContextPath();
+ if (ref.startsWith(contextPath)) {
+ ref = ref.substring(contextPath.length());
+ } else {
+ //absolute path has to start with context path
+ throw new DavException(DavServletResponse.SC_FORBIDDEN);
+ }
+ }
+ if (factory instanceof AbstractLocatorFactory) {
+ return ((AbstractLocatorFactory)factory).createResourceLocator(hrefPrefix, ref, forDestination);
+ }
+ else {
+ return factory.createResourceLocator(hrefPrefix, ref);
+ }
+ }
+
+ /**
+ * Parse a href and return the path of the resource.
+ *
+ * @return path of the resource identified by the href.
+ * @see org.apache.jackrabbit.webdav.bind.BindServletRequest#getHrefLocator
+ */
+ public DavResourceLocator getHrefLocator(String href) throws DavException {
+ return getHrefLocator(href, false);
+ }
+
+ /**
+ * Returns the path of the member resource of the request resource which is identified by the segment parameter.
+ *
+ * @return path of internal member resource.
+ */
+ public DavResourceLocator getMemberLocator(String segment) {
+ String path = (this.getRequestLocator().getHref(true) + segment).substring(hrefPrefix.length());
+ return factory.createResourceLocator(hrefPrefix, path);
+ }
+
+ /**
+ * Return true if the overwrite header does not inhibit overwriting.
+ *
+ * @return true if the overwrite header requests 'overwriting'
+ * @see #HEADER_OVERWRITE
+ * @see DavServletRequest#isOverwrite()
+ */
+ public boolean isOverwrite() {
+ return new OverwriteHeader(httpRequest).isOverwrite();
+ }
+
+ /**
+ * @see DavServletRequest#getDepth(int)
+ */
+ public int getDepth(int defaultValue) {
+ return DepthHeader.parse(httpRequest, defaultValue).getDepth();
+ }
+
+ /**
+ * @see DavServletRequest#getDepth()
+ */
+ public int getDepth() {
+ return getDepth(DEPTH_INFINITY);
+ }
+
+ /**
+ * Parse the Timeout header and return a long representing the value.
+ * {@link #UNDEFINED_TIMEOUT} is used as default value if no header
+ * is available or if the parsing fails.
+ *
+ * @return milliseconds indicating length of the timeout.
+ * @see DavServletRequest#getTimeout()
+ * @see TimeoutHeader#parse(jakarta.servlet.http.HttpServletRequest, long)
+ */
+ public long getTimeout() {
+ return TimeoutHeader.parse(httpRequest, UNDEFINED_TIMEOUT).getTimeout();
+ }
+
+ /**
+ * Retrieve the lock token from the 'Lock-Token' header.
+ *
+ * @return String representing the lock token sent in the Lock-Token header.
+ * @throws IllegalArgumentException If the value has not the correct format.
+ * @see #HEADER_LOCK_TOKEN
+ * @see DavServletRequest#getLockToken()
+ */
+ public String getLockToken() {
+ return CodedUrlHeader.parse(httpRequest, HEADER_LOCK_TOKEN).getCodedUrl();
+ }
+
+ /**
+ * @see DavServletRequest#getRequestDocument()
+ */
+ public Document getRequestDocument() throws DavException {
+ Document requestDocument = null;
+ /*
+ Don't attempt to parse the body if the content length header is 0.
+ NOTE: a value of -1 indicates that the length is unknown, thus we have
+ to parse the body. Note that http1.1 request using chunked transfer
+ coding will therefore not be detected here.
+ */
+ if (httpRequest.getContentLength() == 0) {
+ return requestDocument;
+ }
+ // try to parse the request body
+ try {
+ InputStream in = getDecodedInputStream();
+ if (in != null) {
+ // use a buffered input stream to find out whether there actually
+ // is a request body
+ InputStream bin = new BufferedInputStream(in);
+ bin.mark(1);
+ boolean isEmpty = -1 == bin.read();
+ bin.reset();
+ if (!isEmpty) {
+ requestDocument = DomUtil.parseDocument(bin);
+ }
+ }
+ } catch (IOException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("Unable to build an XML Document from the request body: " + e.getMessage());
+ }
+ Throwable cause = e.getCause();
+ throw (cause instanceof DavException) ? (DavException) cause : new DavException(DavServletResponse.SC_BAD_REQUEST);
+ } catch (ParserConfigurationException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("Unable to build an XML Document from the request body: " + e.getMessage());
+ }
+ throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR);
+ } catch (SAXException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("Unable to build an XML Document from the request body: " + e.getMessage());
+ }
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ return requestDocument;
+ }
+
+ /**
+ * Returns the type of PROPFIND as indicated by the request body.
+ *
+ * @return type of the PROPFIND request. Default value is {@link #PROPFIND_ALL_PROP allprops}
+ * @see DavServletRequest#getPropFindType()
+ */
+ public int getPropFindType() throws DavException {
+ if (propfindProps == null) {
+ parsePropFindRequest();
+ }
+ return propfindType;
+ }
+
+ /**
+ * Returns the set of properties requested by the PROPFIND body or an
+ * empty set if the {@link #getPropFindType type} is either 'allprop' or
+ * 'propname'.
+ *
+ * @return set of properties requested by the PROPFIND body or an empty set.
+ * @see DavServletRequest#getPropFindProperties()
+ */
+ public DavPropertyNameSet getPropFindProperties() throws DavException {
+ if (propfindProps == null) {
+ parsePropFindRequest();
+ }
+ return propfindProps;
+ }
+
+ private InputStream getDecodedInputStream() throws IOException {
+ List<String> contentCodings = getRequestContentCodings();
+ int len = contentCodings.size();
+
+ log.trace("content codings: " + contentCodings);
+ InputStream result = httpRequest.getInputStream();
+
+ for (int i = 1; i <= len; i++) {
+ String s = contentCodings.get(len - i);
+ log.trace("decoding: " + s);
+ if ("gzip".equals(s)) {
+ result = new GZIPInputStream(result);
+ } else if ("deflate".equals(s)) {
+ result = new InflaterInputStream(result);
+ } else {
+ String message = "Unsupported content coding: " + s;
+ try {
+ Element condition = DomUtil.createElement(DomUtil.createDocument(), PRECONDITION_SUPPORTED);
+ throw new IOException(
+ new DavException(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, message, null, condition));
+ } catch (ParserConfigurationException ex) {
+ throw new IOException(message);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private List<String> requestContentCodings = null;
+
+ @Override
+ public List<String> getRequestContentCodings() {
+ if (requestContentCodings == null) {
+ requestContentCodings = AbstractWebdavServlet.getContentCodings(httpRequest);
+ }
+
+ return requestContentCodings;
+ }
+
+ @Override
+ public String getAcceptableCodings() {
+ return "deflate, gzip";
+ }
+
+ /**
+ * Parse the propfind request body in order to determine the type of the propfind
+ * and the set of requested property.
+ * NOTE: An empty 'propfind' request body will be treated as request for all
+ * property according to the specification.
+ */
+ private void parsePropFindRequest() throws DavException {
+ propfindProps = new DavPropertyNameSet();
+ Document requestDocument = getRequestDocument();
+ // propfind httpRequest with empty body >> retrieve all property
+ if (requestDocument == null) {
+ return;
+ }
+
+ // propfind httpRequest with invalid body
+ Element root = requestDocument.getDocumentElement();
+ if (!XML_PROPFIND.equals(root.getLocalName())) {
+ log.info("PropFind-Request has no <propfind> tag.");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST, "PropFind-Request has no <propfind> tag.");
+ }
+
+ DavPropertyNameSet include = null;
+
+ ElementIterator it = DomUtil.getChildren(root);
+ int propfindTypeFound = 0;
+
+ while (it.hasNext()) {
+ Element child = it.nextElement();
+ String nodeName = child.getLocalName();
+ if (NAMESPACE.getURI().equals(child.getNamespaceURI())) {
+ if (XML_PROP.equals(nodeName)) {
+ propfindType = PROPFIND_BY_PROPERTY;
+ propfindProps = new DavPropertyNameSet(child);
+ propfindTypeFound += 1;
+ }
+ else if (XML_PROPNAME.equals(nodeName)) {
+ propfindType = PROPFIND_PROPERTY_NAMES;
+ propfindTypeFound += 1;
+ }
+ else if (XML_ALLPROP.equals(nodeName)) {
+ propfindType = PROPFIND_ALL_PROP;
+ propfindTypeFound += 1;
+ }
+ else if (XML_INCLUDE.equals(nodeName)) {
+ include = new DavPropertyNameSet();
+ ElementIterator pit = DomUtil.getChildren(child);
+ while (pit.hasNext()) {
+ include.add(DavPropertyName.createFromXml(pit.nextElement()));
+ }
+ }
+ }
+ }
+
+ if (propfindTypeFound > 1) {
+ log.info("Multiple top-level propfind instructions");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST, "Multiple top-level propfind instructions");
+ }
+
+ if (include != null) {
+ if (propfindType == PROPFIND_ALL_PROP) {
+ // special case: allprop with include extension
+ propfindType = PROPFIND_ALL_PROP_INCLUDE;
+ propfindProps = include;
+ }
+ else {
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST, "<include> goes only with <allprop>");
+
+ }
+ }
+ }
+
+ /**
+ * Return a {@link List} of property change operations. Each entry
+ * is either of type {@link DavPropertyName}, indicating a <remove>
+ * operation, or of type {@link DavProperty}, indicating a <set>
+ * operation. Note that ordering is significant here.
+ *
+ * @return the list of change operations entries in the PROPPATCH request body
+ * @see DavServletRequest#getPropPatchChangeList()
+ */
+ public List<? extends PropEntry> getPropPatchChangeList() throws DavException {
+ if (proppatchList == null) {
+ parsePropPatchRequest();
+ }
+ return proppatchList;
+ }
+
+ /**
+ * Parse the PROPPATCH request body.
+ */
+ private void parsePropPatchRequest() throws DavException {
+
+ proppatchSet = new DavPropertySet();
+ proppatchList = new ArrayList<PropEntry>();
+
+ Document requestDocument = getRequestDocument();
+
+ if (requestDocument == null) {
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST, "Invalid request body.");
+ }
+
+ Element root = requestDocument.getDocumentElement();
+ if (!DomUtil.matches(root, XML_PROPERTYUPDATE, NAMESPACE)) {
+ log.warn("PropPatch-Request has no <DAV:propertyupdate> tag.");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST, "PropPatch-Request has no <propertyupdate> tag.");
+ }
+
+ ElementIterator it = DomUtil.getChildren(root);
+ while (it.hasNext()) {
+ Element el = it.nextElement();
+ if (DomUtil.matches(el, XML_SET, NAMESPACE)) {
+ Element propEl = DomUtil.getChildElement(el, XML_PROP, NAMESPACE);
+ if (propEl != null) {
+ ElementIterator properties = DomUtil.getChildren(propEl);
+ while (properties.hasNext()) {
+ DavProperty<?> davProp = DefaultDavProperty.createFromXml(properties.nextElement());
+ proppatchSet.add(davProp);
+ proppatchList.add(davProp);
+ }
+ }
+ } else if (DomUtil.matches(el, XML_REMOVE, NAMESPACE)) {
+ Element propEl = DomUtil.getChildElement(el, XML_PROP, NAMESPACE);
+ if (propEl != null) {
+ ElementIterator properties = DomUtil.getChildren(propEl);
+ while (properties.hasNext()) {
+ DavProperty<?> davProp = DefaultDavProperty.createFromXml(properties.nextElement());
+ proppatchSet.add(davProp);
+ proppatchList.add(davProp.getName());
+ }
+ }
+ } else {
+ log.debug("Unknown element in DAV:propertyupdate: " + el.getNodeName());
+ // unknown child elements are ignored
+ }
+ }
+ }
+
+ /**
+ * {@link LockInfo} object encapsulating the information passed with a LOCK
+ * request if the LOCK request body was valid. If the request body is
+ * missing a 'refresh lock' request is assumed. The {@link LockInfo}
+ * then only provides timeout and isDeep property and returns true on
+ * {@link org.apache.jackrabbit.webdav.lock.LockInfo#isRefreshLock()}
+ *
+ * @return lock info object or <code>null</code> if an error occurred while
+ * parsing the request body.
+ * @throws DavException throws a 400 (Bad Request) DavException if a request
+ * body is present but does not start with a DAV:lockinfo element. Note however,
+ * that a non-existing request body is a valid request used to refresh
+ * an existing lock.
+ * @see DavServletRequest#getLockInfo()
+ */
+ public LockInfo getLockInfo() throws DavException {
+ LockInfo lockInfo;
+ boolean isDeep = (getDepth(DEPTH_INFINITY) == DEPTH_INFINITY);
+ Document requestDocument = getRequestDocument();
+ // check if XML request body is present. It SHOULD have one for
+ // 'create Lock' request and missing for a 'refresh Lock' request
+ if (requestDocument != null) {
+ Element root = requestDocument.getDocumentElement();
+ if (root.getLocalName().equals(XML_LOCKINFO)) {
+ lockInfo = new LockInfo(root, getTimeout(), isDeep);
+ } else {
+ log.debug("Lock request body must start with a DAV:lockinfo element.");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ } else {
+ lockInfo = new LockInfo(null, getTimeout(), isDeep);
+ }
+ return lockInfo;
+ }
+
+ /**
+ * Test if the if header matches the given resource. The comparison is
+ * made with the {@link DavResource#getHref()
+ * resource href} and the token returned from an exclusive write lock present on
+ * the resource.<br>
+ * NOTE: If either the If header or the resource is <code>null</code> or if
+ * the resource has not applied an exclusive write lock the preconditions are met.
+ * If in contrast the lock applied to the given resource returns a
+ * <code>null</code> lock token (e.g. for security reasons) or a lock token
+ * that does not match, the method will return false.
+ *
+ * @param resource Webdav resources being operated on
+ * @return true if the test is successful and the preconditions for the
+ * request processing are fulfilled.
+ * @see DavServletRequest#matchesIfHeader(DavResource)
+ * @see IfHeader#matches(String, String, String)
+ * @see DavResource#hasLock(org.apache.jackrabbit.webdav.lock.Type, org.apache.jackrabbit.webdav.lock.Scope)
+ * @see org.apache.jackrabbit.webdav.lock.ActiveLock#getToken()
+ */
+ public boolean matchesIfHeader(DavResource resource) {
+ // no ifheader
+ // >> preconditions ok so far
+ if (!ifHeader.hasValue() || resource == null) {
+ return true;
+ }
+
+ ActiveLock[] locks = resource.getLocks();
+ if (!resource.exists() || locks.length == 0) {
+ return matchesIfHeader(resource.getHref(), null, getStrongETag(resource));
+ }
+ for (ActiveLock lock : locks) {
+ if (matchesIfHeader(resource.getHref(), lock.getToken(), getStrongETag(resource))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @see DavServletRequest#matchesIfHeader(String, String, String)
+ * @see IfHeader#matches(String, String, String)
+ */
+ public boolean matchesIfHeader(String href, String token, String eTag) {
+ return ifHeader.matches(href, token, isStrongETag(eTag) ? eTag : "");
+ }
+
+ /**
+ * Returns the strong etag present on the given resource or empty string
+ * if either the resource does not provide any etag or if the etag is weak.
+ *
+ * @param resource
+ * @return strong etag or empty string.
+ */
+ private String getStrongETag(DavResource resource) {
+ if (resource.exists()) {
+ DavProperty<?> prop = resource.getProperty(DavPropertyName.GETETAG);
+ if (prop != null && prop.getValue() != null) {
+ String etag = prop.getValue().toString();
+ if (isStrongETag(etag)) {
+ return etag;
+ }
+ }
+ }
+ // no strong etag available
+ return "";
+ }
+
+ /**
+ * Returns true if the given string represents a strong etag.
+ *
+ * @param eTag
+ * @return true, if its a strong etag
+ */
+ private static boolean isStrongETag(String eTag) {
+ return eTag != null && eTag.length() > 0 && !eTag.startsWith("W\\");
+ }
+
+ //-----------------------------< TransactionDavServletRequest Interface >---
+ /**
+ * @see org.apache.jackrabbit.webdav.transaction.TransactionDavServletRequest#getTransactionId()
+ */
+ public String getTransactionId() {
+ return CodedUrlHeader.parse(httpRequest, TransactionConstants.HEADER_TRANSACTIONID).getCodedUrl();
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.transaction.TransactionDavServletRequest#getTransactionInfo()
+ */
+ public TransactionInfo getTransactionInfo() throws DavException {
+ Document requestDocument = getRequestDocument();
+ if (requestDocument != null) {
+ return new TransactionInfo(requestDocument.getDocumentElement());
+ }
+ return null;
+ }
+
+ //-----------------------------< ObservationDavServletRequest Interface >---
+ /**
+ * @see org.apache.jackrabbit.webdav.observation.ObservationDavServletRequest#getSubscriptionId()
+ */
+ public String getSubscriptionId() {
+ return CodedUrlHeader.parse(httpRequest, ObservationConstants.HEADER_SUBSCRIPTIONID).getCodedUrl();
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.observation.ObservationDavServletRequest#getPollTimeout()
+ */
+ public long getPollTimeout() {
+ return PollTimeoutHeader.parseHeader(httpRequest, 0).getTimeout();
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.observation.ObservationDavServletRequest#getSubscriptionInfo()
+ */
+ public SubscriptionInfo getSubscriptionInfo() throws DavException {
+ Document requestDocument = getRequestDocument();
+ if (requestDocument != null) {
+ Element root = requestDocument.getDocumentElement();
+ if (ObservationConstants.XML_SUBSCRIPTIONINFO.equals(root.getLocalName())) {
+ int depth = getDepth(DEPTH_0);
+ return new SubscriptionInfo(root, getTimeout(), depth == DEPTH_INFINITY);
+ }
+ }
+ return null;
+ }
+
+ //--------------------------------< OrderingDavServletRequest Interface >---
+ /**
+ * @see org.apache.jackrabbit.webdav.ordering.OrderingDavServletRequest#getOrderingType()
+ */
+ public String getOrderingType() {
+ return getHeader(OrderingConstants.HEADER_ORDERING_TYPE);
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.ordering.OrderingDavServletRequest#getPosition()
+ */
+ public Position getPosition() {
+ String h = getHeader(OrderingConstants.HEADER_POSITION);
+ Position pos = null;
+ if (h != null) {
+ String[] typeNSegment = h.split("\\s");
+ if (typeNSegment.length == 2) {
+ try {
+ pos = new Position(typeNSegment[0], typeNSegment[1]);
+ } catch (IllegalArgumentException e) {
+ log.error("Cannot parse Position header: " + e.getMessage());
+ }
+ }
+ }
+ return pos;
+ }
+
+ /**
+ * @return <code>OrderPatch</code> object representing the orderpatch request
+ * body or <code>null</code> if the
+ * @see org.apache.jackrabbit.webdav.ordering.OrderingDavServletRequest#getOrderPatch()
+ */
+ public OrderPatch getOrderPatch() throws DavException {
+ OrderPatch op = null;
+ Document requestDocument = getRequestDocument();
+ if (requestDocument != null) {
+ Element root = requestDocument.getDocumentElement();
+ op = OrderPatch.createFromXml(root);
+ } else {
+ log.error("Error while building xml document from ORDERPATH request body.");
+ }
+ return op;
+ }
+
+ //-------------------------------------< DeltaVServletRequest interface >---
+ /**
+ * @see org.apache.jackrabbit.webdav.version.DeltaVServletRequest#getLabel()
+ */
+ public String getLabel() {
+ LabelHeader label = LabelHeader.parse(this);
+ if (label != null) {
+ return label.getLabel();
+ }
+ return null;
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.version.DeltaVServletRequest#getLabelInfo()
+ */
+ public LabelInfo getLabelInfo() throws DavException {
+ LabelInfo lInfo = null;
+ Document requestDocument = getRequestDocument();
+ if (requestDocument != null) {
+ Element root = requestDocument.getDocumentElement();
+ int depth = getDepth(DEPTH_0);
+ lInfo = new LabelInfo(root, depth);
+ }
+ return lInfo;
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.version.DeltaVServletRequest#getMergeInfo()
+ */
+ public MergeInfo getMergeInfo() throws DavException {
+ MergeInfo mInfo = null;
+ Document requestDocument = getRequestDocument();
+ if (requestDocument != null) {
+ mInfo = new MergeInfo(requestDocument.getDocumentElement());
+ }
+ return mInfo;
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.version.DeltaVServletRequest#getUpdateInfo()
+ */
+ public UpdateInfo getUpdateInfo() throws DavException {
+ UpdateInfo uInfo = null;
+ Document requestDocument = getRequestDocument();
+ if (requestDocument != null) {
+ uInfo = new UpdateInfo(requestDocument.getDocumentElement());
+ }
+ return uInfo;
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.version.DeltaVServletRequest#getReportInfo()
+ */
+ public ReportInfo getReportInfo() throws DavException {
+ ReportInfo rInfo = null;
+ Document requestDocument = getRequestDocument();
+ if (requestDocument != null) {
+ rInfo = new ReportInfo(requestDocument.getDocumentElement(), getDepth(DEPTH_0));
+ }
+ return rInfo;
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.version.DeltaVServletRequest#getOptionsInfo()
+ */
+ public OptionsInfo getOptionsInfo() throws DavException {
+ OptionsInfo info = null;
+ Document requestDocument = getRequestDocument();
+ if (requestDocument != null) {
+ info = OptionsInfo.createFromXml(requestDocument.getDocumentElement());
+ }
+ return info;
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.bind.BindServletRequest#getRebindInfo()
+ */
+ public RebindInfo getRebindInfo() throws DavException {
+ RebindInfo info = null;
+ Document requestDocument = getRequestDocument();
+ if (requestDocument != null) {
+ info = RebindInfo.createFromXml(requestDocument.getDocumentElement());
+ }
+ return info;
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.bind.BindServletRequest#getUnbindInfo()
+ */
+ public UnbindInfo getUnbindInfo() throws DavException {
+ UnbindInfo info = null;
+ Document requestDocument = getRequestDocument();
+ if (requestDocument != null) {
+ info = UnbindInfo.createFromXml(requestDocument.getDocumentElement());
+ }
+ return info;
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.bind.BindServletRequest#getBindInfo()
+ */
+ public BindInfo getBindInfo() throws DavException {
+ BindInfo info = null;
+ Document requestDocument = getRequestDocument();
+ if (requestDocument != null) {
+ info = BindInfo.createFromXml(requestDocument.getDocumentElement());
+ }
+ return info;
+ }
+
+ //---------------------------------------< HttpServletRequest interface >---
+
+ @Override
+ public String getAuthType() {
+ return httpRequest.getAuthType();
+ }
+
+ @Override
+ public Cookie[] getCookies() {
+ return httpRequest.getCookies();
+ }
+
+ @Override
+ public long getDateHeader(String s) {
+ return httpRequest.getDateHeader(s);
+ }
+
+ @Override
+ public String getHeader(String s) {
+ return httpRequest.getHeader(s);
+ }
+
+ @Override
+ public Enumeration<String> getHeaders(String s) {
+ return httpRequest.getHeaders(s);
+ }
+
+ @Override
+ public Enumeration<String> getHeaderNames() {
+ return httpRequest.getHeaderNames();
+ }
+
+ @Override
+ public int getIntHeader(String s) {
+ return httpRequest.getIntHeader(s);
+ }
+
+ @Override
+ public String getMethod() {
+ return httpRequest.getMethod();
+ }
+
+ @Override
+ public String getPathInfo() {
+ return httpRequest.getPathInfo();
+ }
+
+ @Override
+ public String getPathTranslated() {
+ return httpRequest.getPathTranslated();
+ }
+
+ @Override
+ public String getContextPath() {
+ return httpRequest.getContextPath();
+ }
+
+ @Override
+ public String getQueryString() {
+ return httpRequest.getQueryString();
+ }
+
+ @Override
+ public String getRemoteUser() {
+ return httpRequest.getRemoteUser();
+ }
+
+ @Override
+ public boolean isUserInRole(String s) {
+ return httpRequest.isUserInRole(s);
+ }
+
+ @Override
+ public Principal getUserPrincipal() {
+ return httpRequest.getUserPrincipal();
+ }
+
+ @Override
+ public String getRequestedSessionId() {
+ return httpRequest.getRequestedSessionId();
+ }
+
+ @Override
+ public String getRequestURI() {
+ return httpRequest.getRequestURI();
+ }
+
+ @Override
+ public StringBuffer getRequestURL() {
+ return httpRequest.getRequestURL();
+ }
+
+ @Override
+ public String getServletPath() {
+ return httpRequest.getServletPath();
+ }
+
+ @Override
+ public HttpSession getSession(boolean b) {
+ return httpRequest.getSession(b);
+ }
+
+ @Override
+ public HttpSession getSession() {
+ return httpRequest.getSession();
+ }
+
+ @Override
+ public boolean isRequestedSessionIdValid() {
+ return httpRequest.isRequestedSessionIdValid();
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromCookie() {
+ return httpRequest.isRequestedSessionIdFromCookie();
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromURL() {
+ return httpRequest.isRequestedSessionIdFromURL();
+ }
+
+ @Override
+ public Object getAttribute(String s) {
+ return httpRequest.getAttribute(s);
+ }
+
+ @Override
+ public Enumeration<String> getAttributeNames() {
+ return httpRequest.getAttributeNames();
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return httpRequest.getCharacterEncoding();
+ }
+
+ @Override
+ public void setCharacterEncoding(String s) throws UnsupportedEncodingException {
+ httpRequest.setCharacterEncoding(s);
+ }
+
+ @Override
+ public int getContentLength() {
+ return httpRequest.getContentLength();
+ }
+
+ @Override
+ public String getContentType() {
+ return httpRequest.getContentType();
+ }
+
+ @Override
+ public ServletInputStream getInputStream() throws IOException {
+ return new MyServletInputStream(getDecodedInputStream());
+ }
+
+ @Override
+ public String getParameter(String s) {
+ return httpRequest.getParameter(s);
+ }
+
+ @Override
+ public Enumeration<String> getParameterNames() {
+ return httpRequest.getParameterNames();
+ }
+
+ @Override
+ public String[] getParameterValues(String s) {
+ return httpRequest.getParameterValues(s);
+ }
+
+ @Override
+ public Map<String, String[]> getParameterMap() {
+ return httpRequest.getParameterMap();
+ }
+
+ @Override
+ public String getProtocol() {
+ return httpRequest.getProtocol();
+ }
+
+ @Override
+ public String getScheme() {
+ return httpRequest.getScheme();
+ }
+
+ @Override
+ public String getServerName() {
+ return httpRequest.getServerName();
+ }
+
+ @Override
+ public int getServerPort() {
+ return httpRequest.getServerPort();
+ }
+
+ @Override
+ public BufferedReader getReader() throws IOException {
+ return httpRequest.getReader();
+ }
+
+ @Override
+ public String getRemoteAddr() {
+ return httpRequest.getRemoteAddr();
+ }
+
+ @Override
+ public String getRemoteHost() {
+ return httpRequest.getRemoteHost();
+ }
+
+ @Override
+ public void setAttribute(String s, Object o) {
+ httpRequest.setAttribute(s, o);
+ }
+
+ @Override
+ public void removeAttribute(String s) {
+ httpRequest.removeAttribute(s);
+ }
+
+ @Override
+ public Locale getLocale() {
+ return httpRequest.getLocale();
+ }
+
+ @Override
+ public Enumeration<Locale> getLocales() {
+ return httpRequest.getLocales();
+ }
+
+ @Override
+ public boolean isSecure() {
+ return httpRequest.isSecure();
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String s) {
+ return httpRequest.getRequestDispatcher(s);
+ }
+
+ @Override
+ public int getRemotePort() {
+ return httpRequest.getRemotePort();
+ }
+
+ @Override
+ public String getLocalName() {
+ return httpRequest.getLocalName();
+ }
+
+ @Override
+ public String getLocalAddr() {
+ return httpRequest.getLocalAddr();
+ }
+
+ @Override
+ public int getLocalPort() {
+ return httpRequest.getLocalPort();
+ }
+
+ @Override
+ public String changeSessionId() {
+ return httpRequest.changeSessionId();
+ }
+
+ @Override
+ public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
+ return httpRequest.authenticate(response);
+ }
+
+ @Override
+ public void login(String username, String password) throws ServletException {
+ httpRequest.login(username, password);
+ }
+
+ @Override
+ public void logout() throws ServletException {
+ httpRequest.logout();
+ }
+
+ @Override
+ public Collection<Part> getParts() throws IOException, ServletException {
+ return httpRequest.getParts();
+ }
+
+ @Override
+ public Part getPart(String name) throws IOException, ServletException {
+ return httpRequest.getPart(name);
+ }
+
+ @Override
+ public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException {
+ return httpRequest.upgrade(handlerClass);
+ }
+
+ @Override
+ public long getContentLengthLong() {
+ return httpRequest.getContentLengthLong();
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return httpRequest.getServletContext();
+ }
+
+ @Override
+ public AsyncContext startAsync() throws IllegalStateException {
+ return httpRequest.startAsync();
+ }
+
+ @Override
+ public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException {
+ return httpRequest.startAsync(servletRequest, servletResponse);
+ }
+
+ @Override
+ public boolean isAsyncStarted() {
+ return httpRequest.isAsyncStarted();
+ }
+
+ @Override
+ public boolean isAsyncSupported() {
+ return httpRequest.isAsyncSupported();
+ }
+
+ @Override
+ public AsyncContext getAsyncContext() {
+ return httpRequest.getAsyncContext();
+ }
+
+ @Override
+ public DispatcherType getDispatcherType() {
+ return httpRequest.getDispatcherType();
+ }
+
+ @Override
+ public ServletConnection getServletConnection() {
+ return httpRequest.getServletConnection();
+ }
+
+ @Override
+ public String getProtocolRequestId() {
+ return httpRequest.getProtocolRequestId();
+ }
+
+ @Override
+ public String getRequestId() {
+ return httpRequest.getRequestId();
+ }
+
+ private static class MyServletInputStream extends ServletInputStream {
+
+ private final InputStream delegate;
+
+ public MyServletInputStream(InputStream delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public int available() throws IOException {
+ return delegate.available();
+ }
+
+ @Override
+ public void close() throws IOException {
+ delegate.close();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return delegate.equals(other);
+ }
+
+ @Override
+ public int hashCode() {
+ return delegate.hashCode();
+ }
+
+ @Override
+ public void mark(int readlimit) {
+ delegate.mark(readlimit);
+ }
+
+ @Override
+ public boolean markSupported() {
+ return delegate.markSupported();
+ }
+
+ @Override
+ public int read() throws IOException {
+ return delegate.read();
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ return delegate.read(b, off, len);
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return delegate.read(b);
+ }
+
+ @Override
+ public int readLine(byte[] b, int off, int len) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void reset() throws IOException {
+ delegate.reset();
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ return delegate.skip(n);
+ }
+
+ @Override
+ public String toString() {
+ return delegate.toString();
+ }
+
+ @Override
+ public boolean isFinished() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isReady() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setReadListener(ReadListener readListener) {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/WebdavResponse.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/WebdavResponse.java
new file mode 100644
index 000000000..2fa1811b6
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/WebdavResponse.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.jackrabbit.webdav.observation.ObservationDavServletResponse;
+
+/**
+ * The empty <code>WebdavResponse</code> interface collects the functionality
+ * defined by {@link org.apache.jackrabbit.webdav.DavServletResponse}
+ * encapsulating for the core WebDAV specification (RFC 2518) as well as the
+ * various extensions used for observation and transaction support, ordering of
+ * collections, search and versioning.
+ */
+public interface WebdavResponse extends DavServletResponse, ObservationDavServletResponse {
+
+ // can be removed when we move to Servlet API 4.0
+ public default void setTrailerFields(Supplier<Map<String, String>> supplier) {
+ // nop
+ }
+
+ // can be removed when we move to Servlet API 4.0
+ public default Supplier<Map<String, String>> getTrailerFields() {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/WebdavResponseImpl.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/WebdavResponseImpl.java
new file mode 100644
index 000000000..660d951ad
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/WebdavResponseImpl.java
@@ -0,0 +1,392 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav;
+
+import org.apache.jackrabbit.webdav.header.CodedUrlHeader;
+import org.apache.jackrabbit.webdav.header.Header;
+import org.apache.jackrabbit.webdav.lock.ActiveLock;
+import org.apache.jackrabbit.webdav.lock.LockDiscovery;
+import org.apache.jackrabbit.webdav.observation.EventDiscovery;
+import org.apache.jackrabbit.webdav.observation.ObservationConstants;
+import org.apache.jackrabbit.webdav.observation.Subscription;
+import org.apache.jackrabbit.webdav.observation.SubscriptionDiscovery;
+import org.apache.jackrabbit.webdav.property.DavPropertySet;
+import org.apache.jackrabbit.webdav.xml.DomUtil;
+import org.apache.jackrabbit.webdav.xml.XmlSerializable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import jakarta.servlet.ServletOutputStream;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletResponse;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.function.Supplier;
+import java.util.zip.GZIPOutputStream;
+
+/**
+ * WebdavResponseImpl implements the <code>WebdavResponse</code> interface.
+ */
+public class WebdavResponseImpl implements WebdavResponse {
+
+ private static Logger log = LoggerFactory.getLogger(WebdavResponseImpl.class);
+
+ private HttpServletResponse httpResponse;
+
+ /**
+ * Create a new <code>WebdavResponse</code>
+ *
+ * @param httpResponse
+ */
+ public WebdavResponseImpl(HttpServletResponse httpResponse) {
+ this(httpResponse, false);
+ }
+
+ /**
+ * Create a new <code>WebdavResponse</code>
+ *
+ * @param httpResponse
+ * @param noCache
+ */
+ public WebdavResponseImpl(HttpServletResponse httpResponse, boolean noCache) {
+ this.httpResponse = httpResponse;
+ if (noCache) {
+ /* set cache control headers */
+ addHeader("Pragma", "No-cache"); // http1.0
+ addHeader("Cache-Control", "no-cache"); // http1.1
+ }
+ }
+
+ /**
+ * If the specifid exception provides an error condition an Xml response body
+ * is sent providing more detailed information about the error. Otherwise only
+ * the error code and status phrase is sent back.
+ *
+ * @param exception
+ * @throws IOException
+ * @see DavServletResponse#sendError(org.apache.jackrabbit.webdav.DavException)
+ * @see #sendError(int, String)
+ * @see #sendXmlResponse(XmlSerializable, int)
+ */
+ public void sendError(DavException exception) throws IOException {
+ if (!exception.hasErrorCondition()) {
+ httpResponse.sendError(exception.getErrorCode(), exception.getStatusPhrase());
+ } else {
+ sendXmlResponse(exception, exception.getErrorCode());
+ }
+ }
+
+ @Override
+ public void sendMultiStatus(MultiStatus multistatus) throws IOException {
+ sendXmlResponse(multistatus, SC_MULTI_STATUS);
+ }
+
+ @Override
+ public void sendMultiStatus(MultiStatus multistatus, List<String> acceptableContentCodings) throws IOException {
+ sendXmlResponse(multistatus, SC_MULTI_STATUS, acceptableContentCodings);
+ }
+
+ /**
+ * Send response body for a lock request that was intended to refresh one
+ * or several locks.
+ *
+ * @param locks
+ * @throws java.io.IOException
+ * @see DavServletResponse#sendRefreshLockResponse(org.apache.jackrabbit.webdav.lock.ActiveLock[])
+ */
+ public void sendRefreshLockResponse(ActiveLock[] locks) throws IOException {
+ DavPropertySet propSet = new DavPropertySet();
+ propSet.add(new LockDiscovery(locks));
+ sendXmlResponse(propSet, SC_OK);
+ }
+
+ @Override
+ public void sendXmlResponse(XmlSerializable serializable, int status) throws IOException {
+ sendXmlResponse(serializable, status, Collections.emptyList());
+ }
+
+ @Override
+ public void sendXmlResponse(XmlSerializable serializable, int status, List<String> acceptableContentCodings) throws IOException {
+ httpResponse.setStatus(status);
+
+ if (serializable != null) {
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ Document doc = DomUtil.createDocument();
+ doc.appendChild(serializable.toXml(doc));
+ DomUtil.transformDocument(doc, out);
+ out.close();
+
+ httpResponse.setContentType("text/xml; charset=UTF-8");
+
+ // use GZIP iff accepted by client and content size >= 256 octets
+ if (out.size() < 256 || !acceptableContentCodings.contains("gzip")) {
+ httpResponse.setContentLength(out.size());
+ out.writeTo(httpResponse.getOutputStream());
+ } else {
+ httpResponse.setHeader("Content-Encoding", "gzip");
+ try (OutputStream os = new GZIPOutputStream(httpResponse.getOutputStream())) {
+ out.writeTo(os);
+ }
+ }
+ } catch (ParserConfigurationException e) {
+ log.error(e.getMessage());
+ throw new IOException(e.getMessage());
+ } catch (TransformerException e) {
+ log.error(e.getMessage());
+ throw new IOException(e.getMessage());
+ } catch (SAXException e) {
+ log.error(e.getMessage());
+ throw new IOException(e.getMessage());
+ }
+ }
+ }
+
+ //----------------------------< ObservationDavServletResponse Interface >---
+ /**
+ *
+ * @param subscription
+ * @throws IOException
+ * @see org.apache.jackrabbit.webdav.observation.ObservationDavServletResponse#sendSubscriptionResponse(org.apache.jackrabbit.webdav.observation.Subscription)
+ */
+ public void sendSubscriptionResponse(Subscription subscription) throws IOException {
+ String id = subscription.getSubscriptionId();
+ if (id != null) {
+ Header h = new CodedUrlHeader(ObservationConstants.HEADER_SUBSCRIPTIONID, id);
+ httpResponse.setHeader(h.getHeaderName(), h.getHeaderValue());
+ }
+ DavPropertySet propSet = new DavPropertySet();
+ propSet.add(new SubscriptionDiscovery(subscription));
+ sendXmlResponse(propSet, SC_OK);
+ }
+
+ /**
+ *
+ * @param eventDiscovery
+ * @throws IOException
+ * @see org.apache.jackrabbit.webdav.observation.ObservationDavServletResponse#sendPollResponse(org.apache.jackrabbit.webdav.observation.EventDiscovery)
+ */
+ public void sendPollResponse(EventDiscovery eventDiscovery) throws IOException {
+ sendXmlResponse(eventDiscovery, SC_OK);
+ }
+
+ //--------------------------------------< HttpServletResponse interface >---
+
+ @Override
+ public void addCookie(Cookie cookie) {
+ httpResponse.addCookie(cookie);
+ }
+
+ @Override
+ public boolean containsHeader(String s) {
+ return httpResponse.containsHeader(s);
+ }
+
+ @Override
+ public String encodeURL(String s) {
+ return httpResponse.encodeRedirectURL(s);
+ }
+
+ @Override
+ public String encodeRedirectURL(String s) {
+ return httpResponse.encodeRedirectURL(s);
+ }
+
+ @Override
+ public void sendError(int i, String s) throws IOException {
+ httpResponse.sendError(i, s);
+ }
+
+ @Override
+ public void sendError(int i) throws IOException {
+ httpResponse.sendError(i);
+ }
+
+ @Override
+ public void sendRedirect(String s) throws IOException {
+ httpResponse.sendRedirect(s);
+ }
+
+ @Override
+ public void setDateHeader(String s, long l) {
+ httpResponse.setDateHeader(s, l);
+ }
+
+ @Override
+ public void addDateHeader(String s, long l) {
+ httpResponse.addDateHeader(s, l);
+ }
+
+ @Override
+ public void setHeader(String s, String s1) {
+ httpResponse.setHeader(s, s1);
+ }
+
+ @Override
+ public void addHeader(String s, String s1) {
+ httpResponse.addHeader(s, s1);
+ }
+
+ @Override
+ public void setIntHeader(String s, int i) {
+ httpResponse.setIntHeader(s, i);
+ }
+
+ @Override
+ public void addIntHeader(String s, int i) {
+ httpResponse.addIntHeader(s, i);
+ }
+
+ @Override
+ public void setStatus(int i) {
+ httpResponse.setStatus(i);
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return httpResponse.getCharacterEncoding();
+ }
+
+ @Override
+ public ServletOutputStream getOutputStream() throws IOException {
+ return httpResponse.getOutputStream();
+ }
+
+ @Override
+ public PrintWriter getWriter() throws IOException {
+ return httpResponse.getWriter();
+ }
+
+ @Override
+ public void setContentLength(int i) {
+ httpResponse.setContentLength(i);
+ }
+
+ @Override
+ public void setContentType(String s) {
+ httpResponse.setContentType(s);
+ }
+
+ @Override
+ public void setBufferSize(int i) {
+ httpResponse.setBufferSize(i);
+ }
+
+ @Override
+ public int getBufferSize() {
+ return httpResponse.getBufferSize();
+ }
+
+ @Override
+ public void flushBuffer() throws IOException {
+ httpResponse.flushBuffer();
+ }
+
+ @Override
+ public void resetBuffer() {
+ httpResponse.resetBuffer();
+ }
+
+ @Override
+ public boolean isCommitted() {
+ return httpResponse.isCommitted();
+ }
+
+ @Override
+ public void reset() {
+ httpResponse.reset();
+ }
+
+ @Override
+ public void setLocale(Locale locale) {
+ httpResponse.setLocale(locale);
+ }
+
+ @Override
+ public Locale getLocale() {
+ return httpResponse.getLocale();
+ }
+
+ @Override
+ public String getContentType() {
+ return httpResponse.getContentType();
+ }
+
+ @Override
+ public void setCharacterEncoding(String charset) {
+ httpResponse.setCharacterEncoding(charset);
+ }
+
+ @Override
+ public int getStatus() {
+ return httpResponse.getStatus();
+ }
+
+ @Override
+ public String getHeader(String name) {
+ return httpResponse.getHeader(name);
+ }
+
+ @Override
+ public Collection<String> getHeaders(String name) {
+ return httpResponse.getHeaders(name);
+ }
+
+ @Override
+ public Collection<String> getHeaderNames() {
+ return httpResponse.getHeaderNames();
+ }
+
+ @Override
+ public void setContentLengthLong(long len) {
+ httpResponse.setContentLengthLong(len);
+ }
+
+ // Servlet 4.0 API support for trailers, for now using reflection
+
+ public void setTrailerFields(Supplier<Map<String, String>> supplier) {
+ try {
+ java.lang.reflect.Method stf = httpResponse.getClass().getDeclaredMethod("setTrailerFields", Supplier.class);
+ stf.invoke(httpResponse, supplier);
+ } catch (IllegalAccessException | java.lang.reflect.InvocationTargetException | NoSuchMethodException
+ | SecurityException ex) {
+ throw new UnsupportedOperationException("no servlet 4.0 support on: " + httpResponse.getClass(), ex);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public Supplier<Map<String, String>> getTrailerFields() {
+ try {
+ java.lang.reflect.Method stf = httpResponse.getClass().getDeclaredMethod("getTrailerFields");
+ return (Supplier<Map<String, String>>) stf.invoke(httpResponse);
+ } catch (IllegalAccessException | java.lang.reflect.InvocationTargetException | NoSuchMethodException
+ | SecurityException ex) {
+ throw new UnsupportedOperationException("no servlet 4.0 support on: " + httpResponse.getClass(), ex);
+ }
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/BindConstants.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/BindConstants.java
new file mode 100644
index 000000000..e52f8c668
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/BindConstants.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.bind;
+
+import org.apache.jackrabbit.webdav.xml.Namespace;
+import org.apache.jackrabbit.webdav.DavConstants;
+import org.apache.jackrabbit.webdav.property.DavPropertyName;
+
+/**
+ * <code>BindConstants</code> provide constants for request and response
+ * headers, Xml elements and property names defined by
+ * the BIND specification.
+ */
+public interface BindConstants {
+
+ /**
+ * The namespace
+ */
+ public static final Namespace NAMESPACE = DavConstants.NAMESPACE;
+
+ /**
+ * local names of XML elements used in the request bodies of the methods BIND, REBIND and UNBIND.
+ */
+ public static final String XML_BIND = "bind";
+ public static final String XML_REBIND = "rebind";
+ public static final String XML_UNBIND = "unbind";
+ public static final String XML_SEGMENT = "segment";
+ public static final String XML_HREF = "href";
+ public static final String XML_PARENT = "parent";
+
+ public static final String METHODS = "BIND, REBIND, UNBIND";
+
+ /*
+ * Webdav properties defined by the BIND specification.
+ */
+ public static final DavPropertyName RESOURCEID = DavPropertyName.create("resource-id");
+ public static final DavPropertyName PARENTSET = DavPropertyName.create("parent-set");
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/BindInfo.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/BindInfo.java
new file mode 100644
index 000000000..627640ebf
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/BindInfo.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.bind;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.DavException;
+import org.apache.jackrabbit.webdav.xml.DomUtil;
+import org.apache.jackrabbit.webdav.xml.ElementIterator;
+import org.apache.jackrabbit.webdav.xml.XmlSerializable;
+import org.w3c.dom.Element;
+import org.w3c.dom.Document;
+
+public class BindInfo implements XmlSerializable {
+
+ private static Logger log = LoggerFactory.getLogger(BindInfo.class);
+
+ private String segment;
+ private String href;
+
+ public BindInfo(String href, String segment) {
+ this.href = href;
+ this.segment = segment;
+ }
+
+ public String getHref() {
+ return this.href;
+ }
+
+ public String getSegment() {
+ return this.segment;
+ }
+
+ /**
+ * Build an <code>BindInfo</code> object from the root element present
+ * in the request body.
+ *
+ * @param root the root element of the request body
+ * @return a BindInfo object containing segment and href
+ * @throws org.apache.jackrabbit.webdav.DavException if the BIND request is malformed
+ */
+ public static BindInfo createFromXml(Element root) throws DavException {
+ if (!DomUtil.matches(root, BindConstants.XML_BIND, BindConstants.NAMESPACE)) {
+ log.warn("DAV:bind element expected");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ String href = null;
+ String segment = null;
+ ElementIterator it = DomUtil.getChildren(root);
+ while (it.hasNext()) {
+ Element elt = it.nextElement();
+ if (DomUtil.matches(elt, BindConstants.XML_SEGMENT, BindConstants.NAMESPACE)) {
+ if (segment == null) {
+ segment = DomUtil.getText(elt);
+ } else {
+ log.warn("unexpected multiple occurrence of DAV:segment element");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ } else if (DomUtil.matches(elt, BindConstants.XML_HREF, BindConstants.NAMESPACE)) {
+ if (href == null) {
+ href = DomUtil.getText(elt);
+ } else {
+ log.warn("unexpected multiple occurrence of DAV:href element");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ } else {
+ log.warn("unexpected element " + elt.getLocalName());
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ }
+ if (href == null) {
+ log.warn("DAV:href element expected");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ if (segment == null) {
+ log.warn("DAV:segment element expected");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ return new BindInfo(href, segment);
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.xml.XmlSerializable#toXml(org.w3c.dom.Document)
+ */
+ public Element toXml(Document document) {
+ Element bindElt = DomUtil.createElement(document, BindConstants.XML_BIND, BindConstants.NAMESPACE);
+ Element hrefElt = DomUtil.createElement(document, BindConstants.XML_HREF, BindConstants.NAMESPACE, this.href);
+ Element segElt = DomUtil.createElement(document, BindConstants.XML_SEGMENT, BindConstants.NAMESPACE, this.segment);
+ bindElt.appendChild(hrefElt);
+ bindElt.appendChild(segElt);
+ return bindElt;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/BindServletRequest.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/BindServletRequest.java
new file mode 100644
index 000000000..8d6c5168e
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/BindServletRequest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.bind;
+
+import org.apache.jackrabbit.webdav.DavException;
+import org.apache.jackrabbit.webdav.DavResourceLocator;
+
+/**
+ * <code>BindServletRequest</code> provides extension useful for functionality
+ * related to BIND specification.
+ */
+public interface BindServletRequest {
+
+ /**
+ * Returns the {@link RebindInfo} present with the request
+ *
+ * @return {@link RebindInfo} object
+ * @throws org.apache.jackrabbit.webdav.DavException in case of an invalid or missing request body
+ */
+ public RebindInfo getRebindInfo() throws DavException;
+
+ /**
+ * Returns the {@link UnbindInfo} present with the request
+ *
+ * @return {@link UnbindInfo} object
+ * @throws org.apache.jackrabbit.webdav.DavException in case of an invalid or missing request body
+ */
+ public UnbindInfo getUnbindInfo() throws DavException;
+
+ /**
+ * Returns the {@link BindInfo} present with the request
+ *
+ * @return {@link BindInfo} object
+ * @throws org.apache.jackrabbit.webdav.DavException in case of an invalid or missing request body
+ */
+ public BindInfo getBindInfo() throws DavException;
+
+ /**
+ * Parses a href and returns the path of the resource.
+ *
+ * @return path of the resource identified by the href.
+ */
+ public DavResourceLocator getHrefLocator(String href) throws DavException;
+
+ /**
+ * Returns the path of the member resource of the request resource which is identified by the segment parameter.
+ *
+ * @return path of internal member resource.
+ */
+ public DavResourceLocator getMemberLocator(String segment);
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/BindableResource.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/BindableResource.java
new file mode 100644
index 000000000..86be8faa3
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/BindableResource.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.bind;
+
+import java.util.Set;
+
+import org.apache.jackrabbit.webdav.DavException;
+import org.apache.jackrabbit.webdav.DavResource;
+
+public interface BindableResource {
+
+ /**
+ * Will add a new binding to the given collection referencing this resource.
+ *
+ * @param collection the collection to create the new binding in.
+ * @param newBinding the new binding
+ */
+ public void bind(DavResource collection, DavResource newBinding) throws DavException;
+
+ /**
+ * Will rebind the resource to the given collection. By definition, this is
+ * an atomic move operation.
+ *
+ * @param collection the collection to create the new binding in.
+ * @param newBinding the new binding
+ */
+ public void rebind(DavResource collection, DavResource newBinding) throws DavException;
+
+ /**
+ * Will retrieve a collection of parent elements of the bindable resource
+ * representing the parent set.
+ *
+ * @return newBinding the new binding
+ */
+ public Set<ParentElement> getParentElements();
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/ParentElement.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/ParentElement.java
new file mode 100644
index 000000000..3edd2ab15
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/ParentElement.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.bind;
+
+import org.apache.jackrabbit.webdav.xml.XmlSerializable;
+import org.apache.jackrabbit.webdav.xml.DomUtil;
+import org.apache.jackrabbit.webdav.xml.ElementIterator;
+import org.apache.jackrabbit.webdav.DavException;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.w3c.dom.Element;
+import org.w3c.dom.Document;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * <code>ParentElement</code> wraps en element of the parent set of a resource. A <code>java.util.Set</code> of
+ * <code>ParentElement</code> objects may serve as the value object of the <code>ParentSet</code> DavProperty.
+ */
+public class ParentElement implements XmlSerializable {
+
+ private static Logger log = LoggerFactory.getLogger(ParentElement.class);
+
+ private final String href;
+ private final String segment;
+
+ public ParentElement(String href, String segment) {
+ this.href = href;
+ this.segment = segment;
+ }
+
+ public String getHref() {
+ return this.href;
+ }
+
+ public String getSegment() {
+ return this.segment;
+ }
+
+ /**
+ * Build an <code>ParentElement</code> object from an XML element DAV:parent
+ *
+ * @param root the DAV:parent element
+ * @return a ParentElement object
+ * @throws org.apache.jackrabbit.webdav.DavException if the DAV:parent element is malformed
+ */
+ public static ParentElement createFromXml(Element root) throws DavException {
+ if (!DomUtil.matches(root, BindConstants.XML_PARENT, BindConstants.NAMESPACE)) {
+ log.warn("DAV:paret element expected");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ String href = null;
+ String segment = null;
+ ElementIterator it = DomUtil.getChildren(root);
+ while (it.hasNext()) {
+ Element elt = it.nextElement();
+ if (DomUtil.matches(elt, BindConstants.XML_SEGMENT, BindConstants.NAMESPACE)) {
+ if (segment == null) {
+ segment = DomUtil.getText(elt);
+ } else {
+ log.warn("unexpected multiple occurrence of DAV:segment element");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ } else if (DomUtil.matches(elt, BindConstants.XML_HREF, BindConstants.NAMESPACE)) {
+ if (href == null) {
+ href = DomUtil.getText(elt);
+ } else {
+ log.warn("unexpected multiple occurrence of DAV:href element");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ } else {
+ log.warn("unexpected element " + elt.getLocalName());
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ }
+ if (href == null) {
+ log.warn("DAV:href element expected");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ if (segment == null) {
+ log.warn("DAV:segment element expected");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ return new ParentElement(href, segment);
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.xml.XmlSerializable#toXml(org.w3c.dom.Document)
+ */
+ public Element toXml(Document document) {
+ Element parentElt = DomUtil.createElement(document, BindConstants.XML_PARENT, BindConstants.NAMESPACE);
+ Element hrefElt = DomUtil.createElement(document, BindConstants.XML_HREF, BindConstants.NAMESPACE, this.href);
+ Element segElt = DomUtil.createElement(document, BindConstants.XML_SEGMENT, BindConstants.NAMESPACE, this.segment);
+ parentElt.appendChild(hrefElt);
+ parentElt.appendChild(segElt);
+ return parentElt;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/ParentSet.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/ParentSet.java
new file mode 100644
index 000000000..01fae4230
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/ParentSet.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.bind;
+
+import org.apache.jackrabbit.webdav.property.AbstractDavProperty;
+
+import java.util.Collection;
+
+/**
+ * <code>ParentSet</code> represents a DAV:parent-set property.
+ */
+public class ParentSet extends AbstractDavProperty<Collection<ParentElement>> {
+
+ private final Collection<ParentElement> parents;
+
+ /**
+ * Creates a new ParentSet from a collection of <code>ParentElement</code> objects.
+ * @param parents
+ */
+ public ParentSet(Collection<ParentElement> parents) {
+ super(BindConstants.PARENTSET, true);
+ this.parents = parents;
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.property.AbstractDavProperty#getValue()
+ */
+ public Collection<ParentElement> getValue() {
+ return this.parents;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/RebindInfo.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/RebindInfo.java
new file mode 100644
index 000000000..233b236a7
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/RebindInfo.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.bind;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.DavException;
+import org.apache.jackrabbit.webdav.xml.DomUtil;
+import org.apache.jackrabbit.webdav.xml.ElementIterator;
+import org.apache.jackrabbit.webdav.xml.XmlSerializable;
+import org.w3c.dom.Element;
+import org.w3c.dom.Document;
+
+public class RebindInfo implements XmlSerializable {
+
+ private static Logger log = LoggerFactory.getLogger(RebindInfo.class);
+
+ private String segment;
+ private String href;
+
+ public RebindInfo(String href, String segment) {
+ this.href = href;
+ this.segment = segment;
+ }
+
+ public String getHref() {
+ return this.href;
+ }
+
+ public String getSegment() {
+ return this.segment;
+ }
+
+ /**
+ * Build an <code>RebindInfo</code> object from the root element present
+ * in the request body.
+ *
+ * @param root the root element of the request body
+ * @return a RebindInfo object containing segment and href
+ * @throws org.apache.jackrabbit.webdav.DavException if the REBIND request is malformed
+ */
+ public static RebindInfo createFromXml(Element root) throws DavException {
+ if (!DomUtil.matches(root, BindConstants.XML_REBIND, BindConstants.NAMESPACE)) {
+ log.warn("DAV:rebind element expected");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ String href = null;
+ String segment = null;
+ ElementIterator it = DomUtil.getChildren(root);
+ while (it.hasNext()) {
+ Element elt = it.nextElement();
+ if (DomUtil.matches(elt, BindConstants.XML_SEGMENT, BindConstants.NAMESPACE)) {
+ if (segment == null) {
+ segment = DomUtil.getText(elt);
+ } else {
+ log.warn("unexpected multiple occurrence of DAV:segment element");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ } else if (DomUtil.matches(elt, BindConstants.XML_HREF, BindConstants.NAMESPACE)) {
+ if (href == null) {
+ href = DomUtil.getText(elt);
+ } else {
+ log.warn("unexpected multiple occurrence of DAV:href element");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ } else {
+ log.warn("unexpected element " + elt.getLocalName());
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ }
+ if (href == null) {
+ log.warn("DAV:href element expected");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ if (segment == null) {
+ log.warn("DAV:segment element expected");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ return new RebindInfo(href, segment);
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.xml.XmlSerializable#toXml(org.w3c.dom.Document)
+ */
+ public Element toXml(Document document) {
+ Element rebindElt = DomUtil.createElement(document, BindConstants.XML_REBIND, BindConstants.NAMESPACE);
+ Element hrefElt = DomUtil.createElement(document, BindConstants.XML_HREF, BindConstants.NAMESPACE, this.href);
+ Element segElt = DomUtil.createElement(document, BindConstants.XML_SEGMENT, BindConstants.NAMESPACE, this.segment);
+ rebindElt.appendChild(hrefElt);
+ rebindElt.appendChild(segElt);
+ return rebindElt;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/UnbindInfo.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/UnbindInfo.java
new file mode 100644
index 000000000..e3c7a3e2d
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/UnbindInfo.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.bind;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.DavException;
+import org.apache.jackrabbit.webdav.xml.DomUtil;
+import org.apache.jackrabbit.webdav.xml.ElementIterator;
+import org.apache.jackrabbit.webdav.xml.XmlSerializable;
+import org.w3c.dom.Element;
+import org.w3c.dom.Document;
+
+public class UnbindInfo implements XmlSerializable {
+
+ private static Logger log = LoggerFactory.getLogger(UnbindInfo.class);
+
+ private String segment;
+
+ private UnbindInfo() {}
+
+ public UnbindInfo(String segment) {
+ this.segment = segment;
+ }
+
+ public String getSegment() {
+ return this.segment;
+ }
+
+ /**
+ * Build an <code>UnbindInfo</code> object from the root element present
+ * in the request body.
+ *
+ * @param root the root element of the request body
+ * @return a UnbindInfo object containing a segment identifier
+ * @throws org.apache.jackrabbit.webdav.DavException if the UNBIND request is malformed
+ */
+ public static UnbindInfo createFromXml(Element root) throws DavException {
+ if (!DomUtil.matches(root, BindConstants.XML_UNBIND, BindConstants.NAMESPACE)) {
+ log.warn("DAV:unbind element expected");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ String segment = null;
+ ElementIterator it = DomUtil.getChildren(root);
+ while (it.hasNext()) {
+ Element elt = it.nextElement();
+ if (DomUtil.matches(elt, BindConstants.XML_SEGMENT, BindConstants.NAMESPACE)) {
+ if (segment == null) {
+ segment = DomUtil.getText(elt);
+ } else {
+ log.warn("unexpected multiple occurrence of DAV:segment element");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ } else {
+ log.warn("unexpected element " + elt.getLocalName());
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ }
+ if (segment == null) {
+ log.warn("DAV:segment element expected");
+ throw new DavException(DavServletResponse.SC_BAD_REQUEST);
+ }
+ return new UnbindInfo(segment);
+ }
+
+ /**
+ * @see org.apache.jackrabbit.webdav.xml.XmlSerializable#toXml(org.w3c.dom.Document)
+ */
+ public Element toXml(Document document) {
+ Element unbindElt = DomUtil.createElement(document, BindConstants.XML_UNBIND, BindConstants.NAMESPACE);
+ Element segElt = DomUtil.createElement(document, BindConstants.XML_SEGMENT, BindConstants.NAMESPACE, this.segment);
+ unbindElt.appendChild(segElt);
+ return unbindElt;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/package-info.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/package-info.java
new file mode 100644
index 000000000..05d41820c
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/bind/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@org.osgi.annotation.versioning.Version("1.0.0")
+package org.apache.jackrabbit.webdav.bind;
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/BaseDavRequest.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/BaseDavRequest.java
new file mode 100644
index 000000000..ca365b75f
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/BaseDavRequest.java
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.StatusLine;
+import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
+import org.apache.jackrabbit.webdav.DavConstants;
+import org.apache.jackrabbit.webdav.DavException;
+import org.apache.jackrabbit.webdav.MultiStatus;
+import org.apache.jackrabbit.webdav.lock.LockDiscovery;
+import org.apache.jackrabbit.webdav.observation.EventDiscovery;
+import org.apache.jackrabbit.webdav.observation.ObservationConstants;
+import org.apache.jackrabbit.webdav.observation.Subscription;
+import org.apache.jackrabbit.webdav.observation.SubscriptionDiscovery;
+import org.apache.jackrabbit.webdav.xml.DomUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+/**
+ * Base class for HTTP request classes defined in this package.
+ */
+public abstract class BaseDavRequest extends HttpEntityEnclosingRequestBase {
+
+ private static Logger log = LoggerFactory.getLogger(BaseDavRequest.class);
+
+ public BaseDavRequest(URI uri) {
+ super();
+ super.setURI(uri);
+ }
+
+ /**
+ * Gets a {@link Document} representing the response body.
+ * @return document or {@code null} for null entity
+ * @throws IOException in case of I/O or XMP pasting problems
+ */
+ public Document getResponseBodyAsDocument(HttpEntity entity) throws IOException {
+
+ if (entity == null) {
+ return null;
+ } else {
+ // read response and try to build a xml document
+ InputStream in = entity.getContent();
+ try {
+ return DomUtil.parseDocument(in);
+ } catch (ParserConfigurationException ex) {
+ throw new IOException("XML parser configuration error", ex);
+ } catch (SAXException ex) {
+ throw new IOException("XML parsing error", ex);
+ } finally {
+ in.close();
+ }
+ }
+ }
+
+ /**
+ * Return response body as {@link MultiStatus} object.
+ * @throws IllegalStateException when response does not represent a {@link MultiStatus}
+ * @throws DavException for failures in obtaining/parsing the response body
+ */
+ public MultiStatus getResponseBodyAsMultiStatus(HttpResponse response) throws DavException {
+ try {
+ Document doc = getResponseBodyAsDocument(response.getEntity());
+ if (doc == null) {
+ throw new DavException(response.getStatusLine().getStatusCode(), "no response body");
+ }
+ return MultiStatus.createFromXml(doc.getDocumentElement());
+ } catch (IOException ex) {
+ throw new DavException(response.getStatusLine().getStatusCode(), ex);
+ }
+ }
+
+ /**
+ * Return response body as {@link LockDiscovery} object.
+ * @throws IllegalStateException when response does not represent a {@link LockDiscovery}
+ * @throws DavException for failures in obtaining/parsing the response body
+ */
+ public LockDiscovery getResponseBodyAsLockDiscovery(HttpResponse response) throws DavException {
+ try {
+ Document doc = getResponseBodyAsDocument(response.getEntity());
+ if (doc == null) {
+ throw new DavException(response.getStatusLine().getStatusCode(), "no response body");
+ }
+ Element root = doc.getDocumentElement();
+
+ if (!DomUtil.matches(root, DavConstants.XML_PROP, DavConstants.NAMESPACE)
+ && DomUtil.hasChildElement(root, DavConstants.PROPERTY_LOCKDISCOVERY, DavConstants.NAMESPACE)) {
+ throw new DavException(response.getStatusLine().getStatusCode(),
+ "Missing DAV:prop response body in LOCK response.");
+ }
+
+ Element lde = DomUtil.getChildElement(root, DavConstants.PROPERTY_LOCKDISCOVERY, DavConstants.NAMESPACE);
+ if (!DomUtil.hasChildElement(lde, DavConstants.XML_ACTIVELOCK, DavConstants.NAMESPACE)) {
+ throw new DavException(response.getStatusLine().getStatusCode(),
+ "The DAV:lockdiscovery must contain a least a single DAV:activelock in response to a successful LOCK request.");
+ }
+
+ return LockDiscovery.createFromXml(lde);
+ } catch (IOException ex) {
+ throw new DavException(response.getStatusLine().getStatusCode(), ex);
+ }
+ }
+
+ /**
+ * Return response body as {@link SubscriptionDiscovery} object.
+ * @throws IllegalStateException when response does not represent a {@link SubscriptionDiscovery}
+ * @throws DavException for failures in obtaining/parsing the response body
+ */
+ public SubscriptionDiscovery getResponseBodyAsSubscriptionDiscovery(HttpResponse response) throws DavException {
+ try {
+ Document doc = getResponseBodyAsDocument(response.getEntity());
+ if (doc == null) {
+ throw new DavException(response.getStatusLine().getStatusCode(), "no response body");
+ }
+ Element root = doc.getDocumentElement();
+
+ if (!DomUtil.matches(root, DavConstants.XML_PROP, DavConstants.NAMESPACE)
+ && DomUtil.hasChildElement(root, ObservationConstants.SUBSCRIPTIONDISCOVERY.getName(),
+ ObservationConstants.SUBSCRIPTIONDISCOVERY.getNamespace())) {
+ throw new DavException(response.getStatusLine().getStatusCode(),
+ "Missing DAV:prop response body in SUBSCRIBE response.");
+ }
+
+ Element sde = DomUtil.getChildElement(root, ObservationConstants.SUBSCRIPTIONDISCOVERY.getName(),
+ ObservationConstants.SUBSCRIPTIONDISCOVERY.getNamespace());
+ SubscriptionDiscovery sd = SubscriptionDiscovery.createFromXml(sde);
+ if (((Subscription[]) sd.getValue()).length > 0) {
+ return sd;
+ } else {
+ throw new DavException(response.getStatusLine().getStatusCode(),
+ "Missing 'subscription' elements in SUBSCRIBE response body. At least a single subscription must be present if SUBSCRIBE was successful.");
+ }
+ } catch (IOException ex) {
+ throw new DavException(response.getStatusLine().getStatusCode(), ex);
+ }
+ }
+
+ /**
+ * Return response body as {@link EventDiscovery} object.
+ * @throws IllegalStateException when response does not represent a {@link EventDiscovery}
+ * @throws DavException for failures in obtaining/parsing the response body
+ */
+ public EventDiscovery getResponseBodyAsEventDiscovery(HttpResponse response) throws DavException {
+ try {
+ Document doc = getResponseBodyAsDocument(response.getEntity());
+ if (doc == null) {
+ throw new DavException(response.getStatusLine().getStatusCode(), "no response body");
+ }
+ return EventDiscovery.createFromXml(doc.getDocumentElement());
+ } catch (IOException ex) {
+ throw new DavException(response.getStatusLine().getStatusCode(), ex);
+ }
+ }
+
+ /**
+ * Check the response and throw when it is considered to represent a failure.
+ */
+ public void checkSuccess(HttpResponse response) throws DavException {
+ if (!succeeded(response)) {
+ throw getResponseException(response);
+ }
+ }
+
+ /**
+ * Obtain a {@link DavException} representing the response.
+ * @throws IllegalStateException when the response is considered to be successful
+ */
+ public DavException getResponseException(HttpResponse response) {
+ if (succeeded(response)) {
+ String msg = "Cannot retrieve exception from successful response.";
+ log.warn(msg);
+ throw new IllegalStateException(msg);
+ }
+
+ StatusLine st = response.getStatusLine();
+ Element responseRoot = null;
+ try {
+ responseRoot = getResponseBodyAsDocument(response.getEntity()).getDocumentElement();
+ } catch (IOException e) {
+ // non-parseable body -> use null element
+ }
+
+ return new DavException(st.getStatusCode(), st.getReasonPhrase(), null, responseRoot);
+ }
+
+ /**
+ * Check the provided {@link HttpResponse} for successful execution. The default implementation treats all
+ * 2xx status codes (<a href="http://webdav.org/specs/rfc7231.html#rfc.section.6.3">RFC 7231, Section 6.3</a>).
+ * Implementations can further restrict the accepted range of responses (or even check the response body).
+ */
+ public boolean succeeded(HttpResponse response) {
+ int status = response.getStatusLine().getStatusCode();
+ return status >= 200 && status <= 299;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpBind.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpBind.java
new file mode 100644
index 000000000..4c2161810
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpBind.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.bind.BindInfo;
+
+/**
+ * Represents an HTTP BIND request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc5842.html#rfc.section.4">RFC 5842, Section 4</a>
+ * @since 2.13.6
+ */
+public class HttpBind extends BaseDavRequest {
+
+ public HttpBind(URI uri, BindInfo info) throws IOException {
+ super(uri);
+ super.setEntity(XmlEntity.create(info));
+ }
+
+ public HttpBind(String uri, BindInfo info) throws IOException {
+ this(URI.create(uri), info);
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_BIND;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_OK || statusCode == DavServletResponse.SC_CREATED;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpCheckin.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpCheckin.java
new file mode 100644
index 000000000..06b67aec0
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpCheckin.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+
+/**
+ * Represents an HTTP CHECKIN request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc3253.html#rfc.section.4.4">RFC 3253, Section 4.4</a>
+ * @since 2.13.6
+ */
+public class HttpCheckin extends BaseDavRequest {
+
+ public HttpCheckin(URI uri) {
+ super(uri);
+ }
+
+ public HttpCheckin(String uri) {
+ this(URI.create(uri));
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_CHECKIN;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_CREATED;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpCheckout.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpCheckout.java
new file mode 100644
index 000000000..a7f5e009b
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpCheckout.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+
+/**
+ * Represents an HTTP CHECKOUT request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc3253.html#rfc.section.4.3">RFC 3253, Section 4.3</a>
+ * @since 2.13.6
+ */
+public class HttpCheckout extends BaseDavRequest {
+
+ public HttpCheckout(URI uri) {
+ super(uri);
+ }
+
+ public HttpCheckout(String uri) {
+ this(URI.create(uri));
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_CHECKOUT;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_OK;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpCopy.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpCopy.java
new file mode 100644
index 000000000..4f5337b87
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpCopy.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavConstants;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+
+/**
+ * Represents an HTTP COPY request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc4918.html#rfc.section.9.8">RFC 4918, Section 9.8</a>
+ * @since 2.13.6
+ */
+public class HttpCopy extends BaseDavRequest {
+
+ public HttpCopy(URI uri, URI dest, boolean overwrite, boolean shallow) {
+ super(uri);
+ super.setHeader(DavConstants.HEADER_DESTINATION, dest.toASCIIString());
+ if (!overwrite) {
+ super.setHeader(DavConstants.HEADER_OVERWRITE, "F");
+ }
+ if (shallow) {
+ super.setHeader("Depth", "0");
+ }
+ }
+
+ public HttpCopy(String uri, String dest, boolean overwrite, boolean shallow) {
+ this(URI.create(uri), URI.create(dest), overwrite, shallow);
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_COPY;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_CREATED || statusCode == DavServletResponse.SC_NO_CONTENT;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpDelete.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpDelete.java
new file mode 100644
index 000000000..99c283bab
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpDelete.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.net.URI;
+
+import org.apache.jackrabbit.webdav.DavMethods;
+
+/**
+ * Represents an HTTP DELETE request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc7231.html#rfc.section.4.3.5">RFC 7231, Section 4.3.5</a>
+ * @since 2.13.6
+ */
+public class HttpDelete extends BaseDavRequest {
+
+ public HttpDelete(URI uri){
+ super(uri);
+ }
+
+ public HttpDelete(String uri) {
+ this(URI.create(uri));
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_DELETE;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpLabel.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpLabel.java
new file mode 100644
index 000000000..05c6f48ce
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpLabel.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.header.DepthHeader;
+import org.apache.jackrabbit.webdav.version.LabelInfo;
+
+/**
+ * Represents an HTTP LABEL request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc3253.html#rfc.section.8.2">RFC 3253, Section 8.2</a>
+ * @since 2.13.6
+ */
+public class HttpLabel extends BaseDavRequest {
+
+ public HttpLabel(URI uri, LabelInfo labelInfo) throws IOException {
+ super(uri);
+ DepthHeader dh = new DepthHeader(labelInfo.getDepth());
+ super.setHeader(dh.getHeaderName(), dh.getHeaderValue());
+ super.setEntity(XmlEntity.create(labelInfo));
+ }
+
+ public HttpLabel(String uri, LabelInfo labelInfo) throws IOException {
+ this(URI.create(uri), labelInfo);
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_LABEL;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_OK;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpLock.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpLock.java
new file mode 100644
index 000000000..171776d17
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpLock.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Arrays;
+
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavConstants;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.header.DepthHeader;
+import org.apache.jackrabbit.webdav.header.IfHeader;
+import org.apache.jackrabbit.webdav.header.TimeoutHeader;
+import org.apache.jackrabbit.webdav.lock.LockInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Represents an HTTP LOCK request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc4918.html#rfc.section.9.10">RFC 4918, Section 9.10</a>
+ * @since 2.13.6
+ */
+public class HttpLock extends BaseDavRequest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(HttpLock.class);
+
+ private final boolean isRefresh;
+
+ public HttpLock(URI uri, LockInfo lockInfo) throws IOException {
+ super(uri);
+
+ TimeoutHeader th = new TimeoutHeader(lockInfo.getTimeout());
+ super.setHeader(th.getHeaderName(), th.getHeaderValue());
+ DepthHeader dh = new DepthHeader(lockInfo.isDeep());
+ super.setHeader(dh.getHeaderName(), dh.getHeaderValue());
+
+ super.setEntity(XmlEntity.create(lockInfo));
+
+ isRefresh = false;
+ }
+
+ public HttpLock(String uri, LockInfo lockInfo) throws IOException {
+ this(URI.create(uri), lockInfo);
+ }
+
+ public HttpLock(URI uri, long timeout, String[] lockTokens) {
+ super(uri);
+
+ TimeoutHeader th = new TimeoutHeader(timeout);
+ super.setHeader(th.getHeaderName(), th.getHeaderValue());
+ IfHeader ifh = new IfHeader(lockTokens);
+ super.setHeader(ifh.getHeaderName(), ifh.getHeaderValue());
+ isRefresh = true;
+ }
+
+ public HttpLock(String uri, long timeout, String[] lockTokens) {
+ this(URI.create(uri), timeout, lockTokens);
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_LOCK;
+ }
+
+ public String getLockToken(HttpResponse response) {
+ Header[] ltHeader = response.getHeaders(DavConstants.HEADER_LOCK_TOKEN);
+ if (ltHeader == null || ltHeader.length == 0) {
+ return null;
+ } else if (ltHeader.length != 1) {
+ LOG.debug("Multiple 'Lock-Token' header fields in response for " + getURI() + ": " + Arrays.asList(ltHeader));
+ return null;
+ } else {
+ String v = ltHeader[0].getValue().trim();
+ if (!v.startsWith("<") || !v.endsWith(">")) {
+ LOG.debug("Invalid 'Lock-Token' header field in response for " + getURI() + ": " + Arrays.asList(ltHeader));
+ return null;
+ } else {
+ return v.substring(1, v.length() - 1);
+ }
+ }
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ boolean lockTokenHeaderOk = isRefresh || null != getLockToken(response);
+ return lockTokenHeaderOk && (statusCode == DavServletResponse.SC_OK || statusCode == DavServletResponse.SC_CREATED);
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpMerge.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpMerge.java
new file mode 100644
index 000000000..b8db71dcf
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpMerge.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.version.MergeInfo;
+
+/**
+ * Represents an HTTP MERGE request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc3253.html#rfc.section.11.2">RFC 3253, Section 11.2</a>
+ * @since 2.13.6
+ */
+public class HttpMerge extends BaseDavRequest {
+
+ public HttpMerge(URI uri, MergeInfo mergeInfo) throws IOException {
+ super(uri);
+ super.setEntity(XmlEntity.create(mergeInfo));
+ }
+
+ public HttpMerge(String uri, MergeInfo mergeInfo) throws IOException {
+ this(URI.create(uri), mergeInfo);
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_MERGE;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ // TODO: is this correct?
+ return statusCode == DavServletResponse.SC_MULTI_STATUS;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpMkcol.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpMkcol.java
new file mode 100644
index 000000000..5ecf6a237
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpMkcol.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+
+/**
+ * Represents an HTTP MKCOL request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc4918.html#rfc.section.9.3">RFC 4918, Section 9.3</a>
+ * @since 2.13.6
+ */
+public class HttpMkcol extends BaseDavRequest {
+
+ public HttpMkcol(URI uri) {
+ super(uri);
+ }
+
+ public HttpMkcol(String uri) {
+ this(URI.create(uri));
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_MKCOL;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_CREATED;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpMkworkspace.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpMkworkspace.java
new file mode 100644
index 000000000..1c14fe52a
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpMkworkspace.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+
+/**
+ * Represents an HTTP MKWORKSPACE request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc3253.html#rfc.section.6.3">RFC 3253, Section 6.3</a>
+ * @since 2.13.6
+ */
+public class HttpMkworkspace extends BaseDavRequest {
+
+ public HttpMkworkspace(URI uri) {
+ super(uri);
+ }
+
+ public HttpMkworkspace(String uri) {
+ this(URI.create(uri));
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_MKWORKSPACE;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_CREATED;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpMove.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpMove.java
new file mode 100644
index 000000000..2411e0891
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpMove.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavConstants;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+
+/**
+ * Represents an HTTP MOVE request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc4918.html#rfc.section.9.9">RFC 4918, Section 9.9</a>
+ * @since 2.13.6
+ */
+public class HttpMove extends BaseDavRequest {
+
+ public HttpMove(URI uri, URI dest, boolean overwrite) {
+ super(uri);
+ super.setHeader(DavConstants.HEADER_DESTINATION, dest.toASCIIString());
+ if (!overwrite) {
+ super.setHeader(DavConstants.HEADER_OVERWRITE, "F");
+ }
+ }
+
+ public HttpMove(String uri, String dest, boolean overwrite) {
+ this(URI.create(uri), URI.create(dest), overwrite);
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_MOVE;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_CREATED || statusCode == DavServletResponse.SC_NO_CONTENT;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpOptions.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpOptions.java
new file mode 100644
index 000000000..4986ee2b9
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpOptions.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavConstants;
+import org.apache.jackrabbit.webdav.header.FieldValueParser;
+import org.apache.jackrabbit.webdav.search.SearchConstants;
+
+/**
+ * Represents an HTTP OPTIONS request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc7231.html#rfc.section.4.3.7">RFC 7231, Section 4.3.7</a>
+ * @since 2.13.6
+ */
+public class HttpOptions extends org.apache.http.client.methods.HttpOptions {
+
+ public HttpOptions(URI uri) {
+ super(uri);
+ }
+
+ public HttpOptions(String uri) {
+ super(URI.create(uri));
+ }
+
+ /**
+ * Compute the set of compliance classes returned in the "dav" header field
+ */
+ public Set<String> getDavComplianceClasses(HttpResponse response) {
+ Header[] headers = response.getHeaders(DavConstants.HEADER_DAV);
+ return parseTokenOrCodedUrlheaderField(headers, false);
+ }
+
+ /**
+ * Compute set of search grammars returned in the "dasl" header field
+ */
+ public Set<String> getSearchGrammars(HttpResponse response) {
+ Header[] headers = response.getHeaders(SearchConstants.HEADER_DASL);
+ return parseTokenOrCodedUrlheaderField(headers, true);
+ }
+
+ private Set<String> parseTokenOrCodedUrlheaderField(Header[] headers, boolean removeBrackets) {
+ if (headers == null) {
+ return Collections.emptySet();
+ }
+ else {
+ Set<String> result = new HashSet<String>();
+ for (Header h : headers) {
+ for (String s : FieldValueParser.tokenizeList(h.getValue())) {
+ if (removeBrackets && s.startsWith("<") && s.endsWith(">")) {
+ s = s.substring(1, s.length() - 1);
+ }
+ result.add(s.trim());
+ }
+ }
+ return Collections.unmodifiableSet(result);
+ }
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpOrderpatch.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpOrderpatch.java
new file mode 100644
index 000000000..0e6f0fbf0
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpOrderpatch.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.ordering.OrderPatch;
+
+/**
+ * Represents an HTTP ORDERPATCH request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc3648.html#rfc.section.5">RFC 3648, Section 5</a>
+ * @since 2.13.6
+ */
+public class HttpOrderpatch extends BaseDavRequest {
+
+ public HttpOrderpatch(URI uri, OrderPatch info) throws IOException {
+ super(uri);
+ super.setEntity(XmlEntity.create(info));
+ }
+
+ public HttpOrderpatch(String uri, OrderPatch info) throws IOException {
+ this(URI.create(uri), info);
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_ORDERPATCH;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ return response.getStatusLine().getStatusCode() == DavServletResponse.SC_OK;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpPoll.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpPoll.java
new file mode 100644
index 000000000..af7d62084
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpPoll.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.header.PollTimeoutHeader;
+import org.apache.jackrabbit.webdav.observation.ObservationConstants;
+
+/**
+ * Represents an HTTP POLL request.
+ * <p>
+ * Note that "POLL" is a custom HTTP extension, not defined in a standards paper.
+ * @since 2.13.6
+ */
+public class HttpPoll extends BaseDavRequest {
+
+ public HttpPoll(URI uri, String subscriptionId, long timeout) {
+ super(uri);
+ super.setHeader(ObservationConstants.HEADER_SUBSCRIPTIONID, subscriptionId);
+ if (timeout > 0) {
+ PollTimeoutHeader th = new PollTimeoutHeader(timeout);
+ super.setHeader(th.getHeaderName(), th.getHeaderValue());
+ }
+ }
+
+ public HttpPoll(String uri, String subscriptionId, long timeout) {
+ this(URI.create(uri), subscriptionId, timeout);
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_POLL;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_OK;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpPropfind.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpPropfind.java
new file mode 100644
index 000000000..e548db069
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpPropfind.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavConstants;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.header.DepthHeader;
+import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
+import org.apache.jackrabbit.webdav.property.PropfindInfo;
+
+/**
+ * Represents an HTTP PROPFIND request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc4918.html#rfc.section.9.1">RFC 4918, Section 9.1</a>
+ * @since 2.13.6
+ */
+public class HttpPropfind extends BaseDavRequest {
+
+ public HttpPropfind(URI uri, int propfindType, DavPropertyNameSet names, int depth) throws IOException {
+ super(uri);
+
+ DepthHeader dh = new DepthHeader(depth);
+ super.setHeader(dh.getHeaderName(), dh.getHeaderValue());
+
+ PropfindInfo info = new PropfindInfo(propfindType, names);
+ super.setEntity(XmlEntity.create(info));
+ }
+
+ public HttpPropfind(URI uri, DavPropertyNameSet names, int depth) throws IOException {
+ this(uri, DavConstants.PROPFIND_BY_PROPERTY, names, depth);
+ }
+
+ public HttpPropfind(URI uri, int propfindType, int depth) throws IOException {
+ this(uri, propfindType, new DavPropertyNameSet(), depth);
+ }
+
+ public HttpPropfind(String uri, int propfindType, int depth) throws IOException {
+ this(URI.create(uri), propfindType, depth);
+ }
+
+ public HttpPropfind(String uri, int propfindType, DavPropertyNameSet names, int depth) throws IOException {
+ this(URI.create(uri), propfindType, names, depth);
+ }
+
+ public HttpPropfind(String uri, DavPropertyNameSet names, int depth) throws IOException {
+ this(URI.create(uri), names, depth);
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_PROPFIND;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ return response.getStatusLine().getStatusCode() == DavServletResponse.SC_MULTI_STATUS;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpProppatch.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpProppatch.java
new file mode 100644
index 000000000..2cd35f8f0
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpProppatch.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
+import org.apache.jackrabbit.webdav.property.DavPropertySet;
+import org.apache.jackrabbit.webdav.property.PropEntry;
+import org.apache.jackrabbit.webdav.property.ProppatchInfo;
+
+/**
+ * Represents an HTTP PROPPATCH request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc4918.html#rfc.section.9.2">RFC 4918, Section 9.2</a>
+ * @since 2.13.6
+ */
+public class HttpProppatch extends BaseDavRequest {
+
+ // private DavPropertyNameSet propertyNames;
+
+ public HttpProppatch(URI uri, ProppatchInfo info) throws IOException {
+ super(uri);
+ super.setEntity(XmlEntity.create(info));
+ // this.propertyNames = info.getAffectedProperties();
+ }
+
+ public HttpProppatch(URI uri, List<? extends PropEntry> changeList) throws IOException {
+ this(uri, new ProppatchInfo(changeList));
+ }
+
+ public HttpProppatch(URI uri, DavPropertySet setProperties, DavPropertyNameSet removeProperties) throws IOException {
+ this(uri, new ProppatchInfo(setProperties, removeProperties));
+ }
+
+ public HttpProppatch(String uri, List<? extends PropEntry> changeList) throws IOException {
+ this(URI.create(uri), new ProppatchInfo(changeList));
+ }
+
+ public HttpProppatch(String uri, DavPropertySet setProperties, DavPropertyNameSet removeProperties) throws IOException {
+ this(URI.create(uri), new ProppatchInfo(setProperties, removeProperties));
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_PROPPATCH;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ return response.getStatusLine().getStatusCode() == DavServletResponse.SC_MULTI_STATUS;
+
+ // disabled code that fails for current PROPPATCH behavior of Jackrabbit
+// MultiStatusResponse responses[] = super.getResponseBodyAsMultiStatus(response).getResponses();
+// if (responses.length != 1) {
+// throw new DavException(DavServletResponse.SC_MULTI_STATUS,
+// "PROPPATCH failed: Expected exactly one multistatus response element, but got " + responses.length);
+// }
+// DavPropertyNameSet okSet = responses[0].getPropertyNames(DavServletResponse.SC_OK);
+// if (okSet.isEmpty()) {
+// throw new DavException(DavServletResponse.SC_MULTI_STATUS,
+// "PROPPATCH failed: No 'OK' response found for resource " + responses[0].getHref());
+// } else {
+// DavPropertyNameIterator it = propertyNames.iterator();
+// while (it.hasNext()) {
+// DavPropertyName pn = it.nextPropertyName();
+// boolean success = okSet.remove(pn);
+// if (!success) {
+// throw new DavException(DavServletResponse.SC_MULTI_STATUS,
+// "PROPPATCH failed: Property name not present in multistatus response: " + pn);
+// }
+// }
+// }
+// if (!okSet.isEmpty()) {
+// StringBuilder b = new StringBuilder();
+// DavPropertyNameIterator it = okSet.iterator();
+// while (it.hasNext()) {
+// b.append(it.nextPropertyName().toString()).append("; ");
+// }
+// throw new DavException(DavServletResponse.SC_MULTI_STATUS,
+// "PROPPATCH failed: The following properties outside of the original request where set or removed: " + b.toString());
+// }
+// return true;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpRebind.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpRebind.java
new file mode 100644
index 000000000..e72dea890
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpRebind.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.bind.RebindInfo;
+
+/**
+ * Represents an HTTP REBIND request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc5842.html#rfc.section.6">RFC 5842, Section 6</a>
+ * @since 2.13.6
+ */
+public class HttpRebind extends BaseDavRequest {
+
+ public HttpRebind(URI uri, RebindInfo info) throws IOException {
+ super(uri);
+ super.setEntity(XmlEntity.create(info));
+ }
+
+ public HttpRebind(String uri, RebindInfo info) throws IOException {
+ this(URI.create(uri), info);
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_REBIND;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_OK || statusCode == DavServletResponse.SC_CREATED;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpReport.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpReport.java
new file mode 100644
index 000000000..efb20b6ca
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpReport.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavConstants;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.header.DepthHeader;
+import org.apache.jackrabbit.webdav.version.report.ReportInfo;
+
+/**
+ * Represents an HTTP REPORT request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc3253.html#rfc.section.3.6">RFC 3253, Section 3.6</a>
+ * @since 2.13.6
+ */
+public class HttpReport extends BaseDavRequest {
+
+ private final boolean isDeep;
+
+ public HttpReport(URI uri, ReportInfo reportInfo) throws IOException {
+ super(uri);
+ DepthHeader dh = new DepthHeader(reportInfo.getDepth());
+ isDeep = reportInfo.getDepth() > DavConstants.DEPTH_0;
+ super.setHeader(dh.getHeaderName(), dh.getHeaderValue());
+ super.setEntity(XmlEntity.create(reportInfo));
+ }
+
+ public HttpReport(String uri, ReportInfo reportInfo) throws IOException {
+ this(URI.create(uri), reportInfo);
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_REPORT;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ if (isDeep) {
+ return statusCode == DavServletResponse.SC_MULTI_STATUS;
+ } else {
+ return statusCode == DavServletResponse.SC_OK || statusCode == DavServletResponse.SC_MULTI_STATUS;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpSearch.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpSearch.java
new file mode 100644
index 000000000..f230f2dfb
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpSearch.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.search.SearchInfo;
+
+/**
+ * Represents an HTTP SEARCH request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc5323.html#rfc.section.2">RFC 5323, Section 2</a>
+ * @since 2.13.6
+ */
+public class HttpSearch extends BaseDavRequest {
+
+ public HttpSearch(URI uri, SearchInfo searchInfo) throws IOException {
+ super(uri);
+ super.setEntity(XmlEntity.create(searchInfo));
+ }
+
+ public HttpSearch(String uri, SearchInfo searchInfo) throws IOException {
+ this(URI.create(uri), searchInfo);
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_SEARCH;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_MULTI_STATUS;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpSubscribe.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpSubscribe.java
new file mode 100644
index 000000000..6bdbb7adc
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpSubscribe.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavConstants;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.header.CodedUrlHeader;
+import org.apache.jackrabbit.webdav.header.DepthHeader;
+import org.apache.jackrabbit.webdav.header.TimeoutHeader;
+import org.apache.jackrabbit.webdav.observation.ObservationConstants;
+import org.apache.jackrabbit.webdav.observation.SubscriptionInfo;
+
+/**
+ * Represents an HTTP SUBSCRIBE request.
+ * <p>
+ * Note that "SUBSCRIBE" is a custom HTTP extension, not defined in a standards paper.
+ * @since 2.13.6
+ */
+public class HttpSubscribe extends BaseDavRequest {
+
+ public HttpSubscribe(URI uri, SubscriptionInfo info, String subscriptionId) throws IOException {
+ super(uri);
+ if (info == null) {
+ throw new IllegalArgumentException("SubscriptionInfo must not be null.");
+ }
+ // optional subscriptionId (only required to modify an existing
+ // subscription)
+ if (subscriptionId != null) {
+ CodedUrlHeader h = new CodedUrlHeader(ObservationConstants.HEADER_SUBSCRIPTIONID, subscriptionId);
+ super.setHeader(h.getHeaderName(), h.getHeaderValue());
+ }
+ // optional timeout header
+ long to = info.getTimeOut();
+ if (to != DavConstants.UNDEFINED_TIMEOUT) {
+ TimeoutHeader h = new TimeoutHeader(info.getTimeOut());
+ super.setHeader(h.getHeaderName(), h.getHeaderValue());
+ }
+ // always set depth header since value is boolean flag
+ DepthHeader dh = new DepthHeader(info.isDeep());
+ super.setHeader(dh.getHeaderName(), dh.getHeaderValue());
+ super.setEntity(XmlEntity.create(info));
+ }
+
+ public HttpSubscribe(String uri, SubscriptionInfo info, String subscriptionId) throws IOException {
+ this(URI.create(uri), info, subscriptionId);
+ }
+
+ public String getSubscriptionId(HttpResponse response) {
+ org.apache.http.Header sbHeader = response.getFirstHeader(ObservationConstants.HEADER_SUBSCRIPTIONID);
+ if (sbHeader != null) {
+ CodedUrlHeader cuh = new CodedUrlHeader(ObservationConstants.HEADER_SUBSCRIPTIONID, sbHeader.getValue());
+ return cuh.getCodedUrl();
+ }
+ else {
+ return null;
+ }
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_SUBSCRIBE;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_OK;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpUnbind.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpUnbind.java
new file mode 100644
index 000000000..10e7f4a5b
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpUnbind.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.bind.UnbindInfo;
+
+/**
+ * Represents an HTTP UNBIND request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc5842.html#rfc.section.5">RFC 5842, Section 5</a>
+ * @since 2.13.6
+ */
+public class HttpUnbind extends BaseDavRequest {
+
+ public HttpUnbind(URI uri, UnbindInfo info) throws IOException {
+ super(uri);
+ super.setEntity(XmlEntity.create(info));
+ }
+
+ public HttpUnbind(String uri, UnbindInfo info) throws IOException {
+ this(URI.create(uri), info);
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_UNBIND;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_OK || statusCode == DavServletResponse.SC_NO_CONTENT;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpUnlock.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpUnlock.java
new file mode 100644
index 000000000..aee347365
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpUnlock.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavConstants;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.header.CodedUrlHeader;
+
+/**
+ * Represents an HTTP UNLOCK request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc4918.html#rfc.section.9.11">RFC 4918, Section 9.11</a>
+ * @since 2.13.6
+ */
+public class HttpUnlock extends BaseDavRequest {
+
+ public HttpUnlock(URI uri, String lockToken) {
+ super(uri);
+ CodedUrlHeader lth = new CodedUrlHeader(DavConstants.HEADER_LOCK_TOKEN, lockToken);
+ super.setHeader(lth.getHeaderName(), lth.getHeaderValue());
+ }
+
+ public HttpUnlock(String uri, String lockToken) {
+ this(URI.create(uri), lockToken);
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_UNLOCK;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_OK || statusCode == DavServletResponse.SC_NO_CONTENT;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpUnsubscribe.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpUnsubscribe.java
new file mode 100644
index 000000000..522f17fce
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpUnsubscribe.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.observation.ObservationConstants;
+
+/**
+ * Represents an HTTP UNSUBSCRIBE request.
+ * <p>
+ * Note that "UNSUBSCRIBE" is a custom HTTP extension, not defined in a standards paper.
+ * @since 2.13.6
+ */
+public class HttpUnsubscribe extends BaseDavRequest {
+
+ public HttpUnsubscribe(URI uri, String subscriptionId) {
+ super(uri);
+ super.setHeader(ObservationConstants.HEADER_SUBSCRIPTIONID, subscriptionId);
+ }
+
+ public HttpUnsubscribe(String uri, String subscriptionId) {
+ this(URI.create(uri), subscriptionId);
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_UNSUBSCRIBE;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_NO_CONTENT;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpUpdate.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpUpdate.java
new file mode 100644
index 000000000..019a24fff
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpUpdate.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.version.UpdateInfo;
+
+/**
+ * Represents an HTTP UPDATE request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc3253.html#rfc.section.7.1">RFC 3253, Section 7.1</a>
+ * @since 2.13.6
+ */
+public class HttpUpdate extends BaseDavRequest {
+
+ public HttpUpdate(URI uri, UpdateInfo updateInfo) throws IOException {
+ super(uri);
+ super.setEntity(XmlEntity.create(updateInfo));
+ }
+
+ public HttpUpdate(String uri, UpdateInfo updateInfo) throws IOException {
+ this(URI.create(uri), updateInfo);
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_UPDATE;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_MULTI_STATUS;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpVersionControl.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpVersionControl.java
new file mode 100644
index 000000000..e23a601be
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/HttpVersionControl.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.net.URI;
+
+import org.apache.http.HttpResponse;
+import org.apache.jackrabbit.webdav.DavMethods;
+import org.apache.jackrabbit.webdav.DavServletResponse;
+
+/**
+ * Represents an HTTP VERSION-CONTROL request.
+ *
+ * @see <a href="http://webdav.org/specs/rfc3253.html#rfc.section.3.5">RFC 3253, Section 3.5</a>
+ * @since 2.13.6
+ */
+public class HttpVersionControl extends BaseDavRequest {
+
+ public HttpVersionControl(URI uri) {
+ super(uri);
+ }
+
+ public HttpVersionControl(String uri) {
+ this(URI.create(uri));
+ }
+
+ @Override
+ public String getMethod() {
+ return DavMethods.METHOD_VERSION_CONTROL;
+ }
+
+ @Override
+ public boolean succeeded(HttpResponse response) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ return statusCode == DavServletResponse.SC_OK;
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/XmlEntity.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/XmlEntity.java
new file mode 100644
index 000000000..859bbe404
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/XmlEntity.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.client.methods;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.entity.ContentType;
+import org.apache.jackrabbit.webdav.xml.DomUtil;
+import org.apache.jackrabbit.webdav.xml.XmlSerializable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+/**
+ * Utility methods for creating request entities from {@link Document}s or {@link XmlSerializable}s.
+ */
+public class XmlEntity {
+
+ private static Logger LOG = LoggerFactory.getLogger(XmlEntity.class);
+
+ private static ContentType CT = ContentType.create("application/xml", "UTF-8");
+
+ public static HttpEntity create(Document doc) throws IOException {
+ try {
+ ByteArrayOutputStream xml = new ByteArrayOutputStream();
+ DomUtil.transformDocument(doc, xml);
+ return new ByteArrayEntity(xml.toByteArray(), CT);
+ } catch (TransformerException ex) {
+ LOG.error(ex.getMessage());
+ throw new IOException(ex);
+ } catch (SAXException ex) {
+ LOG.error(ex.getMessage());
+ throw new IOException(ex);
+ }
+ }
+
+ public static HttpEntity create(XmlSerializable payload) throws IOException {
+ try {
+ Document doc = DomUtil.createDocument();
+ doc.appendChild(payload.toXml(doc));
+ return create(doc);
+ } catch (ParserConfigurationException ex) {
+ LOG.error(ex.getMessage());
+ throw new IOException(ex);
+ }
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/package-info.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/package-info.java
new file mode 100644
index 000000000..b667d39c6
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/client/methods/package-info.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Provides classes for use with the Apache HttpClient, supporting WebDAV
+ * request methods.
+ * <p>
+ * This version also contains classes for use with the obsolete "Commons
+ * HttpClient"; they have been marked "deprecated" and will be removed in the
+ * next major release.
+ *
+ * @see <a href="https://issues.apache.org/jira/browse/JCR-2406">JCR-2406</a>
+ * @see <a href=
+ * "https://hc.apache.org/httpcomponents-client-4.5.x/">https://hc.apache.org/httpcomponents-client-4.5.x/</a>
+ */
+@org.osgi.annotation.versioning.Version("2.0.0")
+package org.apache.jackrabbit.webdav.client.methods;
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/CodedUrlHeader.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/CodedUrlHeader.java
new file mode 100644
index 000000000..edbe8aed9
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/CodedUrlHeader.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.header;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+/**
+ * <code>CodedUrlHeader</code>...
+ */
+public class CodedUrlHeader implements Header {
+
+ private static Logger log = LoggerFactory.getLogger(CodedUrlHeader.class);
+
+ private final String headerName;
+ private final String headerValue;
+
+ public CodedUrlHeader(String headerName, String headerValue) {
+ this.headerName = headerName;
+ if (headerValue != null && !(headerValue.startsWith("<") && headerValue.endsWith(">"))) {
+ headerValue = "<" + headerValue + ">";
+ }
+ this.headerValue = headerValue;
+ }
+
+ /**
+ * Return the name of the header
+ *
+ * @return header name
+ * @see Header#getHeaderName()
+ */
+ public String getHeaderName() {
+ return headerName;
+ }
+
+ /**
+ * Return the value of the header
+ *
+ * @return value
+ * @see Header#getHeaderValue()
+ */
+ public String getHeaderValue() {
+ return headerValue;
+ }
+
+ /**
+ * Returns the token present in the header value or <code>null</code>.
+ * If the header contained multiple tokens separated by ',' the first value
+ * is returned.
+ *
+ * @return token present in the CodedURL header or <code>null</code> if
+ * the header is not present.
+ * @see #getCodedUrls()
+ */
+ public String getCodedUrl() {
+ String[] codedUrls = getCodedUrls();
+ return (codedUrls != null) ? codedUrls[0] : null;
+ }
+
+ /**
+ * Return an array of coded urls as present in the header value or <code>null</code> if
+ * no value is present.
+ *
+ * @return array of coded urls
+ */
+ public String[] getCodedUrls() {
+ String[] codedUrls = null;
+ if (headerValue != null) {
+ String[] values = headerValue.split(",");
+ codedUrls = new String[values.length];
+ for (int i = 0; i < values.length; i++) {
+ int p1 = values[i].indexOf('<');
+ if (p1<0) {
+ throw new IllegalArgumentException("Invalid CodedURL header value:" + values[i]);
+ }
+ int p2 = values[i].indexOf('>', p1);
+ if (p2<0) {
+ throw new IllegalArgumentException("Invalid CodedURL header value:" + values[i]);
+ }
+ codedUrls[i] = values[i].substring(p1+1, p2);
+ }
+ }
+ return codedUrls;
+ }
+
+ /**
+ * Retrieves the header with the given name and builds a new <code>CodedUrlHeader</code>.
+ *
+ * @param request
+ * @param headerName
+ * @return new <code>CodedUrlHeader</code> instance
+ */
+ public static CodedUrlHeader parse(HttpServletRequest request, String headerName) {
+ String headerValue = request.getHeader(headerName);
+ return new CodedUrlHeader(headerName, headerValue);
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/DepthHeader.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/DepthHeader.java
new file mode 100644
index 000000000..9b74194a5
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/DepthHeader.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.header;
+
+import org.apache.jackrabbit.webdav.DavConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+/**
+ * <code>DepthHeader</code>...
+ */
+public class DepthHeader implements Header, DavConstants {
+
+ private static Logger log = LoggerFactory.getLogger(DepthHeader.class);
+
+ private final int depth;
+
+ /**
+ * Create a new <code>DepthHeader</code> from the given integer.
+ *
+ * @param depth
+ */
+ public DepthHeader(int depth) {
+ if (depth == DEPTH_0 || depth == DEPTH_1 || depth == DEPTH_INFINITY) {
+ this.depth = depth;
+ } else {
+ throw new IllegalArgumentException("Invalid depth: " + depth);
+ }
+ }
+
+ /**
+ * Create a new <code>DepthHeader</code> with either value {@link #DEPTH_0 0}
+ * or {@link #DEPTH_INFINITY infinity}.
+ *
+ * @param isDeep
+ */
+ public DepthHeader(boolean isDeep) {
+ this.depth = (isDeep) ? DEPTH_INFINITY : DEPTH_0;
+ }
+
+ /**
+ * @return integer representation of the depth indicated by the given header.
+ */
+ public int getDepth() {
+ return depth;
+ }
+
+ /**
+ * Return {@link DavConstants#HEADER_DEPTH Depth}
+ *
+ * @return {@link DavConstants#HEADER_DEPTH Depth}
+ * @see DavConstants#HEADER_DEPTH
+ * @see Header#getHeaderName()
+ */
+ public String getHeaderName() {
+ return DavConstants.HEADER_DEPTH;
+ }
+
+ /**
+ * Returns the header value.
+ *
+ * @return header value
+ * @see Header#getHeaderValue()
+ */
+ public String getHeaderValue() {
+ if (depth == DavConstants.DEPTH_0 || depth == DavConstants.DEPTH_1) {
+ return String.valueOf(depth);
+ } else {
+ return DavConstants.DEPTH_INFINITY_S;
+ }
+ }
+
+ /**
+ * Retrieve the Depth header from the given request object and parse the
+ * value. If no header is present or the value is empty String, the
+ * defaultValue is used ot build a new <code>DepthHeader</code> instance.
+ *
+ * @param request
+ * @param defaultValue
+ * @return a new <code>DepthHeader</code> instance
+ */
+ public static DepthHeader parse(HttpServletRequest request, int defaultValue) {
+ String headerValue = request.getHeader(HEADER_DEPTH);
+ if (headerValue == null || "".equals(headerValue)) {
+ return new DepthHeader(defaultValue);
+ } else {
+ return new DepthHeader(depthToInt(headerValue));
+ }
+ }
+
+ /**
+ * Convert the String depth value to an integer.
+ *
+ * @param depth
+ * @return integer representation of the given depth String
+ * @throws IllegalArgumentException if the String does not represent a valid
+ * depth.
+ */
+ private static int depthToInt(String depth) {
+ int d;
+ if (depth.equalsIgnoreCase(DavConstants.DEPTH_INFINITY_S)) {
+ d = DavConstants.DEPTH_INFINITY;
+ } else if (depth.equals(DavConstants.DEPTH_0+"")) {
+ d = DavConstants.DEPTH_0;
+ } else if (depth.equals(DavConstants.DEPTH_1+"")) {
+ d = DavConstants.DEPTH_1;
+ } else {
+ throw new IllegalArgumentException("Invalid depth value: " + depth);
+ }
+ return d;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/FieldValueParser.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/FieldValueParser.java
new file mode 100644
index 000000000..6f3052168
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/FieldValueParser.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.header;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class FieldValueParser {
+
+ /**
+ * Tokenize lists of token and quoted-url
+ * @param list field value
+ */
+ public static List<String> tokenizeList(String list) {
+
+ String[] split = list.split(",");
+ if (split.length == 1) {
+ return Collections.singletonList(split[0].trim());
+ } else {
+ List<String> result = new ArrayList<String>();
+ String inCodedUrl = null;
+ for (String t : split) {
+ String trimmed = t.trim();
+ // handle quoted-url containing ","
+ if (trimmed.startsWith("<") && !trimmed.endsWith(">")) {
+ inCodedUrl = trimmed + ",";
+ } else if (inCodedUrl != null && trimmed.endsWith(">")) {
+ inCodedUrl += trimmed;
+ result.add(inCodedUrl);
+ inCodedUrl = null;
+ } else {
+ if (trimmed.length() != 0) {
+ result.add(trimmed);
+ }
+ }
+ }
+ return Collections.unmodifiableList(result);
+ }
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/Header.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/Header.java
new file mode 100644
index 000000000..f61a07e90
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/Header.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.header;
+
+/**
+ * <code>Header</code>...
+ */
+public interface Header {
+
+ public String getHeaderName();
+
+ public String getHeaderValue();
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/IfHeader.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/IfHeader.java
new file mode 100644
index 000000000..43ff4dbac
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/IfHeader.java
@@ -0,0 +1,905 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.header;
+
+import org.apache.jackrabbit.webdav.DavConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * The <code>IfHeader</code> class represents the state lists defined
+ * through the HTTP <em>If</em> header, which is specified in RFC 2518 as
+ * follows :
+ * <pre>
+ If = "If" ":" ( 1*No-tag-list | 1*Tagged-list)
+ No-tag-list = List
+ Tagged-list = Resource 1*List
+ Resource = Coded-URL
+ List = "(" 1*(["Not"](State-etag | "[" entity-tag "]")) ")"
+ State-etag = Coded-URL
+ Coded-URL = "<" absoluteURI ">"
+ * </pre>
+ * <p>
+ * Reformulating this specification into proper EBNF as specified by N. Wirth
+ * we get the following productions, which map to the parse METHODS of this
+ * class. Any whitespace is ignored except for white space surrounding and
+ * within words which is considered significant.
+ * <pre>
+ If = "If:" ( Tagged | Untagged ).
+ Tagged = { "<" Word ">" Untagged } .
+ Untagged = { "(" IfList ")" } .
+ IfList = { [ "Not" ] ( ("<" Word ">" ) | ( "[" Word "]" ) ) } .
+ Word = characters .
+ * </pre>
+ * <p>
+ * An <em>If</em> header either contains untagged <em>IfList</em> entries or
+ * tagged <em>IfList</em> entries but not a mixture of both. An <em>If</em>
+ * header containing tagged entries is said to be of <em>tagged</em> type while
+ * an <em>If</em> header containing untagged entries is said to be of
+ * <em>untagged</em> type.
+ * <p>
+ * An <em>IfList</em> is a list of tokens - words enclosed in <em>< ></em>
+ * - and etags - words enclosed in <em>[ ]</em>. An <em>IfList</em> matches a
+ * (token, etag) tuple if all entries in the list match. If an entry in the list
+ * is prefixed with the word <em>Not</em> (parsed case insensitively) the entry
+ * must not match the concrete token or etag.
+ * <p>
+ * Example: The <em>ifList</em> <code>(<token> [etag])</code> only matches
+ * if the concret token has the value <code>token</code> and the conrete etag
+ * has the value <code>etag</code>. On the other hand, the <em>ifList</em>
+ * <code>(Not <notoken>)</code> matches any token which is not
+ * <code>notoken</code> (in this case the concrete value of the etag is
+ * not taken into consideration).
+ *
+ * @author Felix Meschberger
+ */
+public class IfHeader implements Header {
+
+ /**
+ * default logger
+ */
+ private static final Logger log = LoggerFactory.getLogger(IfHeader.class);
+
+ /**
+ * The string representation of the header value
+ */
+ private final String headerValue;
+
+ /**
+ * The list of untagged state entries
+ */
+ private final IfHeaderInterface ifHeader;
+
+ /**
+ * The list of all positive tokens present in the If header.
+ */
+ private List<String> allTokens = new ArrayList<String>();
+ /**
+ * The list of all NOT tokens present in the If header.
+ */
+ private List<String> allNotTokens = new ArrayList<String>();
+
+ private String uriPrefix;
+
+ /**
+ * Create a Untagged <code>IfHeader</code> if the given lock tokens.
+ *
+ * @param tokens
+ */
+ public IfHeader(String[] tokens) {
+ allTokens.addAll(Arrays.asList(tokens));
+ StringBuffer b = new StringBuffer();
+ for (String token : tokens) {
+ b.append("(").append("<");
+ b.append(token);
+ b.append(">").append(")");
+ }
+ headerValue = b.toString();
+ ifHeader = parse();
+ }
+
+ /**
+ * Parses the <em>If</em> header and creates and internal representation
+ * which is easy to query.
+ *
+ * @param req The request object
+ */
+ public IfHeader(HttpServletRequest req) {
+ String host = req.getHeader("Host");
+ String scheme = req.getScheme();
+ uriPrefix = scheme + "://" + host + req.getContextPath();
+ headerValue = req.getHeader(DavConstants.HEADER_IF);
+ ifHeader = parse();
+ }
+
+ /**
+ * Return {@link DavConstants#HEADER_IF If}
+ *
+ * @return {@link DavConstants#HEADER_IF If}
+ * @see DavConstants#HEADER_IF
+ */
+ public String getHeaderName() {
+ return DavConstants.HEADER_IF;
+ }
+
+ /**
+ * Return the String representation of the If header present on
+ * the given request or <code>null</code>.
+ *
+ * @return If header value as String or <code>null</code>.
+ */
+ public String getHeaderValue() {
+ return headerValue;
+ }
+
+ /**
+ * Returns true if an If header was present in the given request. False otherwise.
+ *
+ * @return true if an If header was present.
+ */
+ public boolean hasValue() {
+ return ifHeader != null;
+ }
+
+ /**
+ * Tries to match the contents of the <em>If</em> header with the given
+ * token and etag values with the restriction to only check for the tag.
+ * <p>
+ * If the <em>If</em> header is of untagged type, the untagged <em>IfList</em>
+ * is matched against the token and etag given: A match of the token and
+ * etag is found if at least one of the <em>IfList</em> entries match the
+ * token and etag tuple.
+ *
+ * @param tag The tag to identify the <em>IfList</em> to match the token
+ * and etag against.
+ * @param token The token to compare.
+ * @param etag The ETag value to compare.
+ *
+ * @return If the <em>If</em> header is of untagged type the result is
+ * <code>true</code> if any of the <em>IfList</em> entries matches
+ * the token and etag values. For tagged type <em>If</em> header the
+ * result is <code>true</code> if either no entry for the given tag
+ * exists in the <em>If</em> header or if the <em>IfList</em> for the
+ * given tag matches the token and etag given.
+ */
+ public boolean matches(String tag, String token, String etag) {
+ if (ifHeader == null) {
+ log.debug("matches: No If header, assume match");
+ return true;
+ } else {
+ return ifHeader.matches(tag, token, etag);
+ }
+ }
+
+ /**
+ * @return an iterator over all tokens present in the if header, that were
+ * not denied by a leading NOT statement.
+ */
+ public Iterator<String> getAllTokens() {
+ return allTokens.iterator();
+ }
+
+ /**
+ * @return an iterator over all NOT tokens present in the if header, that
+ * were explicitly denied.
+ */
+ public Iterator<String> getAllNotTokens() {
+ return allNotTokens.iterator();
+ }
+
+ /**
+ * Parse the original header value and build the internal IfHeaderInterface
+ * object that is easy to query.
+ */
+ private IfHeaderInterface parse() {
+ IfHeaderInterface ifHeader;
+ if (headerValue != null && headerValue.length() > 0) {
+ StringReader reader = null;
+ int firstChar = 0;
+
+ try {
+ reader = new StringReader(headerValue);
+ // get the first character to decide - expect '(' or '<'
+ try {
+ reader.mark(1);
+ firstChar = readWhiteSpace(reader);
+ reader.reset();
+ } catch (IOException ignore) {
+ // may be thrown according to API but is only thrown by the
+ // StringReader class if the reader is already closed.
+ }
+
+ if (firstChar == '(') {
+ ifHeader = parseUntagged(reader);
+ } else if (firstChar == '<') {
+ ifHeader = parseTagged(reader);
+ } else {
+ logIllegalState("If", firstChar, "(<", null);
+ ifHeader = null;
+ }
+
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+
+ } else {
+ log.debug("IfHeader: No If header in request");
+ ifHeader = null;
+ }
+ return ifHeader;
+ }
+
+ //---------- internal IF header parser -------------------------------------
+ /**
+ * Parses a tagged type <em>If</em> header. This method implements the
+ * <em>Tagged</em> production given in the class comment :
+ * <pre>
+ Tagged = { "<" Word ">" Untagged } .
+ * </pre>
+ *
+ * @param reader
+ * @return
+ */
+ private IfHeaderMap parseTagged(StringReader reader) {
+ IfHeaderMap map = new IfHeaderMap();
+ try {
+ while (true) {
+ // read next non-white space
+ int c = readWhiteSpace(reader);
+ if (c < 0) {
+ // end of input, no more entries
+ break;
+ } else if (c == '<') {
+ // start a tag with an IfList
+ String resource = readWord(reader, '>');
+ if (resource != null) {
+ // go to untagged after reading the resource
+ map.put(resource, parseUntagged(reader));
+ } else {
+ break;
+ }
+ } else {
+ // unexpected character
+ // catchup to end of input or start of a tag
+ logIllegalState("Tagged", c, "<", reader);
+ }
+ }
+ } catch (IOException ioe) {
+ log.error("parseTagged: Problem parsing If header: "+ioe.toString());
+ }
+
+ return map;
+ }
+
+ /**
+ * Parses an untagged type <em>If</em> header. This method implements the
+ * <em>Untagged</em> production given in the class comment :
+ * <pre>
+ Untagged = { "(" IfList ")" } .
+ * </pre>
+ *
+ * @param reader The <code>StringReader</code> to read from for parsing
+ *
+ * @return An <code>ArrayList</code> of {@link IfList} entries.
+ */
+ private IfHeaderList parseUntagged(StringReader reader) {
+ IfHeaderList list = new IfHeaderList();
+ try {
+ while (true) {
+ // read next non white space
+ reader.mark(1);
+ int c = readWhiteSpace(reader);
+ if (c < 0) {
+ // end of input, no more IfLists
+ break;
+
+ } else if (c == '(') {
+ // start of an IfList, parse
+ list.add(parseIfList(reader));
+
+ } else if (c == '<') {
+ // start of a tag, return current list
+ reader.reset();
+ break;
+
+ } else {
+ // unexpected character
+ // catchup to end of input or start of an IfList
+ logIllegalState("Untagged", c, "(", reader);
+ }
+ }
+ } catch (IOException ioe) {
+ log.error("parseUntagged: Problem parsing If header: "+ioe.toString());
+ }
+ return list;
+ }
+
+ /**
+ * Parses an <em>IfList</em> in the <em>If</em> header. This method
+ * implements the <em>Tagged</em> production given in the class comment :
+ * <pre>
+ IfList = { [ "Not" ] ( ("<" Word ">" ) | ( "[" Word "]" ) ) } .
+ * </pre>
+ *
+ * @param reader The <code>StringReader</code> to read from for parsing
+ *
+ * @return The {@link IfList} for the input <em>IfList</em>.
+ *
+ * @throws IOException if a problem occurs during reading.
+ */
+ private IfList parseIfList(StringReader reader) throws IOException {
+ IfList res = new IfList();
+ boolean positive = true;
+ String word;
+
+ ReadLoop:
+ while (true) {
+ int nextChar = readWhiteSpace(reader);
+ switch (nextChar) {
+ case 'N':
+ case 'n':
+ // read not
+
+ // check whether o or O
+ int not = reader.read();
+ if (not != 'o' && not != 'O') {
+ logIllegalState("IfList-Not", not, "o", null);
+ break;
+ }
+
+ // check whether t or T
+ not = reader.read();
+ if (not !='t' && not != 'T') {
+ logIllegalState("IfList-Not", not, "t", null);
+ break;
+ }
+
+ // read Not ok
+ positive = false;
+ break;
+
+ case '<':
+ // state token
+ word = readWord(reader, '>');
+ if (word != null) {
+ res.add(new IfListEntryToken(word, positive));
+ // also add the token to the list of all tokens
+ if (positive) {
+ allTokens.add(word);
+ } else {
+ allNotTokens.add(word);
+ }
+ positive = true;
+ }
+ break;
+
+ case '[':
+ // etag
+ word = readWord(reader, ']');
+ if (word != null) {
+ res.add(new IfListEntryEtag(word, positive));
+ positive = true;
+ }
+ break;
+
+ case ')':
+ // correct end of list, end the loop
+ log.debug("parseIfList: End of If list, terminating loop");
+ break ReadLoop;
+
+ default:
+ logIllegalState("IfList", nextChar, "nN<[)", reader);
+
+ // abort loop if EOF
+ if (nextChar < 0) {
+ break ReadLoop;
+ }
+
+ break;
+ }
+ }
+
+ // return the current list anyway
+ return res;
+ }
+
+ /**
+ * Returns the first non-whitespace character from the reader or -1 if
+ * the end of the reader is encountered.
+ *
+ * @param reader The <code>Reader</code> to read from
+ *
+ * @return The first non-whitespace character or -1 in case of EOF.
+ *
+ * @throws IOException if a problem occurs during reading.
+ */
+ private int readWhiteSpace(Reader reader) throws IOException {
+ int c = reader.read();
+ while (c >= 0 && Character.isWhitespace((char) c)) {
+ c = reader.read();
+ }
+ return c;
+ }
+
+ /**
+ * Reads from the input until the end character is encountered and returns
+ * the string up to but not including this end character. If the end of input
+ * is reached before reading the end character <code>null</code> is
+ * returned.
+ * <p>
+ * Note that this method does not support any escaping.
+ *
+ * @param reader The <code>Reader</code> to read from
+ * @param end The ending character limiting the word.
+ *
+ * @return The string read up to but not including the ending character or
+ * <code>null</code> if the end of input is reached before the ending
+ * character has been read.
+ *
+ * @throws IOException if a problem occurs during reading.
+ */
+ private String readWord(Reader reader, char end) throws IOException {
+ StringBuffer buf = new StringBuffer();
+
+ // read the word value
+ int c = reader.read();
+ for (; c >= 0 && c != end; c=reader.read()) {
+ buf.append((char) c);
+ }
+
+ // check whether we succeeded
+ if (c < 0) {
+ log.error("readWord: Unexpected end of input reading word");
+ return null;
+ }
+
+ // build the string and return it
+ return buf.toString();
+ }
+
+ /**
+ * Logs an unexpected character with the corresponding state and list of
+ * expected characters. If the reader parameter is not null, characters
+ * are read until either the end of the input is reached or any of the
+ * characters in the expChar string is read.
+ *
+ * @param state The name of the current parse state. This method logs this
+ * name in the message. The intended value would probably be the
+ * name of the EBNF production during which the error occurs.
+ * @param effChar The effective character read.
+ * @param expChar The list of characters acceptable in the current state.
+ * @param reader The reader to be caught up to any of the expected
+ * characters. If <code>null</code> the input is not caught up to
+ * any of the expected characters (of course ;-).
+ */
+ private void logIllegalState(String state, int effChar, String expChar,
+ StringReader reader) {
+
+ // format the effective character to be logged
+ String effString = (effChar < 0) ? "<EOF>" : String.valueOf((char) effChar);
+
+ // log the error
+ log.error("logIllegalState: Unexpected character '"+effString+"' in state "+state+", expected any of "+expChar);
+
+ // catch up if a reader is given
+ if (reader != null && effChar >= 0) {
+ try {
+ log.debug("logIllegalState: Catch up to any of "+expChar);
+ do {
+ reader.mark(1);
+ effChar = reader.read();
+ } while (effChar >= 0 && expChar.indexOf(effChar) < 0);
+ if (effChar >= 0) {
+ reader.reset();
+ }
+ } catch (IOException ioe) {
+ log.error("logIllegalState: IO Problem catching up to any of "+expChar);
+ }
+ }
+ }
+
+ //---------- internal If header structure ----------------------------------
+
+ /**
+ * The <code>IfListEntry</code> abstract class is the base class for
+ * entries in an <em>IfList</em> production. This abstract base class
+ * provides common functionality to both types of entries, namely tokens
+ * enclosed in angle brackets (<code>< ></code>) and etags enclosed
+ * in square brackets (<code>[ ]</code>).
+ */
+ private static abstract class IfListEntry {
+
+ /**
+ * The entry string value - the semantics of this value depends on the
+ * implementing class.
+ */
+ protected final String value;
+
+ /** Flag to indicate, whether this is a positive match or not */
+ protected final boolean positive;
+
+ /** The cached result of the {@link #toString} method. */
+ protected String stringValue;
+
+ /**
+ * Sets up the final fields of this abstract class. The meaning of
+ * value parameter depends solely on the implementing class. From the
+ * point of view of this abstract class, it is simply a string value.
+ *
+ * @param value The string value of this instance
+ * @param positive <code>true</code> if matches are positive
+ */
+ protected IfListEntry(String value, boolean positive) {
+ this.value = value;
+ this.positive = positive;
+ }
+
+ /**
+ * Matches the value from the parameter to the internal string value.
+ * If the parameter and the {@link #value} field match, the method
+ * returns <code>true</code> for positive matches and <code>false</code>
+ * for negative matches.
+ * <p>
+ * This helper method can be called by implementations to evaluate the
+ * concrete match on the correct value parameter. See
+ * {@link #match(String, String)} for the external API method.
+ *
+ * @param value The string value to compare to the {@link #value}
+ * field.
+ *
+ * @return <code>true</code> if the value parameter and the
+ * {@link #value} field match and the {@link #positive} field is
+ * <code>true</code> or if the values do not match and the
+ * {@link #positive} field is <code>false</code>.
+ */
+ protected boolean match(String value) {
+ return positive == this.value.equals(value);
+ }
+
+ /**
+ * Matches the entry's value to the the token or etag. Depending on the
+ * concrete implementation, only one of the parameters may be evaluated
+ * while the other may be ignored.
+ * <p>
+ * Implementing METHODS may call the helper method {@link #match(String)}
+ * for the actual matching.
+ *
+ * @param token The token value to compare
+ * @param etag The etag value to compare
+ *
+ * @return <code>true</code> if the token/etag matches the <em>IfList</em>
+ * entry.
+ */
+ public abstract boolean match(String token, String etag);
+
+ /**
+ * Returns a short type name for the implementation. This method is
+ * used by the {@link #toString} method to build the string representation
+ * if the instance.
+ *
+ * @return The type name of the implementation.
+ */
+ protected abstract String getType();
+
+ /**
+ * Returns the value of this entry.
+ *
+ * @return the value
+ */
+ protected String getValue() {
+ return value;
+ }
+
+ /**
+ * Returns the String representation of this entry. This method uses the
+ * {@link #getType} to build the string representation.
+ *
+ * @return the String representation of this entry.
+ */
+ @Override
+ public String toString() {
+ if (stringValue == null) {
+ stringValue = getType() + ": " + (positive?"":"!") + value;
+ }
+ return stringValue;
+ }
+ }
+
+ /**
+ * The <code>IfListEntryToken</code> extends the {@link IfListEntry}
+ * abstract class to represent an entry for token matching.
+ */
+ private static class IfListEntryToken extends IfListEntry {
+
+ /**
+ * Creates a token matching entry.
+ *
+ * @param token The token value pertinent to this instance.
+ * @param positive <code>true</code> if this is a positive match entry.
+ */
+ IfListEntryToken(String token, boolean positive) {
+ super(token, positive);
+ }
+
+ /**
+ * Matches the token parameter to the stored token value and returns
+ * <code>true</code> if the values match and if the match is positive.
+ * <code>true</code> is also returned for negative matches if the values
+ * do not match.
+ *
+ * @param token The token value to compare
+ * @param etag The etag value to compare, which is ignored in this
+ * implementation.
+ *
+ * @return <code>true</code> if the token matches the <em>IfList</em>
+ * entry's token value.
+ */
+ @Override
+ public boolean match(String token, String etag) {
+ return token == null || super.match(token);
+ }
+
+ /**
+ * Returns the type name of this implementation, which is fixed to
+ * be <em>Token</em>.
+ *
+ * @return The fixed string <em>Token</em> as the type name.
+ */
+ @Override
+ protected String getType() {
+ return "Token";
+ }
+ }
+
+ /**
+ * The <code>IfListEntryToken</code> extends the {@link IfListEntry}
+ * abstract class to represent an entry for etag matching.
+ */
+ private static class IfListEntryEtag extends IfListEntry {
+
+ /**
+ * Creates an etag matching entry.
+ *
+ * @param etag The etag value pertinent to this instance.
+ * @param positive <code>true</code> if this is a positive match entry.
+ */
+ IfListEntryEtag(String etag, boolean positive) {
+ super(etag, positive);
+ }
+
+ /**
+ * Matches the etag parameter to the stored etag value and returns
+ * <code>true</code> if the values match and if the match is positive.
+ * <code>true</code> is also returned for negative matches if the values
+ * do not match.
+ *
+ * @param token The token value to compare, which is ignored in this
+ * implementation.
+ * @param etag The etag value to compare
+ *
+ * @return <code>true</code> if the etag matches the <em>IfList</em>
+ * entry's etag value.
+ */
+ @Override
+ public boolean match(String token, String etag) {
+ return super.match(etag);
+ }
+
+ /**
+ * Returns the type name of this implementation, which is fixed to
+ * be <em>ETag</em>.
+ *
+ * @return The fixed string <em>ETag</em> as the type name.
+ */
+ @Override
+ protected String getType() {
+ return "ETag";
+ }
+ }
+
+ /**
+ * The <code>IfList</code> class extends the <code>ArrayList</code> class
+ * with the limitation to only support adding {@link IfListEntry} objects
+ * and adding a {@link #match} method.
+ * <p>
+ * This class is a container for data contained in the <em>If</em>
+ * production <em>IfList</em>
+ * <pre>
+ IfList = { [ "Not" ] ( ("<" Word ">" ) | ( "[" Word "]" ) ) } .
+ * </pre>
+ * <p>
+ */
+ private static class IfList extends ArrayList<IfListEntry> {
+
+ /**
+ * Adds the {@link IfListEntry} at the end of the list.
+ *
+ * @param entry The {@link IfListEntry} to add to the list
+ *
+ * @return <code>true</code> (as per the general contract of Collection.add).
+ */
+ @Override
+ public boolean add(IfListEntry entry) {
+ return super.add(entry);
+ }
+
+ /**
+ * Adds the {@link IfListEntry} at the indicated position of the list.
+ *
+ * @param index
+ * @param entry
+ *
+ * @throws IndexOutOfBoundsException if index is out of range
+ * <code>(index < 0 || index > size())</code>.
+ */
+ @Override
+ public void add(int index, IfListEntry entry) {
+ super.add(index, entry);
+ }
+
+ /**
+ * Returns <code>true</code> if all {@link IfListEntry} objects in the
+ * list match the given token and etag. If the list is entry, it is
+ * considered to match the token and etag.
+ *
+ * @param token The token to compare.
+ * @param etag The etag to compare.
+ *
+ * @return <code>true</code> if all entries in the list match the
+ * given tag and token.
+ */
+ public boolean match(String token, String etag) {
+ log.debug("match: Trying to match token="+token+", etag="+etag);
+ for (int i=0; i < size(); i++) {
+ IfListEntry ile = get(i);
+ if (!ile.match(token, etag)) {
+ log.debug("match: Entry "+i+"-"+ile+" does not match");
+ return false;
+ }
+ }
+ // invariant: all entries matched
+
+ return true;
+ }
+ }
+
+ /**
+ * The <code>IfHeaderInterface</code> interface abstracts away the difference of
+ * tagged and untagged <em>If</em> header lists. The single method provided
+ * by this interface is to check whether a request may be applied to a
+ * resource with given token and etag.
+ */
+ private static interface IfHeaderInterface {
+
+ /**
+ * Matches the resource, token, and etag against this
+ * <code>IfHeaderInterface</code> instance.
+ *
+ * @param resource The resource to match this instance against. This
+ * must be absolute URI of the resource as defined in Section 3
+ * (URI Syntactic Components) of RFC 2396 Uniform Resource
+ * Identifiers (URI): Generic Syntax.
+ * @param token The resource's lock token to match
+ * @param etag The resource's etag to match
+ *
+ * @return <code>true</code> if the header matches the resource with
+ * token and etag, which means that the request is applicable
+ * to the resource according to the <em>If</em> header.
+ */
+ public boolean matches(String resource, String token, String etag);
+ }
+
+ /**
+ * The <code>IfHeaderList</code> class implements the {@link IfHeaderInterface}
+ * interface to support untagged lists of {@link IfList}s. This class
+ * implements the data container for the production :
+ * <pre>
+ Untagged = { "(" IfList ")" } .
+ * </pre>
+ */
+ private static class IfHeaderList extends ArrayList<IfList> implements IfHeaderInterface {
+
+ /**
+ * Matches a list of {@link IfList}s against the token and etag. If any of
+ * the {@link IfList}s matches, the method returns <code>true</code>.
+ * On the other hand <code>false</code> is only returned if non of the
+ * {@link IfList}s match.
+ *
+ * @param resource The resource to match, which is ignored by this
+ * implementation. A value of <code>null</code> is therefor
+ * acceptable.
+ * @param token The token to compare.
+ * @param etag The ETag value to compare.
+ *
+ * @return <code>True</code> if any of the {@link IfList}s matches the token
+ * and etag, else <code>false</code> is returned.
+ */
+ public boolean matches(String resource, String token, String etag) {
+ log.debug("matches: Trying to match token="+token+", etag="+etag);
+
+ for (IfList il : this) {
+ if (il.match(token, etag)) {
+ log.debug("matches: Found match with " + il);
+ return true;
+ }
+ }
+ // invariant: no match found
+
+ return false;
+ }
+ }
+
+ /**
+ * The <code>IfHeaderMap</code> class implements the {@link IfHeaderInterface}
+ * interface to support tagged lists of {@link IfList}s. This class
+ * implements the data container for the production :
+ * <pre>
+ Tagged = { "<" Word ">" "(" IfList ")" } .
+ * </pre>
+ */
+ private class IfHeaderMap extends HashMap<String, IfHeaderList> implements IfHeaderInterface {
+
+ /**
+ * Matches the token and etag for the given resource. If the resource is
+ * not mentioned in the header, a match is assumed and <code>true</code>
+ * is returned in this case.
+ *
+ * @param resource The absolute URI of the resource for which to find
+ * a match.
+ * @param token The token to compare.
+ * @param etag The etag to compare.
+ *
+ * @return <code>true</code> if either no entry exists for the resource
+ * or if the entry for the resource matches the token and etag.
+ */
+ public boolean matches(String resource, String token, String etag) {
+ log.debug("matches: Trying to match resource="+resource+", token="+token+","+etag);
+
+ String uri;
+ String path;
+ if (resource.startsWith("/")) {
+ path = resource;
+ uri = IfHeader.this.uriPrefix + resource;
+ } else {
+ path = resource.substring(IfHeader.this.uriPrefix.length());
+ uri = resource;
+ }
+ IfHeaderList list = get(path);
+ if (list == null) {
+ list = get(uri);
+ }
+ if (list == null) {
+ log.debug("matches: No entry for tag "+resource+", assuming mismatch");
+ return false;
+ } else {
+ return list.matches(resource, token, etag);
+ }
+ }
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/LabelHeader.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/LabelHeader.java
new file mode 100644
index 000000000..723df11ec
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/LabelHeader.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.header;
+
+import org.apache.jackrabbit.webdav.WebdavRequest;
+import org.apache.jackrabbit.webdav.util.EncodeUtil;
+import org.apache.jackrabbit.webdav.version.DeltaVConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * <code>LabelHeader</code>...
+ */
+public class LabelHeader implements Header {
+
+ private static Logger log = LoggerFactory.getLogger(LabelHeader.class);
+
+ private final String label;
+
+ public LabelHeader(String label) {
+ if (label == null) {
+ throw new IllegalArgumentException("null is not a valid label.");
+ }
+ this.label = label;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public String getHeaderName() {
+ return DeltaVConstants.HEADER_LABEL;
+ }
+
+ public String getHeaderValue() {
+ return EncodeUtil.escape(label);
+ }
+
+ public static LabelHeader parse(WebdavRequest request) {
+ String hv = request.getHeader(DeltaVConstants.HEADER_LABEL);
+ if (hv == null) {
+ return null;
+ } else {
+ return new LabelHeader(EncodeUtil.unescape(hv));
+ }
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/OverwriteHeader.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/OverwriteHeader.java
new file mode 100644
index 000000000..1de797411
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/OverwriteHeader.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.header;
+
+import org.apache.jackrabbit.webdav.DavConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+/**
+ * <code>OverwriteHeader</code>...
+ */
+public class OverwriteHeader implements Header {
+
+ private static Logger log = LoggerFactory.getLogger(OverwriteHeader.class);
+
+ public static final String OVERWRITE_TRUE = "T";
+ public static final String OVERWRITE_FALSE = "F";
+
+ /**
+ * Set 'doOverwrite' to <code>true</code> by default. See RFC 2518:
+ * "If the overwrite header is not included in a COPY or MOVE request then
+ * the resource MUST treat the request as if it has an overwrite header of
+ * value {@link #OVERWRITE_TRUE}".
+ */
+ private final boolean doOverwrite;
+
+ public OverwriteHeader(boolean doOverwrite) {
+ this.doOverwrite = doOverwrite;
+ }
+
+ /**
+ * Create a new <code>OverwriteHeader</code> for the given request object.
+ * If the latter does not contain an "Overwrite" header field, the default
+ * applies, which is {@link #OVERWRITE_TRUE} according to RFC 2518.
+ *
+ * @param request
+ */
+ public OverwriteHeader(HttpServletRequest request) {
+ String overwriteHeader = request.getHeader(DavConstants.HEADER_OVERWRITE);
+ if (overwriteHeader != null) {
+ doOverwrite = overwriteHeader.equalsIgnoreCase(OVERWRITE_TRUE);
+ } else {
+ // no Overwrite header -> default is 'true'
+ doOverwrite = true;
+ }
+ }
+
+ public String getHeaderName() {
+ return DavConstants.HEADER_OVERWRITE;
+ }
+
+ public String getHeaderValue() {
+ return (doOverwrite) ? OVERWRITE_TRUE : OVERWRITE_FALSE;
+ }
+
+ public boolean isOverwrite() {
+ return doOverwrite;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/PollTimeoutHeader.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/PollTimeoutHeader.java
new file mode 100644
index 000000000..73d638053
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/PollTimeoutHeader.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.header;
+
+import org.apache.jackrabbit.webdav.observation.ObservationConstants;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+/**
+ * <code>PollTimeoutHeader</code> implements a timeout header for subscription
+ * polling.
+ */
+public class PollTimeoutHeader extends TimeoutHeader {
+
+ public PollTimeoutHeader(long timeout) {
+ super(timeout);
+ }
+
+ @Override
+ public String getHeaderName() {
+ return ObservationConstants.HEADER_POLL_TIMEOUT;
+ }
+
+ /**
+ * Parses the request timeout header and converts it into a new
+ * <code>PollTimeoutHeader</code> object.<br>The default value is used as
+ * fallback if the String is not parseable.
+ *
+ * @param request
+ * @param defaultValue
+ * @return a new PollTimeoutHeader object.
+ */
+ public static PollTimeoutHeader parseHeader(HttpServletRequest request, long defaultValue) {
+ String timeoutStr = request.getHeader(ObservationConstants.HEADER_POLL_TIMEOUT);
+ long timeout = parse(timeoutStr, defaultValue);
+ return new PollTimeoutHeader(timeout);
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/TimeoutHeader.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/TimeoutHeader.java
new file mode 100644
index 000000000..0e5525359
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/TimeoutHeader.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.header;
+
+import org.apache.jackrabbit.webdav.DavConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+/**
+ * <code>TimeoutHeader</code>...
+ */
+public class TimeoutHeader implements Header, DavConstants {
+
+ private static Logger log = LoggerFactory.getLogger(TimeoutHeader.class);
+
+ private final long timeout;
+
+ public TimeoutHeader(long timeout) {
+ this.timeout = timeout;
+ }
+
+ public String getHeaderName() {
+ return DavConstants.HEADER_TIMEOUT;
+ }
+
+ public String getHeaderValue() {
+ if (timeout == INFINITE_TIMEOUT) {
+ return TIMEOUT_INFINITE;
+ } else {
+ return "Second-" + (timeout / 1000);
+ }
+ }
+
+ public long getTimeout() {
+ return timeout;
+ }
+
+ /**
+ * Parses the request timeout header and converts it into a new
+ * <code>TimeoutHeader</code> object.<br>The default value is used as
+ * fallback if the String is not parseable.
+ *
+ * @param request
+ * @param defaultValue
+ * @return a new TimeoutHeader object.
+ */
+ public static TimeoutHeader parse(HttpServletRequest request, long defaultValue) {
+ String timeoutStr = request.getHeader(HEADER_TIMEOUT);
+ long timeout = parse(timeoutStr, defaultValue);
+ return new TimeoutHeader(timeout);
+ }
+
+ /**
+ * Parses the given timeout String and converts the timeout value
+ * into a long indicating the number of milliseconds until expiration time
+ * is reached.<br>
+ * NOTE: If the timeout String equals to {@link #TIMEOUT_INFINITE 'infinite'}
+ * {@link Integer#MAX_VALUE} is returned. If the Sting is invalid or is in an
+ * invalid format that cannot be parsed, the default value is returned.
+ *
+ * @param timeoutStr
+ * @param defaultValue
+ * @return long representing the timeout present in the header or the default
+ * value if the header is missing or could not be parsed.
+ */
+ public static long parse(String timeoutStr, long defaultValue) {
+ long timeout = defaultValue;
+ if (timeoutStr != null && timeoutStr.length() > 0) {
+ int secondsInd = timeoutStr.indexOf("Second-");
+ if (secondsInd >= 0) {
+ secondsInd += 7; // read over "Second-"
+ int i = secondsInd;
+ while (i < timeoutStr.length() && Character.isDigit(timeoutStr.charAt(i))) {
+ i++;
+ }
+ try {
+ timeout = 1000L * Long.parseLong(timeoutStr.substring(secondsInd, i));
+ } catch (NumberFormatException ignore) {
+ // ignore and return 'undefined' timeout
+ log.error("Invalid timeout format: " + timeoutStr);
+ }
+ } else if (timeoutStr.equalsIgnoreCase(TIMEOUT_INFINITE)) {
+ timeout = INFINITE_TIMEOUT;
+ }
+ }
+ return timeout;
+ }
+}
\ No newline at end of file
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/package-info.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/package-info.java
new file mode 100644
index 000000000..3c834230d
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/header/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@org.osgi.annotation.versioning.Version("1.1.0")
+package org.apache.jackrabbit.webdav.header;
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/io/InputContext.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/io/InputContext.java
new file mode 100644
index 000000000..7faaf32fb
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/io/InputContext.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.io;
+
+import java.io.InputStream;
+
+/**
+ * <code>InputContext</code>...
+ */
+public interface InputContext {
+
+ /**
+ * Return true, if there are any data to be imported (and not only properties)
+ *
+ * @return
+ */
+ public boolean hasStream();
+
+ /**
+ * Returns the input stream of the resource to import.
+ *
+ * @return the input stream.
+ */
+ public InputStream getInputStream();
+
+ /**
+ * Returns the modification time of the resource or the current time if
+ * the modification time has not been set.
+ *
+ * @return the modification time.
+ */
+ public long getModificationTime();
+
+ /**
+ * Returns the content language or <code>null</code>
+ *
+ * @return contentLanguage
+ */
+ public String getContentLanguage();
+
+ /**
+ * Returns the length of the data or -1 if the contentlength could not be
+ * determined.
+ *
+ * @return the content length
+ */
+ public long getContentLength();
+
+ /**
+ * Return the content type or <code>null</code>
+ *
+ * @return
+ */
+ public String getContentType();
+
+ /**
+ * Returns the value of the given property or <code>null</code> if this property does
+ * not exist.
+ *
+ * @param propertyName
+ * @return String property value or <code>null</code>
+ */
+ public String getProperty(String propertyName);
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/io/InputContextImpl.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/io/InputContextImpl.java
new file mode 100644
index 000000000..592eecc1e
--- /dev/null
+++ b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/io/InputContextImpl.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.webdav.io;
+
+import org.apache.jackrabbit.webdav.DavConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.servlet.http.HttpServletRequest;
+import java.io.InputStream;
+import java.util.Date;
+
+/**
+ * <code>InputContextImpl</code> class encapsulates the <code>InputStream</code>
+ * and some header values as present in the POST, PUT or MKCOL request.
+ */
+public class InputContextImpl implements InputContext {
+
+ private static Logger log = LoggerFactory.getLogger(InputContextImpl.class);
+
+ private final HttpServletRequest request;
+ private final InputStream in;
+
+ public InputContextImpl(HttpServletRequest request, InputStream in) {
+ if (request == null) {
+ throw new IllegalArgumentException("DavResource and Request must not be null.");
+ }
+
+ this.request = request;
+ this.in = in;
+ }
+
+ public boolean hasStream() {
+ return in != null;
+ }
+
+ /**
+ * Returns the input stream of the resource to import.
+ *
+ * @return the input stream.
+ */
+ public InputStream getInputStream() {
+ return in;
+ }
+
+ public long getModificationTime() {
+ return new Date().getTime();
+ }
+
+ /**
+ * Returns the content language or <code>null</code>.
+ *
+ * @return contentLanguage
+ */
+ public String getContentLanguage() {
+ return request.getHeader(DavConstants.HEADER_CONTENT_LANGUAGE);
+ }
+
+ /**
+ * @return content length or -1 when unknown
+ */
+ public long getContentLength() {
+ String length = request.getHeader(DavConstants.HEADER_CONTENT_LENGTH);
+ if (length == null) {
+ // header not present
+ return -1;
+ } else {
+ try {
+ return Long.parseLong(length);
+ } catch (NumberFormatException ex) {
+ log.error("broken Content-Length header: " + length);
+ return -1;
+ }
+ }
+ }
+
+ public String getContentType() {
+ return request.getHeader(DavConstants.HEADER_CONTENT_TYPE);
+ }
+
+ public String getProperty(String propertyName) {
+ return request.getHeader(propertyName);
+ }
+}
diff --git a/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/io/OutputContext.java b/openmeetings-service/src/main/java/org/apache/jackrabbit/webdav/io/OutputContext.java
new file mode 100644
index 000000000..a5a25eff5
--- /dev/null
... 18212 lines suppressed ...