From b3b78caa641a6728cb3e27e84340fa1dc7222a1a Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Wed, 30 Dec 2020 15:32:38 +0100 Subject: [PATCH] Initial support for XEP-0446: File Metadata Element Solves SMACK-894 --- .../element/child/DateElement.java | 77 ++++++++++++ .../element/child/DescElement.java | 94 +++++++++++++++ .../element/child/DimensionsElement.java | 75 ++++++++++++ .../element/child/LengthElement.java | 77 ++++++++++++ .../element/child/MediaTypeElement.java | 78 ++++++++++++ .../element/child/NameElement.java | 94 +++++++++++++++ .../element/child/SizeElement.java | 72 +++++++++++ .../element/child/package-info.java | 20 +++ .../provider/FileMetadataElementProvider.java | 114 +++++++++--------- 9 files changed, 644 insertions(+), 57 deletions(-) create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/DateElement.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/DescElement.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/DimensionsElement.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/LengthElement.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/MediaTypeElement.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/NameElement.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/SizeElement.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/package-info.java diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/DateElement.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/DateElement.java new file mode 100644 index 000000000..2a13543b0 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/DateElement.java @@ -0,0 +1,77 @@ +/** + * + * Copyright 2020 Paul Schaub + * + * Licensed 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.jivesoftware.smackx.file_metadata.element.child; + +import java.util.Date; + +import org.jivesoftware.smack.packet.NamedElement; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.EqualsUtil; +import org.jivesoftware.smack.util.HashCode; +import org.jivesoftware.smack.util.XmlStringBuilder; + +import org.jxmpp.util.XmppDateTime; + +/** + * Timestamp specifying the last modified time of the file. + */ +public class DateElement implements NamedElement { + + public static final String ELEMENT = "date"; + + private final Date date; + + public DateElement(Date date) { + this.date = date; + } + + /** + * Return the last modification date of the file. + * + * @return last modification date + */ + public Date getDate() { + return date; + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + XmlStringBuilder sb = new XmlStringBuilder(this).rightAngleBracket(); + sb.append(XmppDateTime.formatXEP0082Date(getDate())); + return sb.closeElement(this); + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public int hashCode() { + return HashCode.builder() + .append(getElementName()) + .append(getDate()) + .build(); + } + + @Override + public boolean equals(Object obj) { + return EqualsUtil.equals(this, obj, (equalsBuilder, other) -> + equalsBuilder.append(getElementName(), other.getElementName()) + .append(getDate(), other.getDate())); + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/DescElement.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/DescElement.java new file mode 100644 index 000000000..5fb426b5f --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/DescElement.java @@ -0,0 +1,94 @@ +/** + * + * Copyright 2020 Paul Schaub + * + * Licensed 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.jivesoftware.smackx.file_metadata.element.child; + +import org.jivesoftware.smack.packet.NamedElement; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.EqualsUtil; +import org.jivesoftware.smack.util.HashCode; +import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smack.util.XmlStringBuilder; + +/** + * A human readable description of the file. Multiple {@link DescElement DescElements} MAY be included + * if different xml:lang values are specified. + */ +public class DescElement implements NamedElement { + + public static final String ELEMENT = "desc"; + + private final String description; + private final String lang; + + public DescElement(String description) { + this(description, null); + } + + public DescElement(String description, String lang) { + this.description = StringUtils.requireNotNullNorEmpty(description, "Description MUST NOT be null nor empty"); + this.lang = lang; + } + + /** + * Return the description of the file. + * + * @return description + */ + public String getDescription() { + return description; + } + + /** + * Return the language of the description or null. + * + * @return language or null + */ + public String getLanguage() { + return lang; + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + return new XmlStringBuilder(this) + .optXmlLangAttribute(getLanguage()) + .rightAngleBracket() + .append(getDescription()) + .closeElement(this); + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public int hashCode() { + return HashCode.builder() + .append(getElementName()) + .append(getLanguage()) + .append(getDescription()) + .build(); + } + + @Override + public boolean equals(Object obj) { + return EqualsUtil.equals(this, obj, (equalsBuilder, other) -> + equalsBuilder.append(getElementName(), other.getElementName()) + .append(getLanguage(), other.getLanguage()) + .append(getDescription(), other.getDescription())); + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/DimensionsElement.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/DimensionsElement.java new file mode 100644 index 000000000..1cdb92ee2 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/DimensionsElement.java @@ -0,0 +1,75 @@ +/** + * + * Copyright 2020 Paul Schaub + * + * Licensed 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.jivesoftware.smackx.file_metadata.element.child; + +import org.jivesoftware.smack.packet.NamedElement; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.EqualsUtil; +import org.jivesoftware.smack.util.HashCode; +import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smack.util.XmlStringBuilder; + +/** + * Horizontal and vertical dimensions of image or video files, in pixels. + */ +public class DimensionsElement implements NamedElement { + + public static final String ELEMENT = "dimensions"; + + private final String dimensions; + + public DimensionsElement(String dimensions) { + this.dimensions = StringUtils.requireNotNullNorEmpty(dimensions, "Dimensions MUST NOT be null nor empty."); + } + + /** + * Return the dimensions of the file in width by height (eg. 1920x1080). + * + * @return dimensions + */ + public String getDimensions() { + return dimensions; + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + return new XmlStringBuilder(this) + .rightAngleBracket() + .append(getDimensions()) + .closeElement(this); + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public int hashCode() { + return HashCode.builder() + .append(getElementName()) + .append(getDimensions()) + .build(); + } + + @Override + public boolean equals(Object obj) { + return EqualsUtil.equals(this, obj, (equalsBuilder, other) -> + equalsBuilder.append(getElementName(), other.getElementName()) + .append(getDimensions(), other.getDimensions())); + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/LengthElement.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/LengthElement.java new file mode 100644 index 000000000..6c29618e9 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/LengthElement.java @@ -0,0 +1,77 @@ +/** + * + * Copyright 2020 Paul Schaub + * + * Licensed 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.jivesoftware.smackx.file_metadata.element.child; + +import org.jivesoftware.smack.packet.NamedElement; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.EqualsUtil; +import org.jivesoftware.smack.util.HashCode; +import org.jivesoftware.smack.util.XmlStringBuilder; + +/** + * Length of an audio or video file, in milliseconds. + */ +public class LengthElement implements NamedElement { + + public static final String ELEMENT = "length"; + + private final long length; + + public LengthElement(long length) { + if (length < 0) { + throw new IllegalArgumentException("Length cannot be negative."); + } + this.length = length; + } + + /** + * Return the length of the audio or video file. + * + * @return length in milliseconds + */ + public long getLength() { + return length; + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + return new XmlStringBuilder(this) + .rightAngleBracket() + .append(Long.toString(getLength())) + .closeElement(this); + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public int hashCode() { + return HashCode.builder() + .append(getElementName()) + .append(getLength()) + .build(); + } + + @Override + public boolean equals(Object obj) { + return EqualsUtil.equals(this, obj, (equalsBuilder, other) -> + equalsBuilder.append(getElementName(), other.getElementName()) + .append(getLength(), other.getLength())); + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/MediaTypeElement.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/MediaTypeElement.java new file mode 100644 index 000000000..14ecc76a0 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/MediaTypeElement.java @@ -0,0 +1,78 @@ +/** + * + * Copyright 2020 Paul Schaub + * + * Licensed 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.jivesoftware.smackx.file_metadata.element.child; + +import org.jivesoftware.smack.packet.NamedElement; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.EqualsUtil; +import org.jivesoftware.smack.util.HashCode; +import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smack.util.XmlStringBuilder; + +/** + * The media type of the file content, which SHOULD be a valid MIME-TYPE as registered with the + * Internet Assigned Numbers Authority (IANA). + * + * @see Media Types + */ +public class MediaTypeElement implements NamedElement { + + public static final String ELEMENT = "media-type"; + + private final String mediaType; + + public MediaTypeElement(String mediaType) { + this.mediaType = StringUtils.requireNotNullNorEmpty(mediaType, "Media-Type MUST NOT be null nor empty"); + } + + /** + * Return the media type of the file. + * + * @return media type + */ + public String getMediaType() { + return mediaType; + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + return new XmlStringBuilder(this) + .rightAngleBracket() + .append(getMediaType()) + .closeElement(this); + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public int hashCode() { + return HashCode.builder() + .append(getElementName()) + .append(getMediaType()) + .build(); + } + + @Override + public boolean equals(Object obj) { + return EqualsUtil.equals(this, obj, (equalsBuilder, other) -> + equalsBuilder.append(getElementName(), other.getElementName()) + .append(getMediaType(), other.getMediaType())); + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/NameElement.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/NameElement.java new file mode 100644 index 000000000..7a89be18a --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/NameElement.java @@ -0,0 +1,94 @@ +/** + * + * Copyright 2020 Paul Schaub + * + * Licensed 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.jivesoftware.smackx.file_metadata.element.child; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +import org.jivesoftware.smack.packet.NamedElement; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.EqualsUtil; +import org.jivesoftware.smack.util.HashCode; +import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smack.util.XmlStringBuilder; + +/** + * The name of the file. + */ +public class NameElement implements NamedElement { + + public static final String ELEMENT = "name"; + + private final String name; + + public NameElement(String name) { + this.name = StringUtils.requireNotNullNorEmpty(name, "Name MUST NOT be null nor empty"); + } + + /** + * Return the name of the file. + * + * @return escaped name + */ + public String getName() { + try { + return URLEncoder.encode(name, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(e); // UTF-8 MUST be supported + } + } + + /** + * Return the text value of this element in its raw form. + * Note: Use {@link #getName()} instead when interpreting the name inside a directory structure. + * + * @see XEP-0446 ยง3. Security Considerations + * @return raw unescaped name + */ + public String getRawName() { + return name; + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + return new XmlStringBuilder(this) + .rightAngleBracket() + .append(getName()) + .closeElement(this); + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public int hashCode() { + return HashCode.builder() + .append(getElementName()) + .append(getRawName()) + .build(); + } + + @Override + public boolean equals(Object obj) { + return EqualsUtil.equals(this, obj, (equalsBuilder, other) -> + equalsBuilder.append(getElementName(), other.getElementName()) + .append(getRawName(), other.getRawName())); + } + +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/SizeElement.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/SizeElement.java new file mode 100644 index 000000000..ee88f5faf --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/SizeElement.java @@ -0,0 +1,72 @@ +/** + * + * Copyright 2020 Paul Schaub + * + * Licensed 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.jivesoftware.smackx.file_metadata.element.child; + +import org.jivesoftware.smack.packet.NamedElement; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.EqualsUtil; +import org.jivesoftware.smack.util.HashCode; +import org.jivesoftware.smack.util.XmlStringBuilder; + +/** + * The length of the file's content, in bytes. + */ +public class SizeElement implements NamedElement { + + public static final String ELEMENT = "size"; + + private final long size; + + public SizeElement(long size) { + if (size < 0) { + throw new IllegalArgumentException("Size MUST NOT be negative."); + } + this.size = size; + } + + public long getSize() { + return size; + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + return new XmlStringBuilder(this) + .rightAngleBracket() + .append(Long.toString(getSize())) + .closeElement(this); + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public int hashCode() { + return HashCode.builder() + .append(getElementName()) + .append(getSize()) + .build(); + } + + @Override + public boolean equals(Object obj) { + return EqualsUtil.equals(this, obj, (equalsBuilder, other) -> + equalsBuilder.append(getElementName(), other.getElementName()) + .append(getSize(), other.getSize())); + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/package-info.java new file mode 100644 index 000000000..f0f904bd8 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/element/child/package-info.java @@ -0,0 +1,20 @@ +/** + * + * Copyright 2020 Paul Schaub + * + * Licensed 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. + */ +/** + * Child elements of the file metadata element. + */ +package org.jivesoftware.smackx.file_metadata.element.child; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/provider/FileMetadataElementProvider.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/provider/FileMetadataElementProvider.java index e4212b0ce..eb98273bd 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/provider/FileMetadataElementProvider.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/file_metadata/provider/FileMetadataElementProvider.java @@ -16,9 +16,6 @@ */ package org.jivesoftware.smackx.file_metadata.provider; -import java.io.IOException; -import java.text.ParseException; - import org.jivesoftware.smack.packet.XmlEnvironment; import org.jivesoftware.smack.parsing.SmackParsingException; import org.jivesoftware.smack.provider.ExtensionElementProvider; @@ -31,6 +28,9 @@ import org.jivesoftware.smackx.hashes.provider.HashElementProvider; import org.jivesoftware.smackx.thumbnails.element.ThumbnailElement; import org.jivesoftware.smackx.thumbnails.provider.ThumbnailElementProvider; +import java.io.IOException; +import java.text.ParseException; + public class FileMetadataElementProvider extends ExtensionElementProvider { @Override @@ -41,60 +41,60 @@ public class FileMetadataElementProvider extends ExtensionElementProvider