diff --git a/elemental-media-type/elemental-media-type-api/pom.xml b/elemental-media-type/elemental-media-type-api/pom.xml new file mode 100644 index 0000000000..1e29fb8211 --- /dev/null +++ b/elemental-media-type/elemental-media-type-api/pom.xml @@ -0,0 +1,84 @@ + + + + 4.0.0 + + + xyz.elemental + elemental-media-type + 7.5.0-SNAPSHOT + .. + + + elemental-media-type-api + + Elemental Internet Media Type Resolver API + Internet Media Type Resolver API for Elemental + + + scm:git:https://github.com/evolvedbinary/elemental.git + scm:git:https://github.com/evolvedbinary/elemental.git + scm:git:https://github.com/evolvedbinary/elemental.git + + + + + com.google.code.findbugs + jsr305 + + + + + + + com.mycila + license-maven-plugin + + + +
${project.parent.relativePath}/../elemental-parent/FDB-backport-to-EDB-LGPL-21-ONLY-license.template.txt
+
+
+
+
+
+
+ +
\ No newline at end of file diff --git a/elemental-media-type/elemental-media-type-api/src/main/java/xyz/elemental/mediatype/MediaType.java b/elemental-media-type/elemental-media-type-api/src/main/java/xyz/elemental/mediatype/MediaType.java new file mode 100644 index 0000000000..ee5c1f792d --- /dev/null +++ b/elemental-media-type/elemental-media-type-api/src/main/java/xyz/elemental/mediatype/MediaType.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2014, Evolved Binary Ltd + * + * This file was originally ported from FusionDB to Elemental by + * Evolved Binary, for the benefit of the Elemental Open Source community. + * Only the ported code as it appears in this file, at the time that + * it was contributed to Elemental, was re-licensed under The GNU + * Lesser General Public License v2.1 only for use in Elemental. + * + * This license grant applies only to a snapshot of the code as it + * appeared when ported, it does not offer or infer any rights to either + * updates of this source code or access to the original source code. + * + * The GNU Lesser General Public License v2.1 only license follows. + * + * ===================================================================== + * + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package xyz.elemental.mediatype; + +import javax.annotation.Nullable; + +/** + * Information about a Media Type (aka MIME Type) + * and how resources of that type should be stored into + * the database. + * + * @author Adam Retter + */ +public interface MediaType { + + /** + * Get the identifier of the Media Type. + * + * For example {@code application/xml}. + * + * @return the identifier of the Media Type + */ + String getIdentifier(); + + /** + * Get the file extensions that are known + * to be associated with the Media Type. + * + * @return the known file extensions associated with the Media Type, or null if there are none + */ + @Nullable String[] getKnownFileExtensions(); + + /** + * Get the database storage type that should + * be used for resources of this Media Type. + * + * @return the database storage type of the Media Type + */ + StorageType getStorageType(); + + // + String APPLICATION_ATOM = "application/atom+xml"; + String APPLICATION_BZIP2 = "application/x-bzip2"; + String APPLICATION_DITA = "application/dita+xml"; + String APPLICATION_ELEMENTAL_DOCUMENT = "application/vnd.elemental.document"; + String APPLICATION_ELEMENTAL_DOCUMENT_BINARY = "application/vnd.elemental.document+binary"; + String APPLICATION_ELEMENTAL_DOCUMENT_XML = "application/vnd.elemental.document+xml"; + String APPLICATION_ELEMENTAL_COLLECTION = "application/vnd.elemental.collection"; + String APPLICATION_EXPATH_PACKAGE_ZIP = "application/prs.expath.package+zip"; + String APPLICATION_GML = "application/gml+xml"; + String APPLICATION_GZIP = "application/gzip"; + String APPLICATION_INVISIBLE_XML_GRAMMAR = "application/prs.invisible-xml.grammar"; + String APPLICATION_INVISIBLE_XML_GRAMMAR_XML = "application/prs.invisible-xml.grammar+xml"; + String APPLICATION_JAVA_ARCHIVE = "application/java-archive"; + String APPLICATION_JSON = "application/json"; + String APPLICATION_MADS = "application/mads+xml"; + String APPLICATION_MARC = "application/marcxml+xml"; + String APPLICATION_METS = "application/mets+xml"; + String APPLICATION_MODS = "application/mods+xml"; + String APPLICATION_NCX = "application/x-dtbncx+xml"; + String APPLICATION_OCTET_STREAM = "application/octet-stream"; + String APPLICATION_OEBPS_PACKAGE = "application/oebps-package+xml"; + String APPLICATION_OPENDOCUMENT_PRESENTATION = "application/vnd.oasis.opendocument.presentation"; + String APPLICATION_OPENDOCUMENT_TEXT = "application/vnd.oasis.opendocument.text"; + String APPLICATION_OPENDOCUMENT_SPREADSHEET = "application/vnd.oasis.opendocument.spreadsheet"; + String APPLICATION_OPENXML_PRESENTATION = "application/vnd.openxmlformats-officedocument.presentationml.presentation"; + String APPLICATION_OPENXML_SPREADSHEET = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + String APPLICATION_OPENXML_WORDPROCESSING = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; + String APPLICATION_PACK200 = "application/x-java-pack200"; + String APPLICATION_PDF = "application/pdf"; + String APPLICATION_RDF_XML = "application/rdf+xml"; + String APPLICATION_RELAXNG_COMPACT = "application/relax-ng-compact-syntax"; + String APPLICATION_RSS = "application/rss+xml"; + String APPLICATION_SCHEMATRON = "application/schematron+xml"; + String APPLICATION_SRU = "application/sru+xml"; + String APPLICATION_TAR = "application/x-tar"; + String APPLICATION_TEI = "application/tei+xml"; + String APPLICATION_WSDL = "application/wsdl+xml"; + String APPLICATION_WWW_FORM_URLENCODED = "application/x-www-form-urlencoded"; + String APPLICATION_XMI = "application/vnd.xmi+xml"; + String APPLICATION_XML = "application/xml"; + String APPLICATION_XML_DTD = "application/xml-dtd"; + String APPLICATION_XHTML = "application/xhtml+xml"; + String APPLICATION_XPROC = "application/xproc+xml"; + String APPLICATION_XSLT = "application/xslt+xml"; + String APPLICATION_XQUERY = "application/xquery"; + String APPLICATION_XQUERY_XML = "application/xquery+xml"; + String APPLICATION_XZ = "application/x-xz"; + String APPLICATION_ZIP = "application/zip"; + String APPLICATION_ZSTD = "application/zstd"; + + String IMAGE_GIF = "image/gif"; + String IMAGE_JPEG = "image/jpeg"; + String IMAGE_PNG = "image/png"; + String IMAGE_SVG = "image/svg+xml"; + String IMAGE_SVG_GZIP = "image/svg+xml"; + // See: https://github.com/w3c/svgwg/issues/701 +// String IMAGE_SVG_GZIP = "image/x.svg+gzip"; + + String MULTIPART_ALTERNATIVE = "multipart/alternative"; + String MULTIPART_MIXED = "multipart/mixed"; + + String TEXT_CSS = "text/css"; + String TEXT_CSV = "text/csv"; + String TEXT_CSV_SCHEMA = "text/csv-schema"; + String TEXT_HTML = "text/html"; + String TEXT_JAVASCRIPT = "text/javascript"; + String TEXT_MARKDOWN = "text/markdown"; + String TEXT_N3 = "text/n3"; + String TEXT_PLAIN = "text/plain"; + String TEXT_TURTLE = "text/turtle"; + String TEXT_URI_LIST = "text/uri-list"; + + /** + * Expect for use within the type attribute of an XML Processing Instruction + * this is probably not what you need, and you should likely use {@link #APPLICATION_XML} instead. + */ + @Deprecated + String TEXT_XSL = "text/xsl"; + // + + // + String APPLICATION_EXISTDB_COLLECTION_CONFIG_XML = "application/prs.existdb.collection-config+xml"; + + /** + * Use {@link #APPLICATION_ELEMENTAL_DOCUMENT} instead. + */ + @Deprecated + String APPLICATION_EXISTDB_DOCUMENT = "application/vnd.existdb.document"; + + /** + * Use {@link #APPLICATION_ELEMENTAL_DOCUMENT_BINARY} instead. + */ + @Deprecated + String APPLICATION_EXISTDB_DOCUMENT_BINARY = "application/vnd.existdb.document+binary"; + + /** + * Use {@link #APPLICATION_ELEMENTAL_DOCUMENT_XML} instead. + */ + @Deprecated + String APPLICATION_EXISTDB_DOCUMENT_XML = "application/vnd.existdb.document+xml"; + + /** + * Use {@link #APPLICATION_ELEMENTAL_COLLECTION} instead. + */ + @Deprecated + String APPLICATION_EXISTDB_COLLECTION = "application/vnd.existdb.collection"; + // +} diff --git a/elemental-media-type/elemental-media-type-api/src/main/java/xyz/elemental/mediatype/MediaTypeResolver.java b/elemental-media-type/elemental-media-type-api/src/main/java/xyz/elemental/mediatype/MediaTypeResolver.java new file mode 100644 index 0000000000..575a43806d --- /dev/null +++ b/elemental-media-type/elemental-media-type-api/src/main/java/xyz/elemental/mediatype/MediaTypeResolver.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2014, Evolved Binary Ltd + * + * This file was originally ported from FusionDB to Elemental by + * Evolved Binary, for the benefit of the Elemental Open Source community. + * Only the ported code as it appears in this file, at the time that + * it was contributed to Elemental, was re-licensed under The GNU + * Lesser General Public License v2.1 only for use in Elemental. + * + * This license grant applies only to a snapshot of the code as it + * appeared when ported, it does not offer or infer any rights to either + * updates of this source code or access to the original source code. + * + * The GNU Lesser General Public License v2.1 only license follows. + * + * ===================================================================== + * + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package xyz.elemental.mediatype; + +import javax.annotation.Nullable; +import java.nio.file.Path; + +/** + * Finds Media Types for resources. + * + * @author Adam Retter + */ +public interface MediaTypeResolver { + + /** + * Resolve the Media Type for the filename. + * + * @param path the Path containing the filename. + * + * @return The MediaType for the filename, or null if there is no known or configured media type + */ + @Nullable MediaType fromFileName(@Nullable final Path path); + + /** + * Resolve the MediaType for the filename. + * + * @param path the file path containing the filename. + * + * @return The MediaType for the filename, or null if there is no known or configured media type. + */ + @Nullable MediaType fromFileName(@Nullable final String path); + + /** + * Resolve the MediaType from the name/identifier + * of the media type. + * + * @param mediaType the name/identifier of the media type. + * + * @return The MediaType for the name/identifier, or null if the media type is unknown. + */ + @Nullable MediaType fromString(@Nullable final String mediaType); + + /** + * Returns the MediaType to be used for + * unknown types of resources. + * + * This is typically used as a catch-all. + * + * @return the MediaType to use for unknown + * types of resources. + */ + MediaType forUnknown(); + + /** + * The Instantiation Exception is thrown + * if an error occurs when the factory + * tries to instantiate a new Media Type Resolver. + */ + class InstantiationException extends Exception { + public InstantiationException(final String message) { + super(message); + } + + public InstantiationException(final String message, final Throwable cause) { + super(message, cause); + } + + public InstantiationException(final Throwable cause) { + super(cause); + } + } +} diff --git a/elemental-media-type/elemental-media-type-api/src/main/java/xyz/elemental/mediatype/MediaTypeResolverFactory.java b/elemental-media-type/elemental-media-type-api/src/main/java/xyz/elemental/mediatype/MediaTypeResolverFactory.java new file mode 100644 index 0000000000..a622df185e --- /dev/null +++ b/elemental-media-type/elemental-media-type-api/src/main/java/xyz/elemental/mediatype/MediaTypeResolverFactory.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2014, Evolved Binary Ltd + * + * This file was originally ported from FusionDB to Elemental by + * Evolved Binary, for the benefit of the Elemental Open Source community. + * Only the ported code as it appears in this file, at the time that + * it was contributed to Elemental, was re-licensed under The GNU + * Lesser General Public License v2.1 only for use in Elemental. + * + * This license grant applies only to a snapshot of the code as it + * appeared when ported, it does not offer or infer any rights to either + * updates of this source code or access to the original source code. + * + * The GNU Lesser General Public License v2.1 only license follows. + * + * ===================================================================== + * + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package xyz.elemental.mediatype; + +import javax.annotation.Nullable; +import java.nio.file.Path; +import xyz.elemental.mediatype.MediaTypeResolver.InstantiationException; + +/** + * Factory for instantiating Media Type Resolvers. + * + * @author Adam Retter + */ +public interface MediaTypeResolverFactory { + + /** + * Instantiate a new Media Type Resolver. + * + * @return a new Media Type Resolver. + * + * @throws InstantiationException if an error occurs + * whilst instantiating the MediaTypeResolver. + */ + MediaTypeResolver newMediaTypeResolver() + throws InstantiationException; + + /** + * Instantiate a new Media Type Resolver. + * + * @param configDirs paths to directories which contain configuration + * files for the media type resolver. + * + * @return a new Media Type Resolver. + * + * @throws InstantiationException if an error occurs + * whilst instantiating the MediaTypeResolver. + */ + MediaTypeResolver newMediaTypeResolver(@Nullable final Path... configDirs) + throws InstantiationException; + +} diff --git a/elemental-media-type/elemental-media-type-api/src/main/java/xyz/elemental/mediatype/StorageType.java b/elemental-media-type/elemental-media-type-api/src/main/java/xyz/elemental/mediatype/StorageType.java new file mode 100644 index 0000000000..01282650c0 --- /dev/null +++ b/elemental-media-type/elemental-media-type-api/src/main/java/xyz/elemental/mediatype/StorageType.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2014, Evolved Binary Ltd + * + * This file was originally ported from FusionDB to Elemental by + * Evolved Binary, for the benefit of the Elemental Open Source community. + * Only the ported code as it appears in this file, at the time that + * it was contributed to Elemental, was re-licensed under The GNU + * Lesser General Public License v2.1 only for use in Elemental. + * + * This license grant applies only to a snapshot of the code as it + * appeared when ported, it does not offer or infer any rights to either + * updates of this source code or access to the original source code. + * + * The GNU Lesser General Public License v2.1 only license follows. + * + * ===================================================================== + * + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package xyz.elemental.mediatype; + +import javax.annotation.Nullable; + +/** + * Types of database storage to use for resources of various Media Type. + * + * @author Adam Retter + */ +public enum StorageType { + /** + * Native XML document storage within the database. + */ + XML, + + /** + * Binary document storage within the database. + */ + BINARY; + + /** + * Get a StorageType by its name. + * Similar to {@link #valueOf(String)} but ignores + * cases sensitivity. + * + * @param name the name of the StorageType + * @return the StorageType + * + * @throws IllegalArgumentException if the name is unknown + */ + public static StorageType fromName(final String name) { + final StorageType storageType = lookup(name); + if (storageType != null) { + return storageType; + } + throw new IllegalArgumentException(); + } + + /** + * Get a StorageType by its name. + * Similar to {@link #fromName(String)} but + * if no Storage Type matches the {@code name} + * then the Storage Type for Unknown resources + * is returned. + * + * @param name the name of the StorageType + * @return the StorageType for the name, or the Storage + * Type for Unknown resources as returned by {@link #forUnknown()}. + */ + public static StorageType fromNameOrDefault(final String name) { + final StorageType storageType = lookup(name); + if (storageType != null) { + return storageType; + } + return forUnknown(); + } + + /** + * Get a StorageType by its name. + * Similar to {@link #valueOf(String)} but ignores + * cases sensitivity. + * + * @param name the name of the StorageType + * @return the StorageType or null if there is + * no StorageType for the provided name. + */ + private static @Nullable StorageType lookup(String name) { + name = name.toUpperCase(); + for (final StorageType storageType : StorageType.values()) { + if (storageType.name().equals(name)) { + return storageType; + } + } + return null; + } + + /** + * Returns the StorageType to be used for + * unknown types of resources. + * + * This is typically used as a catch-all. + * + * @return the StorageType to use for unknown + * types of resources. + */ + public static StorageType forUnknown() { + return BINARY; + } +} diff --git a/elemental-media-type/elemental-media-type-impl/pom.xml b/elemental-media-type/elemental-media-type-impl/pom.xml new file mode 100644 index 0000000000..51388c58a6 --- /dev/null +++ b/elemental-media-type/elemental-media-type-impl/pom.xml @@ -0,0 +1,208 @@ + + + + 4.0.0 + + + xyz.elemental + elemental-media-type + 7.5.0-SNAPSHOT + .. + + + elemental-media-type-impl + + Elemental Internet Media Type Resolver Implementation + Internet Media Type Implementation for Elemental + + + scm:git:https://github.com/evolvedbinary/elemental.git + scm:git:https://github.com/evolvedbinary/elemental.git + scm:git:https://github.com/evolvedbinary/elemental.git + + + + 2.4.65+1.0.1 + + + + + xyz.elemental + elemental-media-type-api + ${project.version} + + + + com.google.code.findbugs + jsr305 + + + + net.jcip + jcip-annotations + + + + org.slf4j + slf4j-api + + + + org.slf4j + slf4j-simple + ${slf4j.version} + test + + + + io.lacuna + bifurcan + + + + jakarta.xml.bind + jakarta.xml.bind-api + + + + org.glassfish.jaxb + jaxb-runtime + runtime + + + + jakarta.activation + jakarta.activation-api + + + + org.eclipse.angus + angus-activation + + + + com.evolvedbinary.thirdparty.org.apache.httpd + apache-httpd-mime-types + ${httpd.mime-types.version} + runtime + + + + org.junit.jupiter + junit-jupiter-api + test + + + + + + + + com.mycila + license-maven-plugin + + + SCRIPT_STYLE + + + +
${project.parent.relativePath}/../elemental-parent/FDB-backport-to-EDB-LGPL-21-ONLY-license.template.txt
+
+
+
+
+ + + org.jvnet.jaxb + jaxb-maven-plugin + + src/main/xjb + src/main/xsd + + + + generate-jaxb-objects + + generate + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + analyze + + analyze-only + + + true + + + org.glassfish.jaxb:jaxb-runtime:jar:${jaxb.impl.version} + + com.evolvedbinary.thirdparty.org.apache.httpd:apache-httpd-mime-types:jar:${httpd.mime-types.version} + + + + net.sf.xmldb-org:xmldb-api:jar + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + ${project.build.directory}/generated-sources/xjc/** + + + +
+
+ +
\ No newline at end of file diff --git a/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/ApplicationMimetypesFileTypeMap.java b/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/ApplicationMimetypesFileTypeMap.java new file mode 100644 index 0000000000..0a75879a47 --- /dev/null +++ b/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/ApplicationMimetypesFileTypeMap.java @@ -0,0 +1,365 @@ +/* + * Copyright (C) 2014, Evolved Binary Ltd + * + * This file was originally ported from FusionDB to Elemental by + * Evolved Binary, for the benefit of the Elemental Open Source community. + * Only the ported code as it appears in this file, at the time that + * it was contributed to Elemental, was re-licensed under The GNU + * Lesser General Public License v2.1 only for use in Elemental. + * + * This license grant applies only to a snapshot of the code as it + * appeared when ported, it does not offer or infer any rights to either + * updates of this source code or access to the original source code. + * + * The GNU Lesser General Public License v2.1 only license follows. + * + * ===================================================================== + * + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package xyz.elemental.mediatype.impl; + +import io.lacuna.bifurcan.IList; +import io.lacuna.bifurcan.LinearList; +import jakarta.activation.MimeTypeEntry; +import jakarta.activation.MimeTypeRegistry; +import jakarta.activation.MimetypesFileTypeMap; +import org.eclipse.angus.activation.MimeTypeFile; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nullable; +import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; + +/** + * An implementation of {@link jakarta.activation.FileTypeMap} which + * extends {@link jakarta.activation.MimetypesFileTypeMap} to also + * read from an application specific file. + * + *

MIME types file search order

+ * The ApplicationMimetypesFileTypeMap looks in various places in the user's + * system for MIME types file entries. When requests are made + * to search for MIME types in the ApplicationMimetypesFileTypeMap, it searches + * MIME types files in the following order: + *
    + *
  1. Programmatically added entries to the ApplicationMimetypesFileTypeMap instance.
  2. + *
  3. The file .jakarta.mime.types in the user's home directory.
  4. + *
  5. The file .mime.types in the user's home directory.
  6. + *
  7. The file jakarta.mime.types from within the user's home directory: + * + *
  8. + *
  9. One or more files named jakarta.mime.types in the application's config directory(s).
  10. + *
  11. One or more files named mime.types in the application's config directory(s).
  12. + *
  13. The file jakarta.mime.types on the classpath in the package xyz.elemental.mediatype.
  14. + *
  15. The file mime.types on the classpath in the package xyz.elemental.mediatype.
  16. + *
  17. The file jakarta.mime.types in the Java runtime.
  18. + *
  19. The file mime.types in the Java runtime.
  20. + *
  21. The file or resources named META-INF/jakarta.mime.types.
  22. + *
  23. The file or resources named META-INF/mime.types.
  24. + *
  25. The file or resource named META-INF/jakarta.mimetypes.default (usually found only in the activation.jar file).
  26. + *
  27. The file or resource named META-INF/mimetypes.default (usually found only in the activation.jar file).
  28. + *
+ * + *

(The current implementation looks for the jakarta.mime.types and mime.types files + * in the Java runtime in the directory java.home/conf + * if it exists, and otherwise in the directory + * java.home/lib, where java.home is the value + * of the "java.home" System property. Note that the "conf" directory was + * introduced in JDK 9.)

+ * + * See {@link MimetypesFileTypeMap} for further information. + * + * @author Adam Retter + */ +public class ApplicationMimetypesFileTypeMap extends MimetypesFileTypeMap { + + private static final Logger LOG = LoggerFactory.getLogger(ApplicationMimetypesFileTypeMap.class); + + private static final String JAKARTA_MIME_TYPES_FILENAME = "jakarta.mime.types"; + private static final String LEGACY_MIME_TYPES_FILENAME = "mime.types"; + + public ApplicationMimetypesFileTypeMap(@Nullable final Path... configDirs) { + final Vector dbv = new Vector<>(6); // usually 6 or fewer databases + @Nullable MimeTypeRegistry mf; + dbv.add(null); // place holder for PROG entry + + @Nullable final Method loadFileMethod = getLoadFileMethod(); + if (loadFileMethod != null) { + + LOG.trace("MimetypesFileTypeMap: load HOME"); + try { + final String user_home = System.getProperty("user.home"); + + if (user_home != null) { + String path = user_home + File.separator + "." + JAKARTA_MIME_TYPES_FILENAME; + mf = loadFileRefl(loadFileMethod, path); + if (mf != null) { + dbv.add(mf); + } + + path = user_home + File.separator + "." + LEGACY_MIME_TYPES_FILENAME; + mf = loadFileRefl(loadFileMethod, path); + if (mf != null) { + dbv.add(mf); + } + } + } catch (final SecurityException ex) { + // no-op + } + + LOG.trace("MimetypesFileTypeMap: load HOME DATA"); + try { + @Nullable final Path userDataFolder = PathUtil.getUserDataFolder(); + + if (userDataFolder != null) { + String path = userDataFolder.resolve("." + JAKARTA_MIME_TYPES_FILENAME).toAbsolutePath().toString(); + mf = loadFileRefl(loadFileMethod, path); + if (mf != null) { + dbv.add(mf); + } + + path = userDataFolder.resolve("." + LEGACY_MIME_TYPES_FILENAME).toAbsolutePath().toString(); + mf = loadFileRefl(loadFileMethod, path); + if (mf != null) { + dbv.add(mf); + } + } + } catch (final SecurityException ex) { + // no-op + } + + LOG.trace("ApplicationMimetypesFileTypeMap: load application"); + if (configDirs != null) { + for (final Path configDir : configDirs) { + boolean found = false; + final String[] filenames = new String[]{JAKARTA_MIME_TYPES_FILENAME, LEGACY_MIME_TYPES_FILENAME}; + for (final String filename : filenames) { + + final Path mimeTypesPath = configDir.resolve(filename); + if (!Files.exists(mimeTypesPath)) { + LOG.trace("No custom {} found at: {}, skipping...", filename, mimeTypesPath.toAbsolutePath()); + } + + mf = loadFileRefl(loadFileMethod, mimeTypesPath.toAbsolutePath().toString()); + if (mf != null) { + dbv.add(mf); + found = true; + } + } + if (!found) { + LOG.warn("Could not find Media Types file named {} or {} in: {}, skipping...", JAKARTA_MIME_TYPES_FILENAME, LEGACY_MIME_TYPES_FILENAME, configDir.toAbsolutePath()); + } + } + } + } + + LOG.trace("ApplicationMimetypesFileTypeMap: load classpath from xyz.elemental.mediatype"); + @Nullable final Method loadAllResourcesMethod = getLoadAllResourcesMethod(); + if (loadAllResourcesMethod != null) { + loadAllResourcesRefl(loadAllResourcesMethod, dbv, new String[] { + "xyz/elemental/mediatype/" + JAKARTA_MIME_TYPES_FILENAME, + "xyz/elemental/mediatype/" + LEGACY_MIME_TYPES_FILENAME + }); + } + + if (loadFileMethod != null) { + LOG.trace("MimetypesFileTypeMap: load SYS"); + try { + // check system's home + final String confDir = confDirRefl(); + if (confDir != null) { + mf = loadFileRefl(loadFileMethod, confDir + JAKARTA_MIME_TYPES_FILENAME); + if (mf != null) { + dbv.add(mf); + } + + mf = loadFileRefl(loadFileMethod, confDir + LEGACY_MIME_TYPES_FILENAME); + if (mf != null) { + dbv.add(mf); + } + } + } catch (final SecurityException ex) { + // no-op + } + } + + if (loadAllResourcesMethod != null) { + LOG.trace("MimetypesFileTypeMap: load JAR"); + // load from the app's jar file + loadAllResourcesRefl(loadAllResourcesMethod, dbv, new String[] { + "META-INF/" + JAKARTA_MIME_TYPES_FILENAME, + "META-INF/" + LEGACY_MIME_TYPES_FILENAME + }); + } + + @Nullable final Method loadResourceMethod = getLoadResourceMethod(); + if (loadResourceMethod != null) { + LOG.trace("MimetypesFileTypeMap: load DEF"); + mf = loadResourceRefl(loadResourceMethod, new String[] { + "/META-INF/jakarta.mimetypes.default", + "/META-INF/mimetypes.default" + }); + if (mf != null) { + dbv.add(mf); + } + } + + final MimeTypeFile[] DB = new MimeTypeFile[dbv.size()]; + dbv.copyInto(DB); + setDBRefl(DB); + } + + private static @Nullable Method getLoadFileMethod() { + try { + final Method loadFileMethod = MimetypesFileTypeMap.class.getDeclaredMethod("loadFile", String.class); + loadFileMethod.setAccessible(true); + return loadFileMethod; + } catch (final NoSuchMethodException e) { + LOG.error(e.getMessage(), e); + return null; + } + } + + private @Nullable MimeTypeRegistry loadFileRefl(final Method loadFileMethod, final String name) { + try { + return (MimeTypeRegistry) loadFileMethod.invoke(this, name); + } catch (final IllegalAccessException | InvocationTargetException e) { + LOG.error(e.getMessage(), e); + return null; + } + } + + private static @Nullable String confDirRefl() { + try { + final Field confDirField = MimetypesFileTypeMap.class.getDeclaredField("confDir"); + confDirField.setAccessible(true); + return (String) confDirField.get(null); + } catch (final NoSuchFieldException | IllegalAccessException e) { + LOG.error(e.getMessage(), e); + return null; + } + } + + private static @Nullable Method getLoadAllResourcesMethod() { + try { + final Method loadAllResourcesMethod = MimetypesFileTypeMap.class.getDeclaredMethod("loadAllResources", Vector.class, String[].class); + loadAllResourcesMethod.setAccessible(true); + return loadAllResourcesMethod; + } catch (final NoSuchMethodException e) { + LOG.error(e.getMessage(), e); + return null; + } + } + + @SuppressWarnings("RawUseOfParameterizedType") + private void loadAllResourcesRefl(final Method loadAllResourcesMethod, final Vector v, final String[] names) { + try { + loadAllResourcesMethod.invoke(this, v, (Object) names); + } catch (final IllegalAccessException | InvocationTargetException e) { + LOG.error(e.getMessage(), e); + } + } + + private static @Nullable Method getLoadResourceMethod() { + try { + final Method loadResourceMethod = MimetypesFileTypeMap.class.getDeclaredMethod("loadResource", String[].class); + loadResourceMethod.setAccessible(true); + return loadResourceMethod; + } catch (final NoSuchMethodException e) { + LOG.error(e.getMessage(), e); + return null; + } + } + + private @Nullable MimeTypeRegistry loadResourceRefl(final Method loadResourceMethod, final String[] names) { + try { + return (MimeTypeFile) loadResourceMethod.invoke(this, (Object) names); + } catch (final IllegalAccessException | InvocationTargetException e) { + LOG.error(e.getMessage(), e); + return null; + } + } + + private void setDBRefl(final MimeTypeRegistry[] DB) { + try { + final Field dbField = MimetypesFileTypeMap.class.getDeclaredField("DB"); + dbField.setAccessible(true); + dbField.set(this, DB); + } catch (final NoSuchFieldException | IllegalAccessException e) { + LOG.error(e.getMessage(), e); + } + } + + /** + * Get all the entries from the MimetypesFileTypeMap. + * + * @return the entries from the MimetypesFileTypeMap. + */ + @SuppressWarnings("unchecked") + IList>> getAllEntries() { + final MimeTypeRegistry[] mimeTypeRegistries; + try { + final Field dbField = MimetypesFileTypeMap.class.getDeclaredField("DB"); + dbField.setAccessible(true); + mimeTypeRegistries = (MimeTypeRegistry[]) dbField.get(this); + } catch (final NoSuchFieldException | IllegalAccessException e) { + LOG.error(e.getMessage(), e); + return null; + } + + if (mimeTypeRegistries == null) { + return null; + } + + final LinearList>> entries = new LinearList<>(); + final Field typeHashField; + try { + typeHashField = MimeTypeFile.class.getDeclaredField("type_hash"); + } catch (final NoSuchFieldException e) { + LOG.error(e.getMessage(), e); + return null; + } + typeHashField.setAccessible(true); + + try { + for (final MimeTypeRegistry mimeTypeRegistry : mimeTypeRegistries) { + if (mimeTypeRegistry != null) { + final Hashtable typeHash = (Hashtable) typeHashField.get(mimeTypeRegistry); + entries.addLast(typeHash.entrySet()); + } + } + } catch (final IllegalAccessException e) { + LOG.error("Unable to access type_hash from MimeTypeFile", e); + return null; + } + + return entries.forked(); + } +} diff --git a/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/MediaTypeImpl.java b/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/MediaTypeImpl.java new file mode 100644 index 0000000000..21ac682c9d --- /dev/null +++ b/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/MediaTypeImpl.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2014, Evolved Binary Ltd + * + * This file was originally ported from FusionDB to Elemental by + * Evolved Binary, for the benefit of the Elemental Open Source community. + * Only the ported code as it appears in this file, at the time that + * it was contributed to Elemental, was re-licensed under The GNU + * Lesser General Public License v2.1 only for use in Elemental. + * + * This license grant applies only to a snapshot of the code as it + * appeared when ported, it does not offer or infer any rights to either + * updates of this source code or access to the original source code. + * + * The GNU Lesser General Public License v2.1 only license follows. + * + * ===================================================================== + * + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package xyz.elemental.mediatype.impl; + +import io.lacuna.bifurcan.LinearSet; +import net.jcip.annotations.NotThreadSafe; +import net.jcip.annotations.ThreadSafe; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.StorageType; + +import javax.annotation.Nullable; + +/** + * Immutable implementation of a Media Type. + * + * @author Adam Retter + */ +@ThreadSafe +public class MediaTypeImpl implements MediaType { + + private final String identifier; + @Nullable private final String[] knownFileExtensions; + private final StorageType storageType; + + /** + * MediaTypeImpl is 100% immutable. + * + * Instead of calling the constructor you can incrementally + * build one via {@link Builder}. + */ + private MediaTypeImpl(final String identifier, @Nullable final String[] knownFileExtensions, final StorageType storageType) { + this.identifier = identifier; + this.knownFileExtensions = knownFileExtensions; + this.storageType = storageType; + } + + @Override + public String getIdentifier() { + return identifier; + } + + @Override + public @Nullable String[] getKnownFileExtensions() { + return knownFileExtensions; + } + + @Override + public StorageType getStorageType() { + return storageType; + } + + /** + * Construct a new Media Type. + * + * @param identifier the Media Type identifier + * @param storageType the database storage that should be used for resources of this Media Type + * + * @return a media type builder. + */ + public static MediaTypeImpl.Builder builder(final String identifier, final StorageType storageType) { + return Builder.forMediaType(identifier, storageType); + } + + /** + * Builder pattern which allows us to + * ultimately construct an Immutable MediaTypeImpl. + */ + @NotThreadSafe + public static class Builder { + private final String identifier; + private final StorageType storageType; + private final LinearSet knownFileExtensions = new LinearSet<>(); + + private Builder(final String identifier, final StorageType storageType) { + this.identifier = identifier; + this.storageType = storageType; + } + + /** + * Initiate the build of a MediaTypeImpl. + * + * @param identifier the Media Type identifier + * @param storageType the database storage that should be used for resources of this Media Type + */ + static Builder forMediaType(final String identifier, final StorageType storageType) { + return new Builder(identifier, storageType); + } + + /** + * Add a file extension for the Media Type. + * + * @param fileExtension a file extension + * @return this + */ + public Builder addFileExtension(final String fileExtension) { + knownFileExtensions.add(fileExtension); + return this; + } + + /** + * Build the Immutable MediaType. + * + * @return an immutable MediaType. + */ + public MediaType build() { + final String[] aryKnownFileExtensions = knownFileExtensions.size() > 0 ? knownFileExtensions.toArray(size -> new String[size]) : null; + return new MediaTypeImpl(identifier, aryKnownFileExtensions, storageType); + } + } +} diff --git a/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/MediaTypeMapper.java b/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/MediaTypeMapper.java new file mode 100644 index 0000000000..cc1786a2b3 --- /dev/null +++ b/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/MediaTypeMapper.java @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2014, Evolved Binary Ltd + * + * This file was originally ported from FusionDB to Elemental by + * Evolved Binary, for the benefit of the Elemental Open Source community. + * Only the ported code as it appears in this file, at the time that + * it was contributed to Elemental, was re-licensed under The GNU + * Lesser General Public License v2.1 only for use in Elemental. + * + * This license grant applies only to a snapshot of the code as it + * appeared when ported, it does not offer or infer any rights to either + * updates of this source code or access to the original source code. + * + * The GNU Lesser General Public License v2.1 only license follows. + * + * ===================================================================== + * + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package xyz.elemental.mediatype.impl; + +import io.lacuna.bifurcan.IList; +import io.lacuna.bifurcan.LinearList; +import net.jcip.annotations.NotThreadSafe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import xyz.elemental.mediatype.StorageType; +import xyz.elemental.mediatype.impl.configuration.MediaType; +import xyz.elemental.mediatype.impl.configuration.MediaTypeMappings; +import xyz.elemental.mediatype.impl.configuration.Storage; + +import javax.annotation.Nullable; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; +import jakarta.xml.bind.Unmarshaller; + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Maps Media Types to database Storage Types. + *

Mappings file search order.

+ * The MediaTypeMapper looks in various places in the user's + * system for media type mappings files. When requests are made + * to resolve media types to storage types, it searches + * mappings types files in the following order: + *

    + *
  1. The file media-type-mappings.xml from within the user's home directory: + * + *
  2. + *
  3. One or more files named media-type-mappings.xml in the Application's config directory(s).
  4. + *
  5. The file media-type-mappings.xml on the classpath in the package xyz.elemental.mediatype.
  6. + *
+ * + * @author Adam Retter + */ +@NotThreadSafe +public class MediaTypeMapper { + + private static final Logger LOG = LoggerFactory.getLogger(MediaTypeMapper.class); + + private static final String MEDIA_TYPE_MAPPINGS_FILENAME = "media-type-mappings.xml"; + + private final Function[] matchers; + + public MediaTypeMapper(@Nullable final Path... configDirs) { + final IList mappingsFileSources = getMappingsFileSources(configDirs); + this.matchers = loadMatchers(mappingsFileSources); + } + + private static IList getMappingsFileSources(final Path... configDirs) { + final LinearList mappingsFileSources = new LinearList<>(); + + LOG.trace("MediaTypeMapper: load HOME"); + @Nullable final Path userConfigFolder = PathUtil.getUserConfigFolder(); + if (userConfigFolder != null) { + final Path mappingsFile = userConfigFolder.resolve(MEDIA_TYPE_MAPPINGS_FILENAME); + if (!Files.exists(mappingsFile)) { + LOG.trace("No media-type-mappings.xml found at: {}, skipping...", mappingsFile.toAbsolutePath()); + } else { + mappingsFileSources.addLast(new MappingsFileSource(mappingsFile)); + } + } + + LOG.trace("MediaTypeMapper: load application"); + if (configDirs != null) { + for (final Path configDir : configDirs) { + final Path mappingsFile = configDir.resolve(MEDIA_TYPE_MAPPINGS_FILENAME); + if (!Files.exists(mappingsFile)) { + LOG.warn("No custom media-type-mappings.xml found at: {}, skipping...", mappingsFile.toAbsolutePath()); + } else { + mappingsFileSources.addLast(new MappingsFileSource(mappingsFile)); + } + } + } + + LOG.trace("ApplicationMimetypesFileTypeMap: load classpath from xyz.elemental.mediatype"); + final String classPathLocationStr = "xyz/elemental/mediatype/" + MEDIA_TYPE_MAPPINGS_FILENAME; + @Nullable final URL url = MediaTypeMapper.class.getClassLoader().getResource(classPathLocationStr); + if (url == null) { + LOG.trace("No media-type-mappings.xml found on classpath from xyz.elemental.mediatype, skipping..."); + } else { + final InputStream is = MediaTypeMapper.class.getClassLoader().getResourceAsStream(classPathLocationStr); + mappingsFileSources.addLast(new MappingsFileSource(url.toString(), is)); + } + + return mappingsFileSources.forked(); + } + + @SuppressWarnings("unchecked") + private static Function[] loadMatchers(final IList mappingsFileSources) { + try { + assert (!mappingsFileSources.isLinear()); + + final JAXBContext context; + final Unmarshaller unmarshaller; + try { + context = JAXBContext.newInstance(MediaTypeMappings.class); + unmarshaller = context.createUnmarshaller(); + } catch (final JAXBException e) { + LOG.error("Unable to instantiate JAXB Unmarshaller: {}", e.getMessage(), e); + return new Function[0]; + } + + final LinearList> matchersList = new LinearList<>(); + for (final MappingsFileSource mappingsFileSource : mappingsFileSources) { + if (mappingsFileSource.path != null && !Files.exists(mappingsFileSource.path)) { + LOG.warn("Mappings path {} does not exist, skipping...", mappingsFileSource.path); + continue; + } + + try { + final MediaTypeMappings mappings; + if (mappingsFileSource.path != null) { + mappings = (MediaTypeMappings) unmarshaller.unmarshal(mappingsFileSource.path.toUri().toURL()); + } else { + mappings = (MediaTypeMappings) unmarshaller.unmarshal(mappingsFileSource.is); + } + if (mappings == null || mappings.getStorage() == null || mappings.getStorage().isEmpty()) { + LOG.error("No mappings found in {} skipping...", mappingsFileSource.location); + continue; + } + + for (final Storage storage : mappings.getStorage()) { + for (final MediaType mediaType : storage.getMediaType()) { + + final StorageType storageType = toStorageType(storage.getType()); + final Function matcher; + switch (mediaType.getMatch()) { + case STARTS_WITH: + matcher = identifier -> { + if (identifier.startsWith(mediaType.getValue())) { + return storageType; + } else { + return null; + } + }; + break; + + case FULL: + matcher = identifier -> { + if (identifier.equals(mediaType.getValue())) { + return storageType; + } else { + return null; + } + }; + break; + + case PATTERN: + final Pattern pattern = Pattern.compile(mediaType.getValue()); + final Matcher patternMatcher = pattern.matcher(""); + matcher = identifier -> { + patternMatcher.reset(identifier); + if (patternMatcher.matches()) { + return storageType; + } else { + return null; + } + }; + break; + + default: + throw new IllegalArgumentException(); + } + + matchersList.addLast(matcher); + } + } + + } catch (final MalformedURLException | JAXBException e) { + @Nullable String message = e.getMessage(); + if (message == null) { + @Nullable final Throwable cause = e.getCause(); + if (cause != null) { + message = cause.getMessage(); + } + } + LOG.error("Skipping {} due to error: {}", mappingsFileSource.location, message, e); + } + } + + return matchersList.toArray(Function[]::new); + + } finally { + for (final MappingsFileSource mappingsFileSource : mappingsFileSources) { + if (mappingsFileSource.is != null) { + try { + mappingsFileSource.is.close(); + } catch (final IOException e) { + LOG.warn("Unable to close mappings file source: {} ", mappingsFileSource.location, e); + } + } + } + } + } + + private static StorageType toStorageType(final xyz.elemental.mediatype.impl.configuration.StorageType type) { + switch (type) { + case XML: + return StorageType.XML; + + case BINARY: + return StorageType.BINARY; + + default: + throw new IllegalArgumentException(); + } + } + + /** + * Given a Media Type identifier try and resolve its Storage Type. + * + * @param mediaTypeIdentifier the identifier of the Media Type. + * + * @return the Storage Type that should be used for the Media Type, + * or {@link StorageType#forUnknown()} if the storage type could not be resolved. + */ + public StorageType resolveStorageType(final String mediaTypeIdentifier) { + return resolveStorageType(mediaTypeIdentifier, StorageType.forUnknown()); + } + + /** + * Given a Media Type identifier try and resolve its Storage Type. + * + * @param mediaTypeIdentifier the identifier of the Media Type. + * @param defaultStorageType the default Storage Type to return if a Storage Type cannot + * be resolved for the Media Type identifier. + * + * @return the Storage Type that should be used for the Media Type, or {@link StorageType#forUnknown()} if the storage type could not be found. + */ + public @Nullable StorageType resolveStorageType(final String mediaTypeIdentifier, @Nullable final StorageType defaultStorageType) { + for (final Function matcher : matchers) { + final StorageType storageType = matcher.apply(mediaTypeIdentifier); + if (storageType != null) { + return storageType; + } + } + + return defaultStorageType; + } + + private static class MappingsFileSource { + private final String location; + + /** + * Either {@link #path} or {@link #is} will be set, but never both. + */ + @Nullable private final Path path; + @Nullable private final InputStream is; + + private MappingsFileSource(final Path path) { + this.location = path.normalize().toAbsolutePath().toString(); + this.path = path; + this.is = null; + } + + private MappingsFileSource(final String location, final InputStream is) { + this.location = location; + this.is = is; + this.path = null; + } + } +} diff --git a/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/MediaTypeResolverFactoryImpl.java b/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/MediaTypeResolverFactoryImpl.java new file mode 100644 index 0000000000..016a73f8e2 --- /dev/null +++ b/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/MediaTypeResolverFactoryImpl.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2014, Evolved Binary Ltd + * + * This file was originally ported from FusionDB to Elemental by + * Evolved Binary, for the benefit of the Elemental Open Source community. + * Only the ported code as it appears in this file, at the time that + * it was contributed to Elemental, was re-licensed under The GNU + * Lesser General Public License v2.1 only for use in Elemental. + * + * This license grant applies only to a snapshot of the code as it + * appeared when ported, it does not offer or infer any rights to either + * updates of this source code or access to the original source code. + * + * The GNU Lesser General Public License v2.1 only license follows. + * + * ===================================================================== + * + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package xyz.elemental.mediatype.impl; + +import xyz.elemental.mediatype.MediaTypeResolver; +import xyz.elemental.mediatype.MediaTypeResolverFactory; + +import javax.annotation.Nullable; +import java.nio.file.Path; + +/** + * Implementation of a Media Type Resolver Factory for + * constructing {@link MediaTypeResolverImpl} instances. + * + * @author Adam Retter + */ +public class MediaTypeResolverFactoryImpl implements MediaTypeResolverFactory { + + public MediaTypeResolverFactoryImpl() { + } + + @Override + public MediaTypeResolver newMediaTypeResolver() { + return newMediaTypeResolver((Path[]) null); + } + + @Override + public MediaTypeResolver newMediaTypeResolver(@Nullable final Path... configDirs) { + final ApplicationMimetypesFileTypeMap mimetypesFileTypeMap = new ApplicationMimetypesFileTypeMap( + configDirs); + final MediaTypeMapper mediaTypeMapper = new MediaTypeMapper(configDirs); + return new MediaTypeResolverImpl(mimetypesFileTypeMap, mediaTypeMapper); + } +} diff --git a/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/MediaTypeResolverImpl.java b/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/MediaTypeResolverImpl.java new file mode 100644 index 0000000000..cf654f90a4 --- /dev/null +++ b/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/MediaTypeResolverImpl.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2014, Evolved Binary Ltd + * + * This file was originally ported from FusionDB to Elemental by + * Evolved Binary, for the benefit of the Elemental Open Source community. + * Only the ported code as it appears in this file, at the time that + * it was contributed to Elemental, was re-licensed under The GNU + * Lesser General Public License v2.1 only for use in Elemental. + * + * This license grant applies only to a snapshot of the code as it + * appeared when ported, it does not offer or infer any rights to either + * updates of this source code or access to the original source code. + * + * The GNU Lesser General Public License v2.1 only license follows. + * + * ===================================================================== + * + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package xyz.elemental.mediatype.impl; + +import io.lacuna.bifurcan.IList; +import io.lacuna.bifurcan.LinearMap; +import jakarta.activation.MimeTypeEntry; +import jakarta.activation.MimetypesFileTypeMap; +import net.jcip.annotations.ThreadSafe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.MediaTypeResolver; +import xyz.elemental.mediatype.StorageType; + +import javax.annotation.Nullable; +import java.nio.file.Path; +import java.util.Map; +import java.util.Set; + +import static xyz.elemental.mediatype.MediaType.APPLICATION_OCTET_STREAM; + +/** + * Implementation of a Media Type Resolver. + * + * Sources the mappings between Media Types and File Extensions + * from a {@link MimetypesFileTypeMap}, and then further + * maps those onto database storage using a {@link MediaTypeMapper}. + * + * @author Adam Retter + */ +@ThreadSafe +public class MediaTypeResolverImpl implements MediaTypeResolver { + + private static final Logger LOG = LoggerFactory.getLogger(MediaTypeResolverImpl.class); + + private final io.lacuna.bifurcan.IMap extensionsIndex; + private final io.lacuna.bifurcan.IMap identifiersIndex; + + private final MediaType defaultMediaType; + + public MediaTypeResolverImpl(final ApplicationMimetypesFileTypeMap fileTypeMap, final MediaTypeMapper mediaTypeMapper) { + final IList>> allEntries = fileTypeMap.getAllEntries(); + if (allEntries == null) { + LOG.warn("Could not load file type maps. No mime types are known to the system!"); + this.extensionsIndex = io.lacuna.bifurcan.Map.empty(); + this.identifiersIndex = io.lacuna.bifurcan.Map.empty(); + this.defaultMediaType = null; + return; + } + assert(!allEntries.isLinear()); + + final LinearMap mutExtensionsIndex = new LinearMap<>(); + final LinearMap mutIdentifiersIndex = new LinearMap<>(); + + for (final Set> entrySet : allEntries) { + for (final Map.Entry entry : entrySet) { + final String fileExtension = entry.getKey().toLowerCase(); + final String identifier = entry.getValue().getMIMEType().toLowerCase(); + + MediaTypeImpl.Builder mediaTypeBuilder = mutExtensionsIndex.get(fileExtension, null); + if (mediaTypeBuilder == null) { + // not present in extensionsIndex + + mediaTypeBuilder = mutIdentifiersIndex.get(identifier, null); + if (mediaTypeBuilder == null) { + + // not present in identifiersIndex or extensionsIndex + mediaTypeBuilder = MediaTypeImpl.Builder + .forMediaType(identifier, mediaTypeMapper.resolveStorageType(identifier)) + .addFileExtension(fileExtension); + + mutExtensionsIndex.put(fileExtension, mediaTypeBuilder); + mutIdentifiersIndex.put(identifier, mediaTypeBuilder); + + } else { + + // present in identifiersIndex, but not extensionsIndex + mediaTypeBuilder.addFileExtension(fileExtension); + mutExtensionsIndex.put(fileExtension, mediaTypeBuilder); + } + } + } + } + + this.extensionsIndex = mutExtensionsIndex.mapValues((k, v) -> v.build()).forked(); + this.identifiersIndex = mutIdentifiersIndex.mapValues((k, v) -> v.build()).forked(); + + assert(!extensionsIndex.isLinear()); + assert(!identifiersIndex.isLinear()); + + this.defaultMediaType = identifiersIndex.get(APPLICATION_OCTET_STREAM) + .orElseGet(() -> MediaTypeImpl.Builder.forMediaType(APPLICATION_OCTET_STREAM, StorageType.BINARY).build()); + } + + @Override + public @Nullable MediaType fromFileName(@Nullable final Path path) { + if (path == null) { + return null; + } + return fromFileNameImpl(path.getFileName().toString()); + } + + @Override + public @Nullable MediaType fromFileName(@Nullable String path) { + if (path == null) { + return null; + } + + // if this is a path, just take the last segment i.e. the filename + int pathSepIdx = -1; + if ((pathSepIdx = path.lastIndexOf('/')) > -1) { + path = path.substring(pathSepIdx + 1); + } else if ((pathSepIdx = path.lastIndexOf('\\')) > -1) { + path = path.substring(pathSepIdx + 1); + } + + return fromFileNameImpl(path); + } + + private @Nullable MediaType fromFileNameImpl(final String fileName) { + final int idx = fileName.lastIndexOf("."); // period index + if (idx == -1) { + return null; + } + + final String extension = fileName.substring(idx + 1); + if (extension.isEmpty()) { + return null; + } + + return extensionsIndex.get(extension.toLowerCase(), null); + } + + @Override + public @Nullable MediaType fromString(@Nullable final String mediaType) { + if (mediaType == null) { + return null; + } + + return identifiersIndex.get(mediaType.toLowerCase(), null); + } + + @Override + public MediaType forUnknown() { + return defaultMediaType; + } +} diff --git a/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/PathUtil.java b/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/PathUtil.java new file mode 100644 index 0000000000..de54559a70 --- /dev/null +++ b/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/PathUtil.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2014, Evolved Binary Ltd + * + * This file was originally ported from FusionDB to Elemental by + * Evolved Binary, for the benefit of the Elemental Open Source community. + * Only the ported code as it appears in this file, at the time that + * it was contributed to Elemental, was re-licensed under The GNU + * Lesser General Public License v2.1 only for use in Elemental. + * + * This license grant applies only to a snapshot of the code as it + * appeared when ported, it does not offer or infer any rights to either + * updates of this source code or access to the original source code. + * + * The GNU Lesser General Public License v2.1 only license follows. + * + * ===================================================================== + * + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package xyz.elemental.mediatype.impl; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nullable; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static xyz.elemental.mediatype.impl.StringUtil.emptyStringAsNull; + +/** + * Utilities for working with Paths. + * + * @author Adam Retter + */ +class PathUtil { + + private static final Logger LOG = LoggerFactory.getLogger(PathUtil.class); + + /** + * Gets the config directory from the user's home folder. + * + * @return One of the following: + *
    + *
  • Linux/Unix: $XDG_CONFIG_HOME/elemental. If $XDG_CONFIG_HOME is not set then, ~/.config/elemental
  • + *
  • macOS: $XDG_CONFIG_HOME/elemental. If $XDG_CONFIG_HOME is not set then, ~/Library/Preferences/xyz.elemental
  • + *
  • Windows: %APPDATA%/Elemental. If %APPDATA% is not set then, %USERPROFILE%/AppData/Local/Elemental
  • + *
+ * or null if the environment variables or home folder cannot be resolved. + */ + static @Nullable Path getUserConfigFolder() { + final String osName = System.getProperty("os.name").toLowerCase(); + + if (osName.startsWith("windows")) { + // Windows + @Nullable String appDataPath = emptyStringAsNull(System.getenv("APPDATA")); + + if (appDataPath == null) { + @Nullable String userProfilePath = emptyStringAsNull(System.getProperty("user.home")); + if (userProfilePath == null) { + LOG.warn("Unable to find environment variables %APPDATA% or %USERPROFILE%"); + } else { + appDataPath = userProfilePath + "\\AppData\\Local"; + } + } + + if (appDataPath != null) { + return Paths.get(appDataPath, "Elemental"); + } + + } else { + @Nullable final String xdgConfigPath = emptyStringAsNull(System.getenv("XDG_CONFIG_HOME")); + if (xdgConfigPath != null) { + return Paths.get(xdgConfigPath, "elemental"); + } + + @Nullable final String homePath = System.getProperty("user.home"); + if (homePath == null) { + LOG.warn("Unable to find environment variable %HOME%"); + } else { + if (osName.startsWith("mac os x")) { + // macOS + return Paths.get(homePath, "Library", "Preferences", "xyz.elemental"); + + } else { + // Linux/Unix (or anything else) + return Paths.get(homePath, ".config", "elemental"); + } + } + } + + return null; + } + + /** + * Gets the data directory from the user's home folder. + * + * @return One of the following: + *
    + *
  • Linux/Unix: $XDG_DATA_HOME If $XDG_DATA_HOME is not set then, ~/.local/share
  • + *
  • macOS: $XDG_DATA_HOME. If $XDG_DATA_HOME is not set then, ~/Library/Application Support
  • + *
  • Windows: %APPDATA%. If %APPDATA% is not set then, %USERPROFILE%/AppData/Local
  • + *
+ * or null if the environment variables or home folder cannot be resolved. + */ + static @Nullable Path getUserDataFolder() { + final String osName = System.getProperty("os.name").toLowerCase(); + + if (osName.startsWith("windows")) { + // Windows + @Nullable String appDataPath = emptyStringAsNull(System.getenv("APPDATA")); + + if (appDataPath == null) { + @Nullable String userProfilePath = emptyStringAsNull(System.getProperty("user.home")); + if (userProfilePath == null) { + LOG.warn("Unable to find environment variables %APPDATA% or %USERPROFILE%"); + } else { + appDataPath = userProfilePath + "\\AppData\\Local"; + } + } + + if (appDataPath != null) { + return Paths.get(appDataPath); + } + + } else { + @Nullable final String xdgConfigPath = emptyStringAsNull(System.getenv("XDG_DATA_HOME")); + if (xdgConfigPath != null) { + return Paths.get(xdgConfigPath); + } + + @Nullable final String homePath = System.getProperty("user.home"); + if (homePath == null) { + LOG.warn("Unable to find environment variable %HOME%"); + } else { + if (osName.startsWith("mac os x")) { + // macOS + return Paths.get(homePath, "Library", "Application Support"); + + } else { + // Linux/Unix (or anything else) + return Paths.get(homePath, ".local", "share"); + } + } + } + + return null; + } +} diff --git a/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/StringUtil.java b/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/StringUtil.java new file mode 100644 index 0000000000..fb28ac87f2 --- /dev/null +++ b/elemental-media-type/elemental-media-type-impl/src/main/java/xyz/elemental/mediatype/impl/StringUtil.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014, Evolved Binary Ltd + * + * This file was originally ported from FusionDB to Elemental by + * Evolved Binary, for the benefit of the Elemental Open Source community. + * Only the ported code as it appears in this file, at the time that + * it was contributed to Elemental, was re-licensed under The GNU + * Lesser General Public License v2.1 only for use in Elemental. + * + * This license grant applies only to a snapshot of the code as it + * appeared when ported, it does not offer or infer any rights to either + * updates of this source code or access to the original source code. + * + * The GNU Lesser General Public License v2.1 only license follows. + * + * ===================================================================== + * + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package xyz.elemental.mediatype.impl; + +import javax.annotation.Nullable; + +/** + * Utilities for working with Strings. + * + * @author Adam Retter + */ +class StringUtil { + + static @Nullable String emptyStringAsNull(@Nullable String str) { + if (str != null) { + str = str.trim(); + if (str.isEmpty()) { + str = null; + } + } + return str; + } +} diff --git a/elemental-media-type/elemental-media-type-impl/src/main/resources/META-INF/services/xyz.elemental.mediatype.MediaTypeResolverFactory b/elemental-media-type/elemental-media-type-impl/src/main/resources/META-INF/services/xyz.elemental.mediatype.MediaTypeResolverFactory new file mode 100644 index 0000000000..cf19bc412e --- /dev/null +++ b/elemental-media-type/elemental-media-type-impl/src/main/resources/META-INF/services/xyz.elemental.mediatype.MediaTypeResolverFactory @@ -0,0 +1 @@ +xyz.elemental.mediatype.impl.MediaTypeResolverFactoryImpl \ No newline at end of file diff --git a/elemental-media-type/elemental-media-type-impl/src/main/xjb/media-type-mappings.xjb b/elemental-media-type/elemental-media-type-impl/src/main/xjb/media-type-mappings.xjb new file mode 100644 index 0000000000..7df9688282 --- /dev/null +++ b/elemental-media-type/elemental-media-type-impl/src/main/xjb/media-type-mappings.xjb @@ -0,0 +1,46 @@ + + + + + + + + + \ No newline at end of file diff --git a/elemental-media-type/elemental-media-type-impl/src/main/xsd/media-type-mappings.xsd b/elemental-media-type/elemental-media-type-impl/src/main/xsd/media-type-mappings.xsd new file mode 100644 index 0000000000..254bd9ed38 --- /dev/null +++ b/elemental-media-type/elemental-media-type-impl/src/main/xsd/media-type-mappings.xsd @@ -0,0 +1,156 @@ + + + + + + + Maps files of various Media Types to the type of storage + that should be used for persisting those files. + + + + + + + + + + + + Each type of storage should only appear once + + + + + + + + + The type of persistent storage to use for various Media Types + + + + + + + + + + + + Matches a Media Type + + + + + + + + + + + + + Types of persistent storage + + + + + Native XML document storage within the database + + + + + + + + + Binary document storage within the database + + + + + + + + Different types of Media Type matching + + + + + Media Type must exactly match the supplied value + + + + + Media Type(s) must start-with the supplied value + + + + + Media Type(s) must match the supplied Java Regular Expression + + + + + + + diff --git a/elemental-media-type/elemental-media-type-impl/src/test/java/xyz/elemental/mediatype/impl/MediaTypeResolverImplTest.java b/elemental-media-type/elemental-media-type-impl/src/test/java/xyz/elemental/mediatype/impl/MediaTypeResolverImplTest.java new file mode 100644 index 0000000000..f90a90d06e --- /dev/null +++ b/elemental-media-type/elemental-media-type-impl/src/test/java/xyz/elemental/mediatype/impl/MediaTypeResolverImplTest.java @@ -0,0 +1,833 @@ +/* + * Copyright (C) 2014, Evolved Binary Ltd + * + * This file was originally ported from FusionDB to Elemental by + * Evolved Binary, for the benefit of the Elemental Open Source community. + * Only the ported code as it appears in this file, at the time that + * it was contributed to Elemental, was re-licensed under The GNU + * Lesser General Public License v2.1 only for use in Elemental. + * + * This license grant applies only to a snapshot of the code as it + * appeared when ported, it does not offer or infer any rights to either + * updates of this source code or access to the original source code. + * + * The GNU Lesser General Public License v2.1 only license follows. + * + * ===================================================================== + * + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package xyz.elemental.mediatype.impl; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.MediaTypeResolver; +import xyz.elemental.mediatype.StorageType; + +import javax.annotation.Nullable; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class MediaTypeResolverImplTest { + + // TODO(AR) if an explicit content type is provided, e.g. HTTP PUT, store the mime type with the document data??? what if its not provided, lookup and store, or lookup on retrieval? + + private static MediaTypeMapper MEDIA_TYPE_MAPPER = null; + private static MediaTypeResolver DEFAULT_MEDIA_RESOLVER = null; + private static MediaTypeResolver APPLICATION_MEDIA_RESOLVER = null; + + @BeforeAll + public static void setupMediaResolvers() throws URISyntaxException { + @Nullable final URL mediaTypeMappings = MediaTypeResolverImplTest.class.getResource("media-type-mappings.xml"); + assertNotNull(mediaTypeMappings); + final Path configDir = Paths.get(mediaTypeMappings.toURI()).getParent(); + MEDIA_TYPE_MAPPER = new MediaTypeMapper(configDir); + + final ApplicationMimetypesFileTypeMap defaultMimetypesFileTypeMap = new ApplicationMimetypesFileTypeMap((Path[]) null); + DEFAULT_MEDIA_RESOLVER = new MediaTypeResolverImpl(defaultMimetypesFileTypeMap, MEDIA_TYPE_MAPPER); + + APPLICATION_MEDIA_RESOLVER = new MediaTypeResolverFactoryImpl().newMediaTypeResolver(configDir); + } + + // + @Test + public void allResolveAtomExtension() { + assertAllResolveFromFileName("something.atom", MediaType.APPLICATION_ATOM, new String[] {"atom"}, StorageType.XML); + } + + @Test + public void allResolveCsvExtension() { + assertAllResolveFromFileName("something.csv", MediaType.TEXT_CSV, new String[] {"csv"}, StorageType.BINARY); + } + + @Test + public void allResolveDocxExtension() { + assertAllResolveFromFileName("something.docx", MediaType.APPLICATION_OPENXML_WORDPROCESSING, new String[] {"docx"}, StorageType.XML); + } + + @Test + public void allResolveDtdExtension() { + assertAllResolveFromFileName("something.dtd", MediaType.APPLICATION_XML_DTD, new String[] {"dtd"}, StorageType.BINARY); + } + + @Test + public void allResolveGifExtension() { + assertAllResolveFromFileName("something.gif", MediaType.IMAGE_GIF, new String[] {"gif"}, StorageType.BINARY); + } + + @Test + public void allResolveGmlExtension() { + assertAllResolveFromFileName("something.gml", MediaType.APPLICATION_GML, new String[] {"gml"}, StorageType.XML); + } + + @Test + public void allResolveHtmExtension() { + assertAllResolveFromFileName("something.htm", MediaType.TEXT_HTML, new String[] {"htm", "html"}, StorageType.BINARY); + } + + @Test + public void allResolveHtmlExtension() { + assertAllResolveFromFileName("something.html", MediaType.TEXT_HTML, new String[] {"htm", "html"}, StorageType.BINARY); + } + + @Test + public void allResolveJpegExtension() { + assertAllResolveFromFileName("something.jpeg", MediaType.IMAGE_JPEG, new String[] {"jpe", "jpg", "jpeg"}, StorageType.BINARY); + } + + @Test + public void allResolveJpgExtension() { + assertAllResolveFromFileName("something.jpg", MediaType.IMAGE_JPEG, new String[] {"jpe", "jpg", "jpeg"}, StorageType.BINARY); + } + + @Test + public void allResolveJsExtension() { + assertAllResolveFromFileName("something.js", MediaType.TEXT_JAVASCRIPT, new String[] {"js", "mjs"}, StorageType.BINARY); + } + + @Test + public void allResolveJsonExtension() { + assertAllResolveFromFileName("something.json", MediaType.APPLICATION_JSON, new String[] {"json"}, StorageType.BINARY); + } + + @Test + public void allResolveMadsExtension() { + assertAllResolveFromFileName("something.mads", MediaType.APPLICATION_MADS, new String[] {"mads"}, StorageType.XML); + } + + @Test + public void allResolveMetsExtension() { + assertAllResolveFromFileName("something.mets", MediaType.APPLICATION_METS, new String[] {"mets"}, StorageType.XML); + } + + @Test + public void allResolveModsExtension() { + assertAllResolveFromFileName("something.mods", MediaType.APPLICATION_MODS, new String[] {"mods"}, StorageType.XML); + } + + @Test + public void allResolveMrcxExtension() { + assertAllResolveFromFileName("something.mrcx", MediaType.APPLICATION_MARC, new String[] {"mrcx"}, StorageType.XML); + } + + @Test + public void allResolveN3Extension() { + assertAllResolveFromFileName("something.n3", MediaType.TEXT_N3, new String[] {"n3"}, StorageType.BINARY); + } + + @Test + public void allResolveNcxExtension() { + assertAllResolveFromFileName("something.ncx", MediaType.APPLICATION_NCX, new String[] {"ncx"}, StorageType.XML); + } + + @Test + public void allResolveOdtExtension() { + assertAllResolveFromFileName("something.odt", MediaType.APPLICATION_OPENDOCUMENT_TEXT, new String[] {"odt"}, StorageType.XML); + } + + @Test + public void allResolveOdpExtension() { + assertAllResolveFromFileName("something.odp", MediaType.APPLICATION_OPENDOCUMENT_PRESENTATION, new String[] {"odp"}, StorageType.XML); + } + + @Test + public void allResolveOdsExtension() { + assertAllResolveFromFileName("something.ods", MediaType.APPLICATION_OPENDOCUMENT_SPREADSHEET, new String[] {"ods"}, StorageType.XML); + } + + @Test + public void allResolveOpfExtension() { + assertAllResolveFromFileName("something.opf", MediaType.APPLICATION_OEBPS_PACKAGE, new String[] {"opf"}, StorageType.XML); + } + + @Test + public void allResolvePngExtension() { + assertAllResolveFromFileName("something.png", MediaType.IMAGE_PNG, new String[] {"png"}, StorageType.BINARY); + } + + @Test + public void allResolvePptxExtension() { + assertAllResolveFromFileName("something.pptx", MediaType.APPLICATION_OPENXML_PRESENTATION, new String[] {"pptx"}, StorageType.XML); + } + + @Test + public void allResolveRncExtension() { + assertAllResolveFromFileName("something.rnc", MediaType.APPLICATION_RELAXNG_COMPACT, new String[] {"rnc"}, StorageType.BINARY); + } + + @Test + public void allResolveRssExtension() { + assertAllResolveFromFileName("something.rss", MediaType.APPLICATION_RSS, new String[] {"rss"}, StorageType.XML); + } + + @Test + public void allResolveSruExtension() { + assertAllResolveFromFileName("something.sru", MediaType.APPLICATION_SRU, new String[] {"sru"}, StorageType.XML); + } + + @Test + public void allResolveTtlExtension() { + assertAllResolveFromFileName("something.ttl", MediaType.TEXT_TURTLE, new String[] {"ttl"}, StorageType.BINARY); + } + + @Test + public void allResolveTxtExtension() { + assertAllResolveFromFileName("something.txt", MediaType.TEXT_PLAIN, new String[] {"txt", "def", "log", "in", "conf", "text", "list"}, StorageType.BINARY); + } + + @Test + public void allResolveWsdlExtension() { + assertAllResolveFromFileName("something.wsdl", MediaType.APPLICATION_WSDL, new String[] {"wsdl"}, StorageType.XML); + } + + @Test + public void allResolveXhtExtension() { + assertAllResolveFromFileName("something.xht", MediaType.APPLICATION_XHTML, new String[] {"xht", "xhtml"}, StorageType.XML); + } + + @Test + public void allResolveXhtmlExtension() { + assertAllResolveFromFileName("something.xhtml", MediaType.APPLICATION_XHTML, new String[] {"xht", "xhtml"}, StorageType.XML); + } + + @Test + public void allResolveXlsxExtension() { + assertAllResolveFromFileName("something.xlsx", MediaType.APPLICATION_OPENXML_SPREADSHEET, new String[] {"xlsx"}, StorageType.XML); + } + + @Test + public void allResolveXplExtension() { + assertAllResolveFromFileName("something.xpl", MediaType.APPLICATION_XPROC, new String[] {"xpl"}, StorageType.XML); + } + + @Test + public void allResolveXsltExtension() { + assertAllResolveFromFileName("something.xslt", MediaType.APPLICATION_XSLT, new String[] {"xslt"}, StorageType.XML); + } + + @Test + public void allResolveAtomIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_ATOM, new String[] {"atom"}, StorageType.XML); + } + + @Test + public void allResolveCsvIdentifier() { + assertAllResolveFromIdentifier(MediaType.TEXT_CSV, new String[] {"csv"}, StorageType.BINARY); + } + + @Test + public void allResolveDocxIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_OPENXML_WORDPROCESSING, new String[] {"docx"}, StorageType.XML); + } + + @Test + public void allResolveDtdIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_XML_DTD, new String[] {"dtd"}, StorageType.BINARY); + } + + @Test + public void allResolveGifIdentifier() { + assertAllResolveFromIdentifier(MediaType.IMAGE_GIF, new String[] {"gif"}, StorageType.BINARY); + } + + @Test + public void allResolveGmlIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_GML, new String[] {"gml"}, StorageType.XML); + } + + @Test + public void allResolveHtmlIdentifier() { + assertAllResolveFromIdentifier(MediaType.TEXT_HTML, new String[] {"htm", "html"}, StorageType.BINARY); + } + + @Test + public void allResolveJpegIdentifier() { + assertAllResolveFromIdentifier(MediaType.IMAGE_JPEG, new String[] {"jpe", "jpg", "jpeg"}, StorageType.BINARY); + } + + @Test + public void allResolveJsIdentifier() { + assertAllResolveFromIdentifier(MediaType.TEXT_JAVASCRIPT, new String[] {"js", "mjs"}, StorageType.BINARY); + } + + @Test + public void allResolveJsonIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_JSON, new String[] {"json"}, StorageType.BINARY); + } + + @Test + public void allResolveMadsIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_MADS, new String[] {"mads"}, StorageType.XML); + } + + @Test + public void allResolveMetsIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_METS, new String[] {"mets"}, StorageType.XML); + } + + @Test + public void allResolveModsIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_MODS, new String[] {"mods"}, StorageType.XML); + } + + @Test + public void allResolveMrcxIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_MARC, new String[] {"mrcx"}, StorageType.XML); + } + + @Test + public void allResolveN3Identifier() { + assertAllResolveFromIdentifier(MediaType.TEXT_N3, new String[] {"n3"}, StorageType.BINARY); + } + + @Test + public void allResolveNcxIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_NCX, new String[] {"ncx"}, StorageType.XML); + } + + @Test + public void allResolveOdtIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_OPENDOCUMENT_TEXT, new String[] {"odt"}, StorageType.XML); + } + + @Test + public void allResolveOdpIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_OPENDOCUMENT_PRESENTATION, new String[] {"odp"}, StorageType.XML); + } + + @Test + public void allResolveOdsIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_OPENDOCUMENT_SPREADSHEET, new String[] {"ods"}, StorageType.XML); + } + + @Test + public void allResolveOpfIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_OEBPS_PACKAGE, new String[] {"opf"}, StorageType.XML); + } + + @Test + public void allResolvePngIdentifier() { + assertAllResolveFromIdentifier(MediaType.IMAGE_PNG, new String[] {"png"}, StorageType.BINARY); + } + + @Test + public void allResolvePptxIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_OPENXML_PRESENTATION, new String[] {"pptx"}, StorageType.XML); + } + + @Test + public void allResolveRncIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_RELAXNG_COMPACT, new String[] {"rnc"}, StorageType.BINARY); + } + + @Test + public void allResolveRssIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_RSS, new String[] {"rss"}, StorageType.XML); + } + + @Test + public void allResolveSruIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_SRU, new String[] {"sru"}, StorageType.XML); + } + + @Test + public void allResolveTtlIdentifier() { + assertAllResolveFromIdentifier(MediaType.TEXT_TURTLE, new String[] {"ttl"}, StorageType.BINARY); + } + + @Test + public void allResolveTxtIdentifier() { + assertAllResolveFromIdentifier(MediaType.TEXT_PLAIN, new String[] {"txt", "def", "log", "in", "conf", "text", "list"}, StorageType.BINARY); + } + + @Test + public void allResolveWsdlIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_WSDL, new String[] {"wsdl"}, StorageType.XML); + } + + @Test + public void allResolveXhtmlIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_XHTML, new String[] {"xht", "xhtml"}, StorageType.XML); + } + + @Test + public void allResolveXlsxIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_OPENXML_SPREADSHEET, new String[] {"xlsx"}, StorageType.XML); + } + + @Test + public void allResolveXplIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_XPROC, new String[] {"xpl"}, StorageType.XML); + } + + @Test + public void allResolveXsltIdentifier() { + assertAllResolveFromIdentifier(MediaType.APPLICATION_XSLT, new String[] {"xslt"}, StorageType.XML); + } + // + + + // + @Test + public void defaultResolveRdfExtension() { + assertDefaultResolveFromFileName("something.rdf", MediaType.APPLICATION_RDF_XML, new String[] {"rdf"}, StorageType.XML); + } + + /** + * The Media Type for SVGZ is horribly broken, see: w3c/svgwg/issues/701 + * So it is overridden in the application's own mime.types file, + * see {@link #applicationResolveSvgExtension()}. + */ + @Test + public void defaultResolveSvgExtension() { + assertDefaultResolveFromFileName("something.svg", MediaType.IMAGE_SVG, new String[] {"svg", "svgz"}, StorageType.XML); + } + + /** + * The Media Type for SVGZ is horribly broken, see: w3c/svgwg/issues/701 + * So it is overridden in the application's own mime.types file, + * see {@link #applicationResolveSvgzExtension()}. + */ + @Test + public void defaultResolveSvgzExtension() { + assertDefaultResolveFromFileName("something.svgz", MediaType.IMAGE_SVG, new String[] {"svg", "svgz"}, StorageType.XML); + } + + @Test + public void defaultResolveTeiExtension() { + assertDefaultResolveFromFileName("something.tei", MediaType.APPLICATION_TEI, new String[] {"tei", "teicorpus"}, StorageType.XML); + } + + @Test + public void defaultResolveTeicorpusExtension() { + assertDefaultResolveFromFileName("something.teicorpus", MediaType.APPLICATION_TEI, new String[] {"tei", "teicorpus"}, StorageType.XML); + } + + @Test + public void defaultResolveXmlExtension() { + assertDefaultResolveFromFileName("something.xml", MediaType.APPLICATION_XML, new String[] {"xsl", "xml"}, StorageType.XML); + } + + @Test + public void defaultResolveXslExtension() { + assertDefaultResolveFromFileName("something.xsl", MediaType.APPLICATION_XML, new String[] {"xsl", "xml"}, StorageType.XML); + } + + @Test + public void defaultResolveRdfIdentifier() { + assertDefaultResolveFromIdentifier(MediaType.APPLICATION_RDF_XML, new String[] {"rdf"}, StorageType.XML); + } + + /** + * The Media Type for SVGZ is horribly broken, see: w3c/svgwg/issues/701 + * So it is overridden in the application's own mime.types file. + */ + @Test + public void defaultResolveSvgIdentifier() { + assertDefaultResolveFromIdentifier(MediaType.IMAGE_SVG, new String[] {"svg", "svgz"}, StorageType.XML); + } + + @Test + public void defaultResolveTeiIdentifier() { + assertDefaultResolveFromIdentifier(MediaType.APPLICATION_TEI, new String[] {"tei", "teicorpus"}, StorageType.XML); + } + + @Test + public void defaultResolveXmlIdentifier() { + assertDefaultResolveFromIdentifier(MediaType.APPLICATION_XML, new String[] {"xsl", "xml"}, StorageType.XML); + } + // + + + // + @Test + public void applicationResolveDitaExtension() { + assertApplicationResolveFromFileName("something.dita",MediaType.APPLICATION_DITA, new String[] {"dita", "ditamap", "ditaval"}, StorageType.XML); + } + + @Test + public void applicationResolveDitamapExtension() { + assertApplicationResolveFromFileName("something.ditamap",MediaType.APPLICATION_DITA, new String[] {"dita", "ditamap", "ditaval"}, StorageType.XML); + } + + @Test + public void applicationResolveDitavalExtension() { + assertApplicationResolveFromFileName("something.ditaval",MediaType.APPLICATION_DITA, new String[] {"dita", "ditamap", "ditaval"}, StorageType.XML); + } + + @Test + public void applicationResolveFoExtension() { + assertApplicationResolveFromFileName("something.fo", MediaType.APPLICATION_XML, new String[] {"fo", "nvdl", "rng", "stx", "xconf", "xml", "xsd", "xsl"}, StorageType.XML); + } + + @Test + public void applicationResolveNvdlExtension() { + assertApplicationResolveFromFileName("something.nvdl", MediaType.APPLICATION_XML, new String[] {"fo", "nvdl", "rng", "stx", "xconf", "xml", "xsd", "xsl"}, StorageType.XML); + } + + @Test + public void applicationResolveOddExtension() { + assertApplicationResolveFromFileName("something.odd", MediaType.APPLICATION_TEI, new String[] {"odd", "tei", "teicorpus"}, StorageType.XML); + } + + @Test + public void applicationResolveOwlExtension() { + assertApplicationResolveFromFileName("something.owl", MediaType.APPLICATION_RDF_XML, new String[] {"xmp", "owl", "rdf"}, StorageType.XML); + } + + @Test + public void applicationResolveMdExtension() { + assertApplicationResolveFromFileName("something.md", MediaType.TEXT_MARKDOWN, new String[] {"md"}, StorageType.BINARY); + } + + @Test + public void applicationResolveRdfExtension() { + assertApplicationResolveFromFileName("something.rdf", MediaType.APPLICATION_RDF_XML, new String[] {"xmp", "owl", "rdf"}, StorageType.XML); + } + + @Test + public void applicationResolveRngExtension() { + assertApplicationResolveFromFileName("something.rng", MediaType.APPLICATION_XML, new String[] {"fo", "nvdl", "rng", "stx", "xconf", "xml", "xsd", "xsl"}, StorageType.XML); + } + + @Test + public void applicationResolveSchExtension() { + assertApplicationResolveFromFileName("something.sch", MediaType.APPLICATION_SCHEMATRON, new String[] {"sch"}, StorageType.XML); + } + + @Test + public void applicationResolveStxExtension() { + assertApplicationResolveFromFileName("something.stx", MediaType.APPLICATION_XML, new String[] {"fo", "nvdl", "rng", "stx", "xconf", "xml", "xsd", "xsl"}, StorageType.XML); + } + + @Test + public void applicationResolveSvgExtension() { + assertApplicationResolveFromFileName("something.svg", MediaType.IMAGE_SVG, new String[] {"svg", "svgz"}, StorageType.XML); + } + + @Test + public void applicationResolveSvgzExtension() { + assertApplicationResolveFromFileName("something.svgz", MediaType.IMAGE_SVG_GZIP, new String[] {"svg", "svgz"}, StorageType.XML); + } + + @Test + public void applicationResolveTeiExtension() { + assertApplicationResolveFromFileName("something.tei", MediaType.APPLICATION_TEI, new String[] {"odd", "tei", "teicorpus"}, StorageType.XML); + } + + @Test + public void applicationResolveTeicorpusExtension() { + assertApplicationResolveFromFileName("something.teicorpus", MediaType.APPLICATION_TEI, new String[] {"odd", "tei", "teicorpus"}, StorageType.XML); + } + + @Test + public void applicationResolveXarExtension() { + assertApplicationResolveFromFileName("something.xar", MediaType.APPLICATION_EXPATH_PACKAGE_ZIP, new String[] {"xar"}, StorageType.BINARY); + } + + @Test + public void applicationResolveXconfExtension() { + assertApplicationResolveFromFileName("something.xconf", MediaType.APPLICATION_XML, new String[] {"fo", "nvdl", "rng", "stx", "xconf", "xml", "xsd", "xsl"}, StorageType.XML); + } + + @Test + public void applicationResolveXmiExtension() { + assertApplicationResolveFromFileName("something.xmi", MediaType.APPLICATION_XMI, new String[] {"xmi"}, StorageType.XML); + } + + @Test + public void applicationResolveXmlExtension() { + assertApplicationResolveFromFileName("something.xml", MediaType.APPLICATION_XML, new String[] {"fo", "nvdl", "rng", "stx", "xconf", "xml", "xsd", "xsl"}, StorageType.XML); + } + + @Test + public void applicationResolveXmpExtension() { + assertApplicationResolveFromFileName("something.xmp", MediaType.APPLICATION_RDF_XML, new String[] {"xmp", "owl", "rdf"}, StorageType.XML); + } + + @Test + public void applicationResolveXqExtension() { + assertApplicationResolveFromFileName("something.xq", MediaType.APPLICATION_XQUERY, new String[] {"xq", "xql", "xqm", "xquery", "xqws", "xqy"}, StorageType.BINARY); + } + + @Test + public void applicationResolveXqlExtension() { + assertApplicationResolveFromFileName("something.xql", MediaType.APPLICATION_XQUERY, new String[] {"xq", "xql", "xqm", "xquery", "xqws", "xqy"}, StorageType.BINARY); + } + + @Test + public void applicationResolveXqmExtension() { + assertApplicationResolveFromFileName("something.xqm", MediaType.APPLICATION_XQUERY, new String[] {"xq", "xql", "xqm", "xquery", "xqws", "xqy"}, StorageType.BINARY); + } + + @Test + public void applicationResolveXqueryExtension() { + assertApplicationResolveFromFileName("something.xquery", MediaType.APPLICATION_XQUERY, new String[] {"xq", "xql", "xqm", "xquery", "xqws", "xqy"}, StorageType.BINARY); + } + + @Test + public void applicationResolveXqwsExtension() { + assertApplicationResolveFromFileName("something.xqws", MediaType.APPLICATION_XQUERY, new String[] {"xq", "xql", "xqm", "xquery", "xqws", "xqy"}, StorageType.BINARY); + } + + @Test + public void applicationResolveXqxExtension() { + assertApplicationResolveFromFileName("something.xqx", MediaType.APPLICATION_XQUERY_XML, new String[] {"xqx"}, StorageType.XML); + } + + @Test + public void applicationResolveXqyExtension() { + assertApplicationResolveFromFileName("something.xqy", MediaType.APPLICATION_XQUERY, new String[] {"xq", "xql", "xqm", "xquery", "xqws", "xqy"}, StorageType.BINARY); + } + + @Test + public void applicationResolveXsdExtension() { + assertApplicationResolveFromFileName("something.xsd", MediaType.APPLICATION_XML, new String[] {"fo", "nvdl", "rng", "stx", "xconf", "xml", "xsd", "xsl"}, StorageType.XML); + } + + @Test + public void applicationResolveXslExtension() { + assertApplicationResolveFromFileName("something.xsl", MediaType.APPLICATION_XML, new String[] {"fo", "nvdl", "rng", "stx", "xconf", "xml", "xsd", "xsl"}, StorageType.XML); + } + + @Test + public void applicationResolveDitaIdentifier() { + assertApplicationResolveFromIdentifier(MediaType.APPLICATION_DITA, new String[] {"dita", "ditamap", "ditaval"}, StorageType.XML); + } + + @Test + public void applicationResolveMdIdentifier() { + assertApplicationResolveFromIdentifier(MediaType.TEXT_MARKDOWN, new String[] {"md"}, StorageType.BINARY); + } + + @Test + public void applicationResolveRdfIdentifier() { + assertApplicationResolveFromIdentifier(MediaType.APPLICATION_RDF_XML, new String[] {"xmp", "owl", "rdf"}, StorageType.XML); + } + + @Test + public void applicationResolveSchIdentifier() { + assertApplicationResolveFromIdentifier(MediaType.APPLICATION_SCHEMATRON, new String[] {"sch"}, StorageType.XML); + } + + @Test + public void applicationResolveSvgIdentifier() { + assertApplicationResolveFromIdentifier(MediaType.IMAGE_SVG, new String[] {"svg", "svgz"}, StorageType.XML); + } + + @Test + public void applicationResolveSvgzIdentifier() { + assertApplicationResolveFromIdentifier(MediaType.IMAGE_SVG_GZIP, new String[] {"svg", "svgz"}, StorageType.XML); + } + + @Test + public void applicationResolveTeiIdentifier() { + assertApplicationResolveFromIdentifier(MediaType.APPLICATION_TEI, new String[] {"odd", "tei", "teicorpus"}, StorageType.XML); + } + + @Test + public void applicationResolveXmiIdentifier() { + assertApplicationResolveFromIdentifier(MediaType.APPLICATION_XMI, new String[] {"xmi"}, StorageType.XML); + } + + @Test + public void applicationResolveXmlIdentifier() { + assertApplicationResolveFromIdentifier(MediaType.APPLICATION_XML, new String[] {"fo", "nvdl", "rng", "stx", "xconf", "xml", "xsd", "xsl"}, StorageType.XML); + } + + @Test + public void applicationResolveXqueryIdentifier() { + assertApplicationResolveFromIdentifier(MediaType.APPLICATION_XQUERY, new String[] {"xq", "xql", "xqm", "xquery", "xqws", "xqy"}, StorageType.BINARY); + } + + @Test + public void applicationResolveXqueryXIdentifier() { + assertApplicationResolveFromIdentifier(MediaType.APPLICATION_XQUERY_XML, new String[] {"xqx"}, StorageType.XML); + } + // + + + /** + * Check that multiple levels of mime.types files + * yield correct lookups via. both + * ApplicationMimetypesFileTypeMap and MediaTypeResolverImpl. + */ + @Test + public void resolveFromCorrectLevel() throws URISyntaxException { + @Nullable final URL defaultApplicationMimeTypes = MediaTypeResolverImplTest.class.getResource("mime.types"); + assertNotNull(defaultApplicationMimeTypes); + final Path defaultApplicationTypesConfigDir = Paths.get(defaultApplicationMimeTypes.toURI()).getParent(); + final String packageNamePath = MediaTypeResolverImplTest.class.getPackage().getName().replace('.', '/'); + + @Nullable final URL moreSpecificMimeTypes = MediaTypeResolverImplTest.class.getResource("/" + packageNamePath + "/test/levels/mime.types"); + assertNotNull(moreSpecificMimeTypes); + final Path moreSpecificApplicationTypesConfigDir = Paths.get(moreSpecificMimeTypes.toURI()).getParent(); + + // NOTE(AR) moreSpecificApplicationTypesConfigDir is provided first so that it has highest priority + final ApplicationMimetypesFileTypeMap mimetypesFileTypeMap = new ApplicationMimetypesFileTypeMap( + moreSpecificApplicationTypesConfigDir, + defaultApplicationTypesConfigDir); + + assertEquals("test/extensible-markup-language", mimetypesFileTypeMap.getContentType("something.xadam")); + assertEquals("test/prs.existdb.collection-config+xml", mimetypesFileTypeMap.getContentType("something.xconf")); + assertEquals("test/extensible-markup-language", mimetypesFileTypeMap.getContentType("something.xml")); + assertEquals(MediaType.APPLICATION_XML, mimetypesFileTypeMap.getContentType("something.xsd")); + assertEquals("test/x.xsl+xml", mimetypesFileTypeMap.getContentType("something.xsl")); + + final MediaTypeResolverImpl specificMediaTypeResolver = new MediaTypeResolverImpl(mimetypesFileTypeMap, MEDIA_TYPE_MAPPER); + + assertResolveFromFileName(specificMediaTypeResolver, "something.xadam", "test/extensible-markup-language", new String[] {"xml", "xadam"}, StorageType.BINARY); + assertResolveFromFileName(specificMediaTypeResolver, "something.xconf", "test/prs.existdb.collection-config+xml", new String[] {"xconf"}, StorageType.XML); + assertResolveFromFileName(specificMediaTypeResolver, "something.xml", "test/extensible-markup-language", new String[] {"xml", "xadam"}, StorageType.BINARY); + assertResolveFromFileName(specificMediaTypeResolver, "something.xsd", MediaType.APPLICATION_XML, new String[] {"nvdl", "stx", "xsd", "fo", "rng"}, StorageType.XML); + assertResolveFromFileName(specificMediaTypeResolver, "something.xsl", "test/x.xsl+xml", new String[] {"xsl"}, StorageType.XML); + + assertResolveFromIdentifier(specificMediaTypeResolver, "test/extensible-markup-language", new String[] { "xml", "xadam" }, StorageType.BINARY); + assertResolveFromIdentifier(specificMediaTypeResolver, "test/prs.existdb.collection-config+xml", new String[] {"xconf"}, StorageType.XML); + assertResolveFromIdentifier(specificMediaTypeResolver, MediaType.APPLICATION_XML, new String[] {"nvdl", "stx", "xsd", "fo", "rng"}, StorageType.XML); + assertResolveFromIdentifier(specificMediaTypeResolver, "test/x.xsl+xml", new String[] {"xsl"}, StorageType.XML); + } + + // + @Test + public void allResolveNonExistentExtension() { + final String fileName = "something.nonexistent"; + + final MediaTypeResolver[] allResolvers = { + DEFAULT_MEDIA_RESOLVER, + APPLICATION_MEDIA_RESOLVER + }; + + for (final MediaTypeResolver resolver : allResolvers) { + assertNotNull(resolver); + + @Nullable MediaType mediaType = resolver.fromFileName(fileName); + assertNull(mediaType); + mediaType = resolver.fromFileName(Paths.get(fileName)); + assertNull(mediaType); + } + } + + @Test + public void allResolveNonExistentIdentifier() { + final String identifier = "non/existent"; + + final MediaTypeResolver[] allResolvers = { + DEFAULT_MEDIA_RESOLVER, + APPLICATION_MEDIA_RESOLVER + }; + + for (final MediaTypeResolver resolver : allResolvers) { + assertNotNull(resolver); + + @Nullable MediaType mediaType = resolver.fromString(identifier); + assertNull(mediaType); + } + } + // + + private void assertAllResolveFromFileName(final String fileName, final String expectedIdentifier, final String[] expectedExtensions, final StorageType expectedStorageType) { + assertDefaultResolveFromFileName(fileName, expectedIdentifier, expectedExtensions, expectedStorageType); + assertApplicationResolveFromFileName(fileName, expectedIdentifier, expectedExtensions, expectedStorageType); + } + + private void assertDefaultResolveFromFileName(final String fileName, final String expectedIdentifier, final String[] expectedExtensions, final StorageType expectedStorageType) { + assertNotNull(DEFAULT_MEDIA_RESOLVER); + assertResolveFromFileName(DEFAULT_MEDIA_RESOLVER, fileName, expectedIdentifier, expectedExtensions, expectedStorageType); + } + + private void assertApplicationResolveFromFileName(final String fileName, final String expectedIdentifier, final String[] expectedExtensions, final StorageType expectedStorageType) { + assertNotNull(APPLICATION_MEDIA_RESOLVER); + assertResolveFromFileName(APPLICATION_MEDIA_RESOLVER, fileName, expectedIdentifier, expectedExtensions, expectedStorageType); + } + + private void assertResolveFromFileName(final MediaTypeResolver mediaTypeResolver, final String fileName, final String expectedIdentifier, final String[] expectedExtensions, final StorageType expectedStorageType) { + // by String + @Nullable MediaType mediaType = mediaTypeResolver.fromFileName(fileName); + assertNotNull(mediaType); + assertEquals(expectedIdentifier, mediaType.getIdentifier()); + assertArrayAnyOrderEquals(expectedExtensions, mediaType.getKnownFileExtensions()); + assertEquals(expectedStorageType, mediaType.getStorageType()); + + // by Path + mediaType = mediaTypeResolver.fromFileName(Paths.get(fileName)); + assertNotNull(mediaType); + assertEquals(expectedIdentifier, mediaType.getIdentifier()); + assertArrayAnyOrderEquals(expectedExtensions, mediaType.getKnownFileExtensions()); + assertEquals(expectedStorageType, mediaType.getStorageType()); + } + + private void assertAllResolveFromIdentifier(final String identifier, final String[] expectedExtensions, final StorageType expectedStorageType) { + assertDefaultResolveFromIdentifier(identifier, expectedExtensions, expectedStorageType); + assertApplicationResolveFromIdentifier(identifier, expectedExtensions, expectedStorageType); + } + + private void assertDefaultResolveFromIdentifier(final String identifier, final String[] expectedExtensions, final StorageType expectedStorageType) { + assertNotNull(DEFAULT_MEDIA_RESOLVER); + assertResolveFromIdentifier(DEFAULT_MEDIA_RESOLVER, identifier, expectedExtensions, expectedStorageType); + } + + private void assertApplicationResolveFromIdentifier(final String identifier, final String[] expectedExtensions, final StorageType expectedStorageType) { + assertNotNull(APPLICATION_MEDIA_RESOLVER); + assertResolveFromIdentifier(APPLICATION_MEDIA_RESOLVER, identifier, expectedExtensions, expectedStorageType); + } + + private void assertResolveFromIdentifier(final MediaTypeResolver mediaTypeResolver, final String identifier, final String[] expectedExtensions, final StorageType expectedStorageType) { + final @Nullable MediaType mediaType = mediaTypeResolver.fromString(identifier); + assertNotNull(mediaType); + assertArrayAnyOrderEquals(expectedExtensions, mediaType.getKnownFileExtensions()); + assertEquals(expectedStorageType, mediaType.getStorageType()); + } + + private static void assertArrayAnyOrderEquals(final T[] expected, final T[] actual) { + Arrays.sort(expected); + Arrays.sort(actual); + assertArrayEquals(expected, actual); + } +} diff --git a/elemental-media-type/elemental-media-type-impl/src/test/resources/xyz/elemental/mediatype/impl/media-type-mappings.xml b/elemental-media-type/elemental-media-type-impl/src/test/resources/xyz/elemental/mediatype/impl/media-type-mappings.xml new file mode 100644 index 0000000000..6d8e835bbf --- /dev/null +++ b/elemental-media-type/elemental-media-type-impl/src/test/resources/xyz/elemental/mediatype/impl/media-type-mappings.xml @@ -0,0 +1,50 @@ + + + + + + application/xml + text/xml + application/vnd.oasis.opendocument. + application/vnd.openxmlformats- + [^+]+\+xml$ + + + \ No newline at end of file diff --git a/elemental-media-type/elemental-media-type-impl/src/test/resources/xyz/elemental/mediatype/impl/mime.types b/elemental-media-type/elemental-media-type-impl/src/test/resources/xyz/elemental/mediatype/impl/mime.types new file mode 100644 index 0000000000..593bca4d7f --- /dev/null +++ b/elemental-media-type/elemental-media-type-impl/src/test/resources/xyz/elemental/mediatype/impl/mime.types @@ -0,0 +1,51 @@ +# +# Copyright (C) 2014, Evolved Binary Ltd +# +# This file was originally ported from FusionDB to Elemental by +# Evolved Binary, for the benefit of the Elemental Open Source community. +# Only the ported code as it appears in this file, at the time that +# it was contributed to Elemental, was re-licensed under The GNU +# Lesser General Public License v2.1 only for use in Elemental. +# +# This license grant applies only to a snapshot of the code as it +# appeared when ported, it does not offer or infer any rights to either +# updates of this source code or access to the original source code. +# +# The GNU Lesser General Public License v2.1 only license follows. +# +# ===================================================================== +# +# Elemental +# Copyright (C) 2024, Evolved Binary Ltd +# +# admin@evolvedbinary.com +# https://www.evolvedbinary.com | https://www.elemental.xyz +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; version 2.1. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +application/dita+xml dita ditamap ditaval +application/prs.existdb.collection-config+xml xconf +application/prs.expath.package+zip xar +application/rdf+xml xmp owl rdf +application/schematron+xml sch +application/tei+xml odd tei teicorpus +application/vnd.xmi+xml xmi +application/xml fo nvdl rng stx xconf xml xsd xsl +application/xquery xq xql xqm xquery xqws xqy +application/xquery+xml xqx +image/svg+xml svg svgz +# See: https://github.com/w3c/svgwg/issues/701 +# image/x.svg+gzip svgz +text/markdown md \ No newline at end of file diff --git a/elemental-media-type/elemental-media-type-impl/src/test/resources/xyz/elemental/mediatype/impl/test/levels/mime.types b/elemental-media-type/elemental-media-type-impl/src/test/resources/xyz/elemental/mediatype/impl/test/levels/mime.types new file mode 100644 index 0000000000..3c4966cf55 --- /dev/null +++ b/elemental-media-type/elemental-media-type-impl/src/test/resources/xyz/elemental/mediatype/impl/test/levels/mime.types @@ -0,0 +1,41 @@ +# +# Copyright (C) 2014, Evolved Binary Ltd +# +# This file was originally ported from FusionDB to Elemental by +# Evolved Binary, for the benefit of the Elemental Open Source community. +# Only the ported code as it appears in this file, at the time that +# it was contributed to Elemental, was re-licensed under The GNU +# Lesser General Public License v2.1 only for use in Elemental. +# +# This license grant applies only to a snapshot of the code as it +# appeared when ported, it does not offer or infer any rights to either +# updates of this source code or access to the original source code. +# +# The GNU Lesser General Public License v2.1 only license follows. +# +# ===================================================================== +# +# Elemental +# Copyright (C) 2024, Evolved Binary Ltd +# +# admin@evolvedbinary.com +# https://www.evolvedbinary.com | https://www.elemental.xyz +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; version 2.1. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +test/dita+xml dita +test/prs.existdb.collection-config+xml xconf +test/extensible-markup-language xadam xml +test/x.xsl+xml xsl \ No newline at end of file diff --git a/elemental-media-type/pom.xml b/elemental-media-type/pom.xml new file mode 100644 index 0000000000..a7f6f68cdb --- /dev/null +++ b/elemental-media-type/pom.xml @@ -0,0 +1,83 @@ + + + + 4.0.0 + + + xyz.elemental + elemental-parent + 7.5.0-SNAPSHOT + ../elemental-parent + + + elemental-media-type + pom + + Elemental Internet Media Type Resolver + Internet Media Type Resolver API and Implementation for Elemental + + + scm:git:https://github.com/evolvedbinary/elemental.git + scm:git:https://github.com/evolvedbinary/elemental.git + scm:git:https://github.com/evolvedbinary/elemental.git + + + + elemental-media-type-api + elemental-media-type-impl + + + + + + com.mycila + license-maven-plugin + + + +
${project.parent.relativePath}/FDB-backport-to-EDB-LGPL-21-ONLY-license.template.txt
+
+
+
+
+
+
+ +
\ No newline at end of file diff --git a/elemental-parent/FDB-backport-to-EDB-LGPL-21-ONLY-license.template.txt b/elemental-parent/FDB-backport-to-EDB-LGPL-21-ONLY-license.template.txt new file mode 100644 index 0000000000..b39453e753 --- /dev/null +++ b/elemental-parent/FDB-backport-to-EDB-LGPL-21-ONLY-license.template.txt @@ -0,0 +1,34 @@ +Copyright (C) 2014, Evolved Binary Ltd + +This file was originally ported from FusionDB to Elemental by +Evolved Binary, for the benefit of the Elemental Open Source community. +Only the ported code as it appears in this file, at the time that +it was contributed to Elemental, was re-licensed under The GNU +Lesser General Public License v2.1 only for use in Elemental. + +This license grant applies only to a snapshot of the code as it +appeared when ported, it does not offer or infer any rights to either +updates of this source code or access to the original source code. + +The GNU Lesser General Public License v2.1 only license follows. + +===================================================================== + +Elemental +Copyright (C) 2024, Evolved Binary Ltd + +admin@evolvedbinary.com +https://www.evolvedbinary.com | https://www.elemental.xyz + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; version 2.1. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA \ No newline at end of file diff --git a/elemental-parent/pom.xml b/elemental-parent/pom.xml index 9272aa07c5..e039b32ef1 100644 --- a/elemental-parent/pom.xml +++ b/elemental-parent/pom.xml @@ -99,8 +99,10 @@ 6.0.0 6.0.0 3.4 + 2.1.4 4.0.4 4.0.6 + 2.0.17 1C @@ -119,12 +121,89 @@ jsr305 3.0.2 + + + io.lacuna + bifurcan + 0.2.0-rc1 + + + + net.jcip + jcip-annotations + 1.0 + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + + jakarta.activation + jakarta.activation-api + ${jakarta.activation-api.version} + + + + org.eclipse.angus + angus-activation + ${eclipse.angus-activation.version} + + + + jakarta.xml.bind + jakarta.xml.bind-api + ${jaxb.api.version} + + + + org.glassfish.jaxb + jaxb-runtime + ${jaxb.impl.version} + runtime + + + + com.sun.activation + jakarta.activation + + + + + + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + test + + + + org.junit.jupiter + junit-jupiter-params + ${junit.jupiter.version} + test + + + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + test + + + org.jvnet.jaxb + jaxb-maven-plugin + 4.0.12 + org.apache.maven.plugins maven-compiler-plugin @@ -238,6 +317,7 @@ SLASHSTAR_STYLE SLASHSTAR_STYLE XML_STYLE + SCRIPT_STYLE XML_STYLE XML_STYLE XML_STYLE @@ -474,6 +554,7 @@
${project.parent.relativePath}/elemental-LGPL-21-ONLY-license.template.txt
elemental-LGPL-21-ONLY-license.template.txt + FDB-backport-to-EDB-LGPL-21-ONLY-license.template.txt diff --git a/exist-ant/pom.xml b/exist-ant/pom.xml index 7663cad2b0..e4355e969d 100644 --- a/exist-ant/pom.xml +++ b/exist-ant/pom.xml @@ -80,6 +80,16 @@ exist-start ${project.version} + + xyz.elemental + elemental-media-type-api + ${project.version} + + + xyz.elemental + elemental-media-type-impl + ${project.version} + net.sf.xmldb-org xmldb-api @@ -174,6 +184,7 @@ pom.xml src/test/resources-filtered/conf.xml src/test/resources/log4j2.xml + src/main/java/org/exist/ant/XMLDBStoreTask.java @@ -191,6 +202,7 @@ xquery-license-style.xml src/test/resources-filtered/conf.xml src/test/resources/log4j2.xml + src/main/java/org/exist/ant/XMLDBStoreTask.java diff --git a/exist-ant/src/main/java/org/exist/ant/XMLDBStoreTask.java b/exist-ant/src/main/java/org/exist/ant/XMLDBStoreTask.java index 14e8b0a96e..4f2ba92826 100644 --- a/exist-ant/src/main/java/org/exist/ant/XMLDBStoreTask.java +++ b/exist-ant/src/main/java/org/exist/ant/XMLDBStoreTask.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -25,8 +49,7 @@ import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.types.FileSet; -import org.exist.util.MimeTable; -import org.exist.util.MimeType; +import org.exist.mediatype.MediaTypeUtil; import org.exist.xmldb.EXistResource; import org.exist.xmldb.XmldbURI; import org.exist.xquery.Constants; @@ -36,9 +59,14 @@ import org.xmldb.api.base.XMLDBException; import org.xmldb.api.modules.BinaryResource; import org.xmldb.api.modules.XMLResource; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.MediaTypeResolver; +import xyz.elemental.mediatype.StorageType; +import xyz.elemental.mediatype.impl.MediaTypeImpl; import java.io.File; import java.util.ArrayList; +import java.util.List; /** @@ -55,17 +83,17 @@ * @author Peter Klotz */ public class XMLDBStoreTask extends AbstractXMLDBTask { - private File mimeTypesFile = null; + private File mediaTypesFile = null; private File srcFile = null; private String targetFile = null; - private ArrayList fileSetList = null; + private List fileSetList = null; private boolean createCollection = false; private boolean createSubcollections = false; private boolean includeEmptyDirs = true; private String type = null; private String defaultMimeType = null; private String forceMimeType = null; - private MimeTable mtable = null; + private MediaTypeResolver mediaTypeResolver = null; @Override public void execute() throws BuildException { @@ -130,42 +158,61 @@ public void execute() throws BuildException { if (srcFile != null) { log("Storing " + srcFile.getName()); - final String baseMimeType; + MediaType mediaType = getMediaTypeResolver().fromFileName(srcFile.getName()); + final String baseMediaType; + if (forceMimeType != null) { - baseMimeType = forceMimeType; + baseMediaType = forceMimeType; + + } else if (mediaType != null) { + baseMediaType = mediaType.getIdentifier(); + } else { - final MimeType fileMime = getMimeTable().getContentTypeFor(srcFile.getName()); - if (fileMime != null) { - baseMimeType = fileMime.getName(); - } else { - baseMimeType = defaultMimeType; + baseMediaType = defaultMimeType; + } + + if (type != null) { + if ("xml".equals(type) && (mediaType == null || mediaType.getStorageType() != StorageType.XML)) { + if (baseMediaType != null) { + mediaType = MediaTypeImpl.builder(baseMediaType, StorageType.XML).build(); + } else { + mediaType = mediaTypeResolver.fromString(MediaType.APPLICATION_XML); + } + + } else if ("binary".equals(type) && (mediaType == null || mediaType.getStorageType() != StorageType.BINARY)) { + if (baseMediaType != null) { + mediaType = MediaTypeImpl.builder(baseMediaType, StorageType.BINARY).build(); + } else { + mediaType = mediaTypeResolver.forUnknown(); + } } } - final MimeType mime; - if ("xml".equals(type)) { - mime = (baseMimeType != null) ? new MimeType(baseMimeType, MimeType.XML) : MimeType.XML_TYPE; - } else if ("binary".equals(type)) { - mime = (baseMimeType != null) ? new MimeType(baseMimeType, MimeType.BINARY) : MimeType.BINARY_TYPE; - } else { + // single file + if (mediaType == null) { final String msg = "Cannot guess mime-type kind for " + srcFile.getName() + ". Treating it as a binary."; log(msg, Project.MSG_ERR); - mime = (baseMimeType != null) ? new MimeType(baseMimeType, MimeType.BINARY) : MimeType.BINARY_TYPE; + if (baseMediaType != null) { + mediaType = MediaTypeImpl.builder(baseMediaType, StorageType.BINARY).build(); + } else { + mediaType = mediaTypeResolver.forUnknown(); + } } + final Class resourceType = mediaType.getStorageType() == StorageType.XML ? XMLResource.class : BinaryResource.class; + if (targetFile == null) { targetFile = srcFile.getName(); } try { - final Class resourceType = mime.isXMLType() ? XMLResource.class : BinaryResource.class; - log("Creating resource " + targetFile + " in collection " + col.getName() + " of type " + resourceType.getName() + " with mime-type: " + mime.getName(), Project.MSG_DEBUG); + log("Creating resource " + targetFile + " in collection " + col.getName() + " of type " + resourceType + " with media-type: " + mediaType.getIdentifier(), Project.MSG_DEBUG); try (Resource res = col.createResource(targetFile, resourceType)) { if (srcFile.length() == 0) { // note: solves bug id 2429889 when this task hits empty files } else { res.setContent(srcFile); - ((EXistResource) res).setMimeType(mime.getName()); + ((EXistResource) res).setMediaType(mediaType.getIdentifier()); col.storeResource(res); } @@ -266,40 +313,53 @@ public void execute() throws BuildException { col = root; } - MimeType currentMime = getMimeTable().getContentTypeFor(file.getName()); - final String currentBaseMimeType; + MediaType currentMediaType = getMediaTypeResolver().fromFileName(file.getName()); + final String currentBaseMediaType; if (forceMimeType != null) { - currentBaseMimeType = forceMimeType; + currentBaseMediaType = forceMimeType; - } else if (currentMime != null) { - currentBaseMimeType = currentMime.getName(); + } else if (currentMediaType != null) { + currentBaseMediaType = currentMediaType.getIdentifier(); } else { - currentBaseMimeType = defaultMimeType; + currentBaseMediaType = defaultMimeType; } if (type != null) { - if ("xml".equals(type)) { - currentMime = (currentBaseMimeType != null) ? (new MimeType(currentBaseMimeType, MimeType.XML)) : MimeType.XML_TYPE; - } else if ("binary".equals(type)) { - currentMime = (currentBaseMimeType != null) ? (new MimeType(currentBaseMimeType, MimeType.BINARY)) : MimeType.BINARY_TYPE; + if ("xml".equals(type) && (currentMediaType == null || currentMediaType.getStorageType() != StorageType.XML)) { + if (currentBaseMediaType != null) { + currentMediaType = MediaTypeImpl.builder(currentBaseMediaType, StorageType.XML).build(); + } else { + currentMediaType = mediaTypeResolver.fromString(MediaType.APPLICATION_XML); + } + + } else if ("binary".equals(type) && (currentMediaType == null || currentMediaType.getStorageType() != StorageType.BINARY)) { + if (currentBaseMediaType != null) { + currentMediaType = MediaTypeImpl.builder(currentBaseMediaType, StorageType.BINARY).build(); + } else { + currentMediaType = mediaTypeResolver.forUnknown(); + } } } - if (currentMime == null) { + if (currentMediaType == null) { final String msg = "Cannot find mime-type kind for " + file.getName() + ". Treating it as a binary."; log(msg, Project.MSG_ERR); - currentMime = (currentBaseMimeType != null) ? (new MimeType(currentBaseMimeType, MimeType.BINARY)) : MimeType.BINARY_TYPE; + if (currentBaseMediaType != null) { + currentMediaType = MediaTypeImpl.builder(currentBaseMediaType, StorageType.BINARY).build(); + } else { + currentMediaType = mediaTypeResolver.forUnknown(); + } } - final Class resourceType = currentMime.isXMLType() ? XMLResource.class : BinaryResource.class; - log("Creating resource " + file.getName() + " in collection " + col.getName() + " of type " + resourceType.getName() + " with mime-type: " + currentMime.getName(), Project.MSG_DEBUG); + final Class resourceType = currentMediaType.getStorageType() == StorageType.XML ? XMLResource.class : BinaryResource.class; + log("Creating resource " + file.getName() + " in collection " + col.getName() + " of type " + resourceType + " with media-type: " + currentMediaType.getIdentifier(), Project.MSG_DEBUG); try (Resource res = col.createResource(file.getName(), resourceType)) { res.setContent(file); - ((EXistResource) res).setMimeType(currentMime.getName()); + ((EXistResource) res).setMediaType(currentMediaType.getIdentifier()); col.storeResource(res); if (permissions != null) { @@ -354,8 +414,12 @@ public void setIncludeEmptyDirs(final boolean create) { this.includeEmptyDirs = create; } - public void setMimeTypesFile(final File file) { - this.mimeTypesFile = file; + public void setMimeTypesFile(final File mediaTypesFile) { + setMediaTypesFile(mediaTypesFile); + } + + public void setMediaTypesFile(final File mediaTypesFile) { + this.mediaTypesFile = mediaTypesFile; } public void setType(final String type) { @@ -370,17 +434,19 @@ public void setForceMimeType(final String mimeType) { this.forceMimeType = mimeType; } - private MimeTable getMimeTable() throws BuildException { - if (mtable == null) { - if (mimeTypesFile != null && mimeTypesFile.exists()) { - log("Trying to use MIME Types file " + mimeTypesFile.getAbsolutePath(), Project.MSG_DEBUG); - mtable = MimeTable.getInstance(mimeTypesFile.toPath()); - } else { + private MediaTypeResolver getMediaTypeResolver() throws BuildException { + if (mediaTypeResolver == null) { + if (mediaTypesFile != null && mediaTypesFile.exists()) { + log("Trying to use MIME Types file " + mediaTypesFile.getAbsolutePath(), Project.MSG_DEBUG); + mediaTypeResolver = MediaTypeUtil.newMediaTypeResolver(mediaTypesFile.getParentFile().toPath()); + } + + if (mediaTypeResolver == null) { log("Using default MIME Types resources", Project.MSG_DEBUG); - mtable = MimeTable.getInstance(); + mediaTypeResolver = MediaTypeUtil.newMediaTypeResolver(null); } } - return mtable; + return mediaTypeResolver; } } diff --git a/exist-core-jmh/pom.xml b/exist-core-jmh/pom.xml index e48d45b3d3..6c6b2ee2bd 100644 --- a/exist-core-jmh/pom.xml +++ b/exist-core-jmh/pom.xml @@ -141,7 +141,7 @@ -
${project.parent.relativePath}/FDB-backport-LGPL-21-ONLY-license.template.txt
+
${project.parent.relativePath}/FDB-backport-to-existdb-LGPL-21-ONLY-license.template.txt
src/main/java/org/exist/storage/lock/LockTableBenchmark.java src/main/java/org/exist/xquery/utils/StringJoinBenchmark.java diff --git a/exist-core/FDB-backport-BSD-3-license.template.txt b/exist-core/FDB-backport-to-existdb-BSD-3-license.template.txt similarity index 100% rename from exist-core/FDB-backport-BSD-3-license.template.txt rename to exist-core/FDB-backport-to-existdb-BSD-3-license.template.txt diff --git a/exist-core/pom.xml b/exist-core/pom.xml index 377bea02d7..8e864fe90c 100644 --- a/exist-core/pom.xml +++ b/exist-core/pom.xml @@ -202,6 +202,18 @@ ${project.version}
+ + xyz.elemental + elemental-media-type-api + ${project.version} + + + + xyz.elemental + elemental-media-type-impl + ${project.version} + + org.exquery exquery-common @@ -789,6 +801,7 @@ src/test/resources-filtered/conf.xml src/test/resources/log4j2.xml src/test/resources/standalone-webapp/WEB-INF/web.xml + src/main/xjb/rest-api.xjb src/test/xquery/tail-recursion.xml src/test/xquery/maps/maps.xqm src/test/xquery/util/util.xml @@ -802,12 +815,22 @@ src/main/java/org/exist/Namespaces.java src/main/resources-filtered/org/exist/system.properties src/test/java/org/exist/TestDataGenerator + src/main/java/org/exist/backup/Backup.java + src/main/java/org/exist/backup/CreateBackupDialog.java + src/test/java/org/exist/backup/DeepEmbeddedBackupRestoreTest.java src/main/java/org/exist/backup/ExportGUI.java src/main/java/org/exist/backup/ExportMain.java src/main/java/org/exist/backup/Main.java + src/main/java/org/exist/backup/Restore.java + src/test/java/org/exist/backup/RestoreAppsTest.java src/main/java/org/exist/backup/SystemExport.java + src/test/java/org/exist/backup/SystemExportFiltersTest.java + src/test/java/org/exist/backup/SystemExportImportTest.java + src/test/java/org/exist/backup/XMLDBRestoreTest.java src/main/java/org/exist/backup/ZipWriter.java + src/main/java/org/exist/backup/restore/AbstractRestoreHandler.java src/main/java/org/exist/backup/restore/AppRestoreUtils.java + src/main/java/org/exist/backup/xquery/RetrieveBackup.java src/main/java/org/exist/client/ClientFrame.java src/main/java/org/exist/client/CommandlineOptions.java src/main/java/org/exist/client/Connection.java @@ -815,6 +838,7 @@ src/main/java/org/exist/client/DocumentView.java src/main/java/org/exist/client/IndexDialog.java src/main/java/org/exist/client/InteractiveClient.java + src/main/java/org/exist/client/MediaTypeFileFilter.java src/main/resources/org/exist/client/messages.properties src/main/resources/org/exist/client/messages_es_ES.properties src/main/resources/org/exist/client/messages_fr_FR.properties @@ -836,6 +860,8 @@ src/main/java/org/exist/collections/Collection.java src/main/java/org/exist/collections/CollectionConfiguration.java src/main/java/org/exist/collections/CollectionConfigurationManager.java + src/test/java/org/exist/collections/CollectionOrderTest.java + src/test/java/org/exist/collections/CollectionRemovalTest.java src/test/java/org/exist/collections/CollectionStoreTest.java src/main/java/org/exist/collections/LockedCollection.java src/main/java/org/exist/collections/MutableCollection.java @@ -844,13 +870,20 @@ src/main/java/org/exist/collections/triggers/CollectionTriggers.java src/main/java/org/exist/collections/triggers/DocumentTrigger.java src/main/java/org/exist/collections/triggers/DocumentTriggers.java + src/test/java/org/exist/collections/triggers/HistoryTriggerTest.java src/test/java/org/exist/collections/triggers/MessagesTrigger.java src/test/java/org/exist/collections/triggers/TriggerConfigTest.java src/main/java/org/exist/collections/triggers/XQueryStartupTrigger.java src/main/java/org/exist/collections/triggers/XQueryTrigger.java + src/test/java/org/exist/collections/triggers/XQueryTrigger2Test.java + src/test/java/org/exist/collections/triggers/XQueryTriggerChainTest.java + src/test/java/org/exist/collections/triggers/XQueryTriggerSetGidTest.java + src/test/java/org/exist/collections/triggers/XQueryTriggerSetUidTest.java + src/test/java/org/exist/collections/triggers/XQueryTriggerTest.java src/main/java/org/exist/config/Configuration.java src/main/java/org/exist/config/ConfigurationImpl.java src/main/java/org/exist/config/Configurator.java + src/test/java/org/exist/config/TwoDatabasesTest.java src/test/java/org/exist/deadlocks/GetReleaseBrokerDeadlocksTest.java src/main/java/org/exist/dom/NodeListImpl.java src/main/java/org/exist/dom/QName.java @@ -871,9 +904,13 @@ src/main/java/org/exist/dom/persistent/AbstractArrayNodeSet.java src/main/java/org/exist/dom/persistent/AbstractCharacterData.java src/main/java/org/exist/dom/persistent/AttrImpl.java + src/test/java/org/exist/dom/persistent/BasicNodeSetTest.java src/main/java/org/exist/dom/persistent/BinaryDocument.java + src/test/java/org/exist/dom/persistent/CDataIntergationTest.java src/main/java/org/exist/dom/persistent/CommentImpl.java + src/test/java/org/exist/dom/persistent/CommentTest.java src/test/java/org/exist/dom/persistent/DefaultDocumentSetTest.java + src/test/java/org/exist/dom/persistent/DocTypeTest.java src/main/java/org/exist/dom/persistent/DocumentImpl.java src/main/java/org/exist/dom/persistent/DocumentMetadata.java src/main/java/org/exist/dom/persistent/DocumentSet.java @@ -895,19 +932,25 @@ src/main/java/org/exist/dom/persistent/XMLUtil.java src/test/java/org/exist/http/AbstractHttpTest.java src/main/java/org/exist/http/AuditTrailSessionListener.java + src/test/java/org/exist/http/AuditTrailSessionListenerTest.java src/main/java/org/exist/http/Descriptor.java + src/main/java/org/exist/http/Response.java src/main/java/org/exist/http/RESTServer.java src/test/java/org/exist/http/RESTServiceTest.java src/main/java/org/exist/http/servlets/AbstractExistHttpServlet.java src/main/java/org/exist/http/servlets/EXistServlet.java + src/main/java/org/exist/http/servlets/HttpServletRequestWrapper.java src/main/java/org/exist/http/servlets/RedirectorServlet.java src/main/java/org/exist/http/servlets/XQueryServlet.java src/main/java/org/exist/http/servlets/XSLTServlet.java + src/test/java/org/exist/http/urlrewrite/ControllerTest.java src/main/java/org/exist/http/urlrewrite/ModuleCall.java src/main/java/org/exist/http/urlrewrite/PathForward.java src/main/java/org/exist/http/urlrewrite/Redirect.java src/main/java/org/exist/http/urlrewrite/RewriteConfig.java + src/test/java/org/exist/http/urlrewrite/URLRewritingTest.java src/main/java/org/exist/http/urlrewrite/XQueryURLRewrite.java + src/test/java/org/exist/http/urlrewrite/XQueryURLRewriteTest.java src/main/java/org/exist/indexing/Index.java src/main/java/org/exist/indexing/IndexController.java src/main/java/org/exist/indexing/IndexManager.java @@ -936,10 +979,20 @@ src/main/java/org/exist/management/impl/SanityReport.java src/main/java/org/exist/numbering/DLN.java src/main/java/org/exist/numbering/DLNFactory.java + src/test/java/org/exist/numbering/DLNStorageTest.java src/main/java/org/exist/numbering/NodeId.java src/main/java/org/exist/numbering/NodeIdFactory.java + src/main/java/org/exist/protocolhandler/eXistURLStreamHandlerFactory.java + src/main/java/org/exist/protocolhandler/URLStreamHandlerStartupTrigger.java + src/main/java/org/exist/protocolhandler/embedded/EmbeddedOutputStream.java + src/main/java/org/exist/protocolhandler/embedded/InMemoryOutputStream.java + src/main/java/org/exist/protocolhandler/protocols/xmldb/EmbeddedURLConnection.java + src/main/java/org/exist/protocolhandler/protocols/xmldb/Handler.java + src/main/java/org/exist/protocolhandler/protocols/xmldb/InMemoryURLConnection.java src/main/java/org/exist/protocolhandler/xmldb/XmldbURL.java + src/main/java/org/exist/protocolhandler/xmlrpc/XmlrpcOutputStream.java src/main/java/org/exist/protocolhandler/xmlrpc/XmlrpcUpload.java + src/main/java/org/exist/protocolhandler/xmlrpc/XmlrpcUploadRunnable.java src/main/java/org/exist/repo/AutoDeploymentTrigger.java src/main/java/org/exist/repo/ClasspathHelper.java src/main/java/org/exist/repo/Deployment.java @@ -950,6 +1003,7 @@ src/test/java/org/exist/security/FnDocSecurityTest.java src/main/java/org/exist/security/Permission.java src/main/java/org/exist/security/PermissionRequired.java + src/test/java/org/exist/security/RestApiSecurityTest.java src/main/java/org/exist/security/SecurityManager.java src/main/java/org/exist/security/SimpleACLPermissionInternal.java src/test/java/org/exist/security/SimpleACLPermissionTest.java @@ -960,27 +1014,51 @@ src/main/java/org/exist/security/internal/aider/UnixStylePermissionAider.java src/main/java/org/exist/source/Source.java src/main/java/org/exist/source/SourceFactory.java + src/main/java/org/exist/source/URLSource.java + src/test/java/org/exist/stax/EmbeddedXMLStreamReaderTest.java + src/test/java/org/exist/storage/AbstractUpdateTest.java src/test/java/org/exist/storage/BFileRecoverTest.java + src/test/java/org/exist/storage/BinaryDocumentTest.java src/main/java/org/exist/storage/BrokerFactory.java src/main/java/org/exist/storage/BrokerPool.java src/test/java/org/exist/storage/BrokerPoolsTest.java src/test/java/org/exist/storage/BrokerPoolTest.java src/test/java/org/exist/storage/CollectionTest.java + src/test/java/org/exist/storage/ConcurrentBrokerPoolTest.java + src/test/java/org/exist/storage/ConcurrentStoreTest.java + src/test/java/org/exist/storage/CopyCollectionRecoveryTest.java + src/test/java/org/exist/storage/CopyResourceRecoveryTest.java src/test/java/org/exist/storage/CopyResourceTest.java src/main/java/org/exist/storage/DBBroker.java + src/test/java/org/exist/storage/DirtyShutdownTest.java src/test/java/org/exist/storage/DOMFileRecoverTest.java src/main/java/org/exist/storage/Indexable.java src/main/java/org/exist/storage/IndexSpec.java + src/test/java/org/exist/storage/LargeValuesTest.java + src/test/java/org/exist/storage/ModificationTimeTest.java + src/test/java/org/exist/storage/MoveCollectionRecoveryTest.java + src/test/java/org/exist/storage/MoveOverwriteCollectionTest.java + src/test/java/org/exist/storage/MoveOverwriteResourceTest.java + src/test/java/org/exist/storage/MoveResourceRecoveryTest.java src/main/java/org/exist/storage/NativeBroker.java src/main/java/org/exist/storage/NativeValueIndex.java src/main/java/org/exist/storage/NodePath.java src/test/java/org/exist/storage/NodePathTest.java src/main/java/org/exist/storage/ProcessMonitor.java + src/test/java/org/exist/storage/RangeIndexUpdateTest.java src/test/java/org/exist/storage/RecoverBinary2Test.java src/test/java/org/exist/storage/Recovery2Test.java src/test/java/org/exist/storage/RecoveryTest.java + src/test/java/org/exist/storage/ReindexRecoveryTest.java + src/test/java/org/exist/storage/ReindexTest.java src/test/java/org/exist/storage/RemoveCollectionTest.java + src/test/java/org/exist/storage/RemoveRootCollectionTest.java + src/test/java/org/exist/storage/ResourceTest.java + src/test/java/org/exist/storage/ShutdownTest.java src/main/java/org/exist/storage/StorageAddress.java + src/test/java/org/exist/storage/StoreBinaryTest.java + src/test/java/org/exist/storage/StoreResourceTest.java + src/test/java/org/exist/storage/UpdateRecoverTest.java src/test/java/org/exist/storage/XIncludeSerializerTest.java src/test/java/org/exist/storage/btree/BTreeTest.java src/main/java/org/exist/storage/btree/TreeMetrics.java @@ -993,6 +1071,7 @@ src/test/java/org/exist/storage/io/VariableByteStreamTest.java src/test/java/org/exist/storage/lock/DeadlockTest.java src/main/java/org/exist/storage/lock/FileLock.java + src/test/java/org/exist/storage/lock/GetXMLResourceNoLockTest.java src/test/java/org/exist/storage/lock/ProtectedModeTest.java src/main/java/org/exist/storage/recovery/RecoveryManager.java src/main/java/org/exist/storage/serializers/EXistOutputKeys.java @@ -1019,7 +1098,14 @@ src/main/java/org/exist/util/Configuration.java src/test/java/org/exist/util/DOMSerializerTest.java src/test/java/org/exist/util/LeasableTest.java + src/test/java/org/exist/util/MediaTypeResolverTest.java + src/main/java/org/exist/util/MimeTable.java + src/main/java/org/exist/util/MimeType.java src/main/java/org/exist/util/ParametersExtractor.java + src/main/java/org/exist/util/XMLFilenameFilter.java + src/test/java/org/exist/util/XMLReaderExpansionTest.java + src/test/java/org/exist/util/XMLReaderSecurityTest.java + src/main/java/org/exist/util/XQueryFilenameFilter.java src/main/java/org/exist/util/crypto/digest/DigestType.java src/main/java/org/exist/util/io/ByteArrayContent.java src/test/java/org/exist/util/io/ByteArrayContentTest.java @@ -1050,6 +1136,7 @@ src/test/java/org/exist/util/sorters/SortTestNodeId.java src/test/resources/org/exist/validation/catalog.xml src/test/java/org/exist/validation/CollectionConfigurationValidationModeTest.java + src/test/java/org/exist/validation/DtdEntityTest.java src/main/java/org/exist/validation/XmlLibraryChecker.java src/main/java/org/exist/validation/internal/DatabaseResources.java src/main/resources/org/exist/validation/internal/query/find_catalogs_with_dtd.xq @@ -1057,6 +1144,8 @@ src/main/java/org/exist/validation/resolver/SearchResourceResolver.java src/test/java/org/exist/w3c/tests/TestCase.java src/main/java/org/exist/webstart/JnlpJarFiles.java + src/main/java/org/exist/webstart/JnlpWriter.java + src/main/java/org/exist/xmldb/AbstractEXistResource.java src/main/java/org/exist/xmldb/AbstractRemoteResource.java src/test/java/org/exist/xmldb/ContentAsDOMTest.java src/test/java/org/exist/xmldb/CreateCollectionsTest.java @@ -1064,11 +1153,16 @@ src/test/java/org/exist/xmldb/EXistXMLSerializeTest.java src/test/java/org/exist/xmldb/IndexingTest.java src/main/java/org/exist/xmldb/LocalBinaryResource.java + src/main/java/org/exist/xmldb/LocalCollection.java src/main/java/org/exist/xmldb/LocalResourceSet.java + src/main/java/org/exist/xmldb/LocalRestoreService.java src/main/java/org/exist/xmldb/LocalXMLResource.java src/main/java/org/exist/xmldb/LocalXPathQueryService.java src/main/java/org/exist/xmldb/RemoteBinaryResource.java + src/main/java/org/exist/xmldb/RemoteCollection.java + src/test/java/org/exist/xmldb/RemoteCollectionTest.java src/test/java/org/exist/xmldb/RemoteDOMTest.java + src/test/java/org/exist/xmldb/RemoteQueryTest.java src/main/java/org/exist/xmldb/RemoteResourceSet.java src/main/java/org/exist/xmldb/RemoteRestoreService.java src/main/java/org/exist/xmldb/RemoteXMLResource.java @@ -1095,6 +1189,7 @@ src/test/java/org/exist/xmlrpc/QuerySessionTest.java src/main/java/org/exist/xmlrpc/RpcAPI.java src/main/java/org/exist/xmlrpc/RpcConnection.java + src/test/java/org/exist/xmlrpc/XmlRpcTest.java src/main/java/org/exist/xqj/Marshaller.java src/test/java/org/exist/xqj/MarshallerTest.java src/main/java/org/exist/xquery/AbstractInternalModule.java @@ -1106,12 +1201,14 @@ src/main/java/org/exist/xquery/DynamicCardinalityCheck.java src/main/java/org/exist/xquery/DynamicTypeCheck.java src/main/java/org/exist/xquery/DynamicVariable.java + src/test/java/org/exist/xquery/EmbeddedBinariesTest.java src/test/java/org/exist/xquery/EmbeddedBinariesTest.java.java src/main/java/org/exist/xquery/ErrorCodes.java src/main/java/org/exist/xquery/ExternalModuleImpl.java src/test/java/org/exist/xquery/ForwardReferenceTest.java src/main/java/org/exist/xquery/Function.java src/main/java/org/exist/xquery/FunctionFactory.java + src/test/java/org/exist/xquery/LexerTest.java src/main/java/org/exist/xquery/LocationStep.java src/main/java/org/exist/xquery/Module.java src/main/java/org/exist/xquery/NamedFunctionReference.java @@ -1122,18 +1219,21 @@ src/main/java/org/exist/xquery/PerformanceStatsImpl.java src/test/java/org/exist/xquery/RestBinariesTest.java src/test/java/org/exist/xquery/StoredModuleTest.java + src/test/java/org/exist/xquery/TransformTest.java src/main/java/org/exist/xquery/TryCatchExpression.java src/main/java/org/exist/xquery/UserDefinedFunction.java src/main/java/org/exist/xquery/Variable.java src/main/java/org/exist/xquery/VariableDeclaration.java src/main/java/org/exist/xquery/VariableImpl.java src/main/java/org/exist/xquery/VariableReference.java + src/test/java/org/exist/xquery/VariablesTest.java src/test/java/org/exist/xquery/WindowClauseTest.java src/test/java/org/exist/xquery/XmldbBinariesTest.java src/test/java/org/exist/xquery/XPathOpOrSpecialCaseTest.java src/test/java/org/exist/xquery/XPathQueryTest.java src/main/java/org/exist/xquery/XPathUtil.java src/main/java/org/exist/xquery/XQueryContext.java + src/test/java/org/exist/xquery/XQueryDeclareContextItemTest.java src/test/java/org/exist/xquery/XQueryFunctionsTest.java src/main/java/org/exist/xquery/XQueryProcessingInstruction.java src/test/java/org/exist/xquery/XQueryProcessingInstructionTest.java @@ -1247,9 +1347,16 @@ src/main/java/org/exist/xquery/functions/fn/transform/Options.java src/main/java/org/exist/xquery/functions/fn/transform/Transform.java src/main/java/org/exist/xquery/functions/fn/transform/TreeUtils.java + src/test/java/org/exist/xquery/functions/inspect/InspectModuleTest.java src/main/java/org/exist/xquery/functions/integer/WordPicture.java src/main/java/org/exist/xquery/functions/map/MapExpr.java + src/main/java/org/exist/xquery/functions/request/GetData.java + src/test/java/org/exist/xquery/functions/request/GetData2Test.java + src/test/java/org/exist/xquery/functions/request/GetDataTest.java src/test/java/org/exist/xquery/functions/request/GetHeaderTest.java + src/test/java/org/exist/xquery/functions/request/GetParameterTest.java + src/test/java/org/exist/xquery/functions/request/PatchTest.java + src/main/java/org/exist/xquery/functions/response/Stream.java src/test/java/org/exist/xquery/functions/securitymanager/GetPermissionsTest.java src/test/java/org/exist/xquery/functions/securitymanager/GroupManagementFunctionRemoveGroupTest.java src/test/java/org/exist/xquery/functions/securitymanager/GroupMembershipFunctionRemoveGroupMemberTest.java @@ -1258,6 +1365,7 @@ src/test/java/org/exist/xquery/functions/securitymanager/PermissionsFunctionChownTest.java src/test/java/org/exist/xquery/functions/system/GetRunningXQueriesTest.java src/main/java/org/exist/xquery/functions/system/GetUptime.java + src/main/java/org/exist/xquery/functions/system/Restore.java src/main/java/org/exist/xquery/functions/system/Shutdown.java src/main/java/org/exist/xquery/functions/system/SystemModule.java src/main/java/org/exist/xquery/functions/system/TriggerSystemTask.java @@ -1267,6 +1375,8 @@ src/test/java/org/exist/xquery/functions/transform/TransformTest.java src/main/java/org/exist/xquery/functions/util/BuiltinFunctions.java src/main/java/org/exist/xquery/functions/util/DescribeFunction.java + src/test/java/org/exist/xquery/functions/util/EvalTest.java + src/test/java/org/exist/xquery/functions/util/ExpandTest.java src/main/java/org/exist/xquery/functions/util/FunctionFunction.java src/main/java/org/exist/xquery/functions/util/LogFunction.java src/main/java/org/exist/xquery/functions/util/ModuleInfo.java @@ -1280,7 +1390,10 @@ src/test/java/org/exist/xquery/functions/validate/JingXsdTest.java src/main/java/org/exist/xquery/functions/validation/Jaxp.java src/test/java/org/exist/xquery/functions/xmldb/DbStore2Test.java + src/main/java/org/exist/xquery/functions/xmldb/XMLDBGetMimeType.java + src/main/java/org/exist/xquery/functions/xmldb/XMLDBLoadFromPattern.java src/main/java/org/exist/xquery/functions/xmldb/XMLDBModule.java + src/main/java/org/exist/xquery/functions/xmldb/XMLDBSetMimeType.java src/main/java/org/exist/xquery/functions/xmldb/XMLDBStore.java src/main/java/org/exist/xquery/functions/xmldb/XMLDBXUpdate.java src/test/java/org/exist/xquery/functions/xquery3/TryCatchTest.java @@ -1288,6 +1401,7 @@ src/test/java/org/exist/xquery/update/AbstractUpdateTest.java src/test/java/org/exist/xquery/update/IndexIntegrationTest.java src/test/java/org/exist/xquery/update/UpdateInsertTest.java + src/test/java/org/exist/xquery/update/UpdateInsertTriggersDefragTest.java src/test/java/org/exist/xquery/update/UpdateReplaceTest.java src/test/java/org/exist/xquery/update/UpdateValueTest.java src/main/java/org/exist/xquery/util/ExpressionDumper.java @@ -1352,7 +1466,7 @@ ARC-BSD-3-license.template.txt BX-BSD-3-license.template.txt DBXML-10-license.template.txt - FDB-backport-BSD-3-license.template.txt + FDB-backport-to-existdb-BSD-3-license.template.txt src/test/resources/uk-towns.txt src/test/resources/**/*.bin src/test/resources/**/*.xar @@ -1366,6 +1480,7 @@ src/test/resources-filtered/conf.xml src/test/resources/log4j2.xml src/test/resources/standalone-webapp/WEB-INF/web.xml + src/main/xjb/rest-api.xjb src/test/xquery/binary-value.xqm src/test/xquery/instance-of.xqm src/test/xquery/operator-mapping.xqm @@ -1391,12 +1506,22 @@ src/main/java/org/exist/Namespaces.java src/main/resources-filtered/org/exist/system.properties src/test/java/org/exist/TestDataGenerator + src/main/java/org/exist/backup/Backup.java + src/main/java/org/exist/backup/CreateBackupDialog.java + src/test/java/org/exist/backup/DeepEmbeddedBackupRestoreTest.java src/main/java/org/exist/backup/ExportGUI.java src/main/java/org/exist/backup/ExportMain.java src/main/java/org/exist/backup/Main.java + src/main/java/org/exist/backup/Restore.java + src/test/java/org/exist/backup/RestoreAppsTest.java src/main/java/org/exist/backup/SystemExport.java + src/test/java/org/exist/backup/SystemExportFiltersTest.java + src/test/java/org/exist/backup/SystemExportImportTest.java + src/test/java/org/exist/backup/XMLDBRestoreTest.java src/main/java/org/exist/backup/ZipWriter.java + src/main/java/org/exist/backup/restore/AbstractRestoreHandler.java src/main/java/org/exist/backup/restore/AppRestoreUtils.java + src/main/java/org/exist/backup/xquery/RetrieveBackup.java src/main/java/org/exist/client/ClientFrame.java src/main/java/org/exist/client/CommandlineOptions.java src/main/java/org/exist/client/Connection.java @@ -1404,6 +1529,7 @@ src/main/java/org/exist/client/DocumentView.java src/main/java/org/exist/client/IndexDialog.java src/main/java/org/exist/client/InteractiveClient.java + src/main/java/org/exist/client/MediaTypeFileFilter.java src/main/resources/org/exist/client/messages.properties src/main/resources/org/exist/client/messages_es_ES.properties src/main/resources/org/exist/client/messages_fr_FR.properties @@ -1425,6 +1551,8 @@ src/main/java/org/exist/collections/Collection.java src/main/java/org/exist/collections/CollectionConfiguration.java src/main/java/org/exist/collections/CollectionConfigurationManager.java + src/test/java/org/exist/collections/CollectionOrderTest.java + src/test/java/org/exist/collections/CollectionRemovalTest.java src/test/java/org/exist/collections/CollectionStoreTest.java src/main/java/org/exist/collections/LockedCollection.java src/main/java/org/exist/collections/MutableCollection.java @@ -1433,13 +1561,20 @@ src/main/java/org/exist/collections/triggers/CollectionTriggers.java src/main/java/org/exist/collections/triggers/DocumentTrigger.java src/main/java/org/exist/collections/triggers/DocumentTriggers.java + src/test/java/org/exist/collections/triggers/HistoryTriggerTest.java src/test/java/org/exist/collections/triggers/MessagesTrigger.java src/test/java/org/exist/collections/triggers/TriggerConfigTest.java src/main/java/org/exist/collections/triggers/XQueryStartupTrigger.java src/main/java/org/exist/collections/triggers/XQueryTrigger.java + src/test/java/org/exist/collections/triggers/XQueryTrigger2Test.java + src/test/java/org/exist/collections/triggers/XQueryTriggerChainTest.java + src/test/java/org/exist/collections/triggers/XQueryTriggerSetGidTest.java + src/test/java/org/exist/collections/triggers/XQueryTriggerSetUidTest.java + src/test/java/org/exist/collections/triggers/XQueryTriggerTest.java src/main/java/org/exist/config/Configuration.java src/main/java/org/exist/config/ConfigurationImpl.java src/main/java/org/exist/config/Configurator.java + src/test/java/org/exist/config/TwoDatabasesTest.java src/test/java/org/exist/deadlocks/GetReleaseBrokerDeadlocksTest.java src/main/java/org/exist/dom/NodeListImpl.java src/main/java/org/exist/dom/QName.java @@ -1468,9 +1603,13 @@ src/main/java/org/exist/dom/persistent/AbstractArrayNodeSet.java src/main/java/org/exist/dom/persistent/AbstractCharacterData.java src/main/java/org/exist/dom/persistent/AttrImpl.java + src/test/java/org/exist/dom/persistent/BasicNodeSetTest.java src/main/java/org/exist/dom/persistent/BinaryDocument.java + src/test/java/org/exist/dom/persistent/CDataIntergationTest.java src/main/java/org/exist/dom/persistent/CommentImpl.java + src/test/java/org/exist/dom/persistent/CommentTest.java src/test/java/org/exist/dom/persistent/DefaultDocumentSetTest.java + src/test/java/org/exist/dom/persistent/DocTypeTest.java src/main/java/org/exist/dom/persistent/DocumentImpl.java src/main/java/org/exist/dom/persistent/DocumentMetadata.java src/main/java/org/exist/dom/persistent/DocumentSet.java @@ -1493,21 +1632,27 @@ src/main/java/org/exist/dom/persistent/XMLUtil.java src/test/java/org/exist/http/AbstractHttpTest.java src/main/java/org/exist/http/AuditTrailSessionListener.java + src/test/java/org/exist/http/AuditTrailSessionListenerTest.java src/main/java/org/exist/http/Descriptor.java + src/main/java/org/exist/http/Response.java src/test/java/org/exist/http/RESTExternalVariableTest.java src/main/java/org/exist/http/RESTServer.java src/test/java/org/exist/http/RESTServiceTest.java src/main/java/org/exist/http/servlets/AbstractExistHttpServlet.java src/main/java/org/exist/http/servlets/EXistServlet.java + src/main/java/org/exist/http/servlets/HttpServletRequestWrapper.java src/main/java/org/exist/http/servlets/RedirectorServlet.java src/main/java/org/exist/http/servlets/XQueryServlet.java src/main/java/org/exist/http/servlets/XSLTServlet.java + src/test/java/org/exist/http/urlrewrite/ControllerTest.java src/main/java/org/exist/http/urlrewrite/ModuleCall.java src/main/java/org/exist/http/urlrewrite/PathForward.java src/main/java/org/exist/http/urlrewrite/Redirect.java src/test/java/org/exist/http/urlrewrite/RedirectTest.java src/main/java/org/exist/http/urlrewrite/RewriteConfig.java + src/test/java/org/exist/http/urlrewrite/URLRewritingTest.java src/main/java/org/exist/http/urlrewrite/XQueryURLRewrite.java + src/test/java/org/exist/http/urlrewrite/XQueryURLRewriteTest.java src/main/java/org/exist/indexing/Index.java src/main/java/org/exist/indexing/IndexController.java src/main/java/org/exist/indexing/IndexManager.java @@ -1534,12 +1679,24 @@ src/main/java/org/exist/management/impl/ExistMBean.java src/main/java/org/exist/management/impl/JMXAgent.java src/main/java/org/exist/management/impl/SanityReport.java + src/main/java/org/exist/mediatype/MediaTypeService.java + src/main/java/org/exist/mediatype/MediaTypeUtil.java src/main/java/org/exist/numbering/DLN.java src/main/java/org/exist/numbering/DLNFactory.java + src/test/java/org/exist/numbering/DLNStorageTest.java src/main/java/org/exist/numbering/NodeId.java src/main/java/org/exist/numbering/NodeIdFactory.java + src/main/java/org/exist/protocolhandler/eXistURLStreamHandlerFactory.java + src/main/java/org/exist/protocolhandler/URLStreamHandlerStartupTrigger.java + src/main/java/org/exist/protocolhandler/embedded/EmbeddedOutputStream.java + src/main/java/org/exist/protocolhandler/embedded/InMemoryOutputStream.java + src/main/java/org/exist/protocolhandler/protocols/xmldb/EmbeddedURLConnection.java + src/main/java/org/exist/protocolhandler/protocols/xmldb/Handler.java + src/main/java/org/exist/protocolhandler/protocols/xmldb/InMemoryURLConnection.java src/main/java/org/exist/protocolhandler/xmldb/XmldbURL.java + src/main/java/org/exist/protocolhandler/xmlrpc/XmlrpcOutputStream.java src/main/java/org/exist/protocolhandler/xmlrpc/XmlrpcUpload.java + src/main/java/org/exist/protocolhandler/xmlrpc/XmlrpcUploadRunnable.java src/main/java/org/exist/repo/AutoDeploymentTrigger.java src/main/java/org/exist/repo/ClasspathHelper.java src/main/java/org/exist/repo/Deployment.java @@ -1553,6 +1710,7 @@ src/main/java/org/exist/security/Permission.java src/main/java/org/exist/security/PermissionRequired.java src/main/java/org/exist/security/PermissionRequiredCheck.java + src/test/java/org/exist/security/RestApiSecurityTest.java src/main/java/org/exist/security/SecurityManager.java src/main/java/org/exist/security/SimpleACLPermissionInternal.java src/test/java/org/exist/security/SimpleACLPermissionTest.java @@ -1563,8 +1721,12 @@ src/main/java/org/exist/security/internal/aider/UnixStylePermissionAider.java src/main/java/org/exist/source/Source.java src/main/java/org/exist/source/SourceFactory.java + src/main/java/org/exist/source/URLSource.java + src/test/java/org/exist/stax/EmbeddedXMLStreamReaderTest.java src/test/java/org/exist/storage/AbstractRecoverTest.java + src/test/java/org/exist/storage/AbstractUpdateTest.java src/test/java/org/exist/storage/BFileRecoverTest.java + src/test/java/org/exist/storage/BinaryDocumentTest.java src/main/java/org/exist/storage/BrokerFactory.java src/main/java/org/exist/storage/BrokerPool.java src/main/java/org/exist/storage/BrokerPoolService.java @@ -1575,25 +1737,45 @@ src/test/java/org/exist/storage/BrokerPoolsTest.java src/test/java/org/exist/storage/BrokerPoolTest.java src/test/java/org/exist/storage/CollectionTest.java + src/test/java/org/exist/storage/ConcurrentBrokerPoolTest.java + src/test/java/org/exist/storage/ConcurrentStoreTest.java + src/test/java/org/exist/storage/CopyCollectionRecoveryTest.java + src/test/java/org/exist/storage/CopyResourceRecoveryTest.java src/test/java/org/exist/storage/CopyResourceTest.java src/main/java/org/exist/storage/DBBroker.java + src/test/java/org/exist/storage/DirtyShutdownTest.java src/test/java/org/exist/storage/DOMFileRecoverTest.java src/main/java/org/exist/storage/FluentBrokerAPI.java src/main/java/org/exist/storage/Indexable.java src/main/java/org/exist/storage/IndexSpec.java + src/test/java/org/exist/storage/LargeValuesTest.java + src/test/java/org/exist/storage/ModificationTimeTest.java + src/test/java/org/exist/storage/MoveCollectionRecoveryTest.java src/test/java/org/exist/storage/MoveCollectionTest.java + src/test/java/org/exist/storage/MoveOverwriteCollectionTest.java + src/test/java/org/exist/storage/MoveOverwriteResourceTest.java + src/test/java/org/exist/storage/MoveResourceRecoveryTest.java src/main/java/org/exist/storage/NativeBroker.java src/main/java/org/exist/storage/NativeValueIndex.java src/main/java/org/exist/storage/NodePath.java src/test/java/org/exist/storage/NodePathTest.java src/main/java/org/exist/storage/ProcessMonitor.java + src/test/java/org/exist/storage/RangeIndexUpdateTest.java src/test/java/org/exist/storage/RecoverBinary2Test.java src/test/java/org/exist/storage/RecoverBinaryTest.java src/test/java/org/exist/storage/RecoverXmlTest.java src/test/java/org/exist/storage/Recovery2Test.java src/test/java/org/exist/storage/RecoveryTest.java + src/test/java/org/exist/storage/ReindexRecoveryTest.java + src/test/java/org/exist/storage/ReindexTest.java src/test/java/org/exist/storage/RemoveCollectionTest.java + src/test/java/org/exist/storage/RemoveRootCollectionTest.java + src/test/java/org/exist/storage/ResourceTest.java + src/test/java/org/exist/storage/ShutdownTest.java src/main/java/org/exist/storage/StorageAddress.java + src/test/java/org/exist/storage/StoreBinaryTest.java + src/test/java/org/exist/storage/StoreResourceTest.java + src/test/java/org/exist/storage/UpdateRecoverTest.java src/test/java/org/exist/storage/XIncludeSerializerTest.java src/main/java/org/exist/storage/XQueryPool.java src/main/java/org/exist/storage/blob/** @@ -1630,6 +1812,7 @@ src/main/java/org/exist/storage/lock/EnsureUnlocked.java src/main/java/org/exist/storage/lock/FileLock.java src/main/java/org/exist/storage/lock/FileLockService.java + src/test/java/org/exist/storage/lock/GetXMLResourceNoLockTest.java src/main/java/org/exist/storage/lock/LockedPath.java src/main/java/org/exist/storage/lock/LockEventJsonListener.java src/main/java/org/exist/storage/lock/LockEventLogListener.java @@ -1685,10 +1868,17 @@ src/main/java/org/exist/util/JREUtil.java src/test/java/org/exist/util/LeasableTest.java src/main/java/org/exist/util/MapUtil.java + src/test/java/org/exist/util/MediaTypeResolverTest.java + src/main/java/org/exist/util/MimeTable.java + src/main/java/org/exist/util/MimeType.java src/main/java/org/exist/util/OSUtil.java src/main/java/org/exist/util/ParametersExtractor.java src/main/java/org/exist/util/StringUtil.java src/main/java/org/exist/util/UTF8.java + src/main/java/org/exist/util/XMLFilenameFilter.java + src/test/java/org/exist/util/XMLReaderExpansionTest.java + src/test/java/org/exist/util/XMLReaderSecurityTest.java + src/main/java/org/exist/util/XQueryFilenameFilter.java src/main/java/org/exist/util/crypto/digest/DigestType.java src/main/java/org/exist/util/io/AbstractContentFile.java src/main/java/org/exist/util/io/ByteArrayContent.java @@ -1721,6 +1911,7 @@ src/test/java/org/exist/util/sorters/SortTestNodeId.java src/test/resources/org/exist/validation/catalog.xml src/test/java/org/exist/validation/CollectionConfigurationValidationModeTest.java + src/test/java/org/exist/validation/DtdEntityTest.java src/main/java/org/exist/validation/XmlLibraryChecker.java src/main/java/org/exist/validation/internal/DatabaseResources.java src/main/resources/org/exist/validation/internal/query/find_catalogs_with_dtd.xq @@ -1728,6 +1919,8 @@ src/main/java/org/exist/validation/resolver/SearchResourceResolver.java src/test/java/org/exist/w3c/tests/TestCase.java src/main/java/org/exist/webstart/JnlpJarFiles.java + src/main/java/org/exist/webstart/JnlpWriter.java + src/main/java/org/exist/xmldb/AbstractEXistResource.java src/main/java/org/exist/xmldb/AbstractRemoteResource.java src/test/java/org/exist/xmldb/ContentAsDOMTest.java src/test/java/org/exist/xmldb/CreateCollectionsTest.java @@ -1735,11 +1928,16 @@ src/test/java/org/exist/xmldb/EXistXMLSerializeTest.java src/test/java/org/exist/xmldb/IndexingTest.java src/main/java/org/exist/xmldb/LocalBinaryResource.java + src/main/java/org/exist/xmldb/LocalCollection.java src/main/java/org/exist/xmldb/LocalResourceSet.java + src/main/java/org/exist/xmldb/LocalRestoreService.java src/main/java/org/exist/xmldb/LocalXMLResource.java src/main/java/org/exist/xmldb/LocalXPathQueryService.java src/main/java/org/exist/xmldb/RemoteBinaryResource.java + src/main/java/org/exist/xmldb/RemoteCollection.java + src/test/java/org/exist/xmldb/RemoteCollectionTest.java src/test/java/org/exist/xmldb/RemoteDOMTest.java + src/test/java/org/exist/xmldb/RemoteQueryTest.java src/main/java/org/exist/xmldb/RemoteResourceSet.java src/main/java/org/exist/xmldb/RemoteRestoreService.java src/main/java/org/exist/xmldb/RemoteXMLResource.java @@ -1772,6 +1970,7 @@ src/main/java/org/exist/xmlrpc/RpcAPI.java src/main/java/org/exist/xmlrpc/RpcConnection.java src/main/java/org/exist/xmlrpc/XmlRpcExtensionConstants.java + src/test/java/org/exist/xmlrpc/XmlRpcTest.java src/main/java/org/exist/xqj/Marshaller.java src/test/java/org/exist/xqj/MarshallerTest.java src/main/java/org/exist/xquery/AbstractInternalModule.java @@ -1785,6 +1984,7 @@ src/main/java/org/exist/xquery/DynamicCardinalityCheck.java src/main/java/org/exist/xquery/DynamicTypeCheck.java src/main/java/org/exist/xquery/DynamicVariable.java + src/test/java/org/exist/xquery/EmbeddedBinariesTest.java src/test/java/org/exist/xquery/EmbeddedBinariesTest.java.java src/main/java/org/exist/xquery/ErrorCodes.java src/main/java/org/exist/xquery/ExternalModuleImpl.java @@ -1797,6 +1997,7 @@ src/main/java/org/exist/xquery/JavaBinding.java src/test/resources-filtered/org/exist/xquery/JavaBindingTest.conf.xml src/test/java/org/exist/xquery/JavaBindingTest.java + src/test/java/org/exist/xquery/LexerTest.java src/main/java/org/exist/xquery/LocationStep.java src/main/java/org/exist/xquery/Materializable.java src/main/java/org/exist/xquery/Module.java @@ -1808,12 +2009,14 @@ src/main/java/org/exist/xquery/PerformanceStatsImpl.java src/test/java/org/exist/xquery/RestBinariesTest.java src/test/java/org/exist/xquery/StoredModuleTest.java + src/test/java/org/exist/xquery/TransformTest.java src/main/java/org/exist/xquery/TryCatchExpression.java src/main/java/org/exist/xquery/UserDefinedFunction.java src/main/java/org/exist/xquery/Variable.java src/main/java/org/exist/xquery/VariableDeclaration.java src/main/java/org/exist/xquery/VariableImpl.java src/main/java/org/exist/xquery/VariableReference.java + src/test/java/org/exist/xquery/VariablesTest.java src/test/java/org/exist/xquery/WatchdogTest.java src/test/java/org/exist/xquery/WindowClauseTest.java src/test/java/org/exist/xquery/XmldbBinariesTest.java @@ -1823,6 +2026,7 @@ src/test/java/org/exist/xquery/XPathUtilTest.java src/main/java/org/exist/xquery/XQueryContext.java src/test/java/org/exist/xquery/XQueryContextAttributesTest.java + src/test/java/org/exist/xquery/XQueryDeclareContextItemTest.java src/test/java/org/exist/xquery/XQueryFunctionsTest.java src/main/java/org/exist/xquery/XQueryProcessingInstruction.java src/test/java/org/exist/xquery/XQueryProcessingInstructionTest.java @@ -1941,10 +2145,17 @@ src/main/java/org/exist/xquery/functions/fn/transform/Options.java src/main/java/org/exist/xquery/functions/fn/transform/Transform.java src/main/java/org/exist/xquery/functions/fn/transform/TreeUtils.java + src/test/java/org/exist/xquery/functions/inspect/InspectModuleTest.java src/main/java/org/exist/xquery/functions/integer/WordPicture.java src/main/java/org/exist/xquery/functions/map/MapExpr.java src/main/java/org/exist/xquery/functions/map/MapType.java + src/main/java/org/exist/xquery/functions/request/GetData.java + src/test/java/org/exist/xquery/functions/request/GetData2Test.java + src/test/java/org/exist/xquery/functions/request/GetDataTest.java src/test/java/org/exist/xquery/functions/request/GetHeaderTest.java + src/test/java/org/exist/xquery/functions/request/GetParameterTest.java + src/test/java/org/exist/xquery/functions/request/PatchTest.java + src/main/java/org/exist/xquery/functions/response/Stream.java src/test/java/org/exist/xquery/functions/securitymanager/AccountMetadataFunctionsTest.java src/test/java/org/exist/xquery/functions/securitymanager/GetPermissionsTest.java src/test/java/org/exist/xquery/functions/securitymanager/GroupManagementFunctionRemoveGroupTest.java @@ -1958,6 +2169,7 @@ src/main/java/org/exist/xquery/functions/system/FunctionAvailable.java src/test/java/org/exist/xquery/functions/system/GetRunningXQueriesTest.java src/main/java/org/exist/xquery/functions/system/GetUptime.java + src/main/java/org/exist/xquery/functions/system/Restore.java src/main/java/org/exist/xquery/functions/system/Shutdown.java src/main/java/org/exist/xquery/functions/system/SystemModule.java src/main/java/org/exist/xquery/functions/system/TriggerSystemTask.java @@ -1968,6 +2180,8 @@ src/main/java/org/exist/xquery/functions/util/BuiltinFunctions.java src/main/java/org/exist/xquery/functions/util/DescribeFunction.java src/main/java/org/exist/xquery/functions/util/Eval.java + src/test/java/org/exist/xquery/functions/util/EvalTest.java + src/test/java/org/exist/xquery/functions/util/ExpandTest.java src/main/java/org/exist/xquery/functions/util/FunctionFunction.java src/main/java/org/exist/xquery/functions/util/LogFunction.java src/main/java/org/exist/xquery/functions/util/ModuleInfo.java @@ -1983,7 +2197,10 @@ src/test/java/org/exist/xquery/functions/xmldb/AbstractXMLDBTest.java src/test/java/org/exist/xquery/functions/xmldb/DbStore2Test.java src/test/java/org/exist/xquery/functions/xmldb/XMLDBAuthenticateTest.java + src/main/java/org/exist/xquery/functions/xmldb/XMLDBGetMimeType.java + src/main/java/org/exist/xquery/functions/xmldb/XMLDBLoadFromPattern.java src/main/java/org/exist/xquery/functions/xmldb/XMLDBModule.java + src/main/java/org/exist/xquery/functions/xmldb/XMLDBSetMimeType.java src/main/java/org/exist/xquery/functions/xmldb/XMLDBStore.java src/test/java/org/exist/xquery/functions/xmldb/XMLDBStoreTest.java src/main/java/org/exist/xquery/functions/xmldb/XMLDBXUpdate.java @@ -1994,6 +2211,7 @@ src/test/java/org/exist/xquery/update/AbstractUpdateTest.java src/test/java/org/exist/xquery/update/IndexIntegrationTest.java src/test/java/org/exist/xquery/update/UpdateInsertTest.java + src/test/java/org/exist/xquery/update/UpdateInsertTriggersDefragTest.java src/test/java/org/exist/xquery/update/UpdateReplaceTest.java src/test/java/org/exist/xquery/update/UpdateValueTest.java src/main/java/org/exist/xquery/util/ExpressionDumper.java @@ -2056,6 +2274,8 @@ src/main/java/org/exist/xupdate/Update.java src/main/java/org/exist/xupdate/XUpdateProcessor.java src/test/java/org/exist/xupdate/XUpdateTest.java + src/main/resources/xyz/elemental/mediatype/media-type-mappings.xml + src/main/resources/xyz/elemental/mediatype/mime.types @@ -2129,9 +2349,9 @@ The original license statement is also included below.]]> -
${project.parent.relativePath}/FDB-backport-LGPL-21-ONLY-license.template.txt
+
${project.parent.relativePath}/FDB-backport-to-existdb-LGPL-21-ONLY-license.template.txt
src/test/xquery/binary-value.xqm src/test/xquery/instance-of.xqm @@ -2228,9 +2448,22 @@ The original license statement is also included below.]]> -
FDB-backport-BSD-3-license.template.txt
+
${project.parent.relativePath}/../elemental-parent/FDB-backport-to-EDB-LGPL-21-ONLY-license.template.txt
+ + src/main/java/org/exist/mediatype/MediaTypeService.java + src/main/java/org/exist/mediatype/MediaTypeUtil.java + src/main/resources/xyz/elemental/mediatype/media-type-mappings.xml + src/main/resources/xyz/elemental/mediatype/mime.types + +
+ + + +
FDB-backport-to-existdb-BSD-3-license.template.txt
src/main/java/org/exist/util/CodePointString.java src/test/java/org/exist/util/CodePointStringTest.java @@ -2240,12 +2473,12 @@ The original license statement is also included below.]]> -
FDB-backport-BSD-3-license.template.txt
+
FDB-backport-to-existdb-BSD-3-license.template.txt
BX-BSD-3-license.template.txt
@@ -2346,6 +2579,23 @@ The BaseX Team. The original license statement is also included below.]]>
+ + org.jvnet.jaxb + jaxb-maven-plugin + + src/main/xjb + src/main/xsd + + + + generate-jaxb-objects + + generate + + + + + org.apache.maven.plugins maven-compiler-plugin diff --git a/exist-core/src/main/java/org/exist/backup/Backup.java b/exist-core/src/main/java/org/exist/backup/Backup.java index e000fa6d93..4ab112b1d3 100644 --- a/exist-core/src/main/java/org/exist/backup/Backup.java +++ b/exist-core/src/main/java/org/exist/backup/Backup.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -421,7 +445,7 @@ private void backup(final Set seenBlobIds, final Collection current, fin } attr.addAttribute(Namespaces.EXIST_NS, "filename", "filename", "CDATA", filename); - attr.addAttribute(Namespaces.EXIST_NS, "mimetype", "mimetype", "CDATA", encode(((EXistResource) resource).getMimeType())); + attr.addAttribute(Namespaces.EXIST_NS, "mimetype", "mimetype", "CDATA", encode(((EXistResource) resource).getMediaType())); if (XML_RESOURCE.equals(resourceType)) { diff --git a/exist-core/src/main/java/org/exist/backup/CreateBackupDialog.java b/exist-core/src/main/java/org/exist/backup/CreateBackupDialog.java index 189d06b3b9..5d2b92bef4 100644 --- a/exist-core/src/main/java/org/exist/backup/CreateBackupDialog.java +++ b/exist-core/src/main/java/org/exist/backup/CreateBackupDialog.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -22,12 +46,14 @@ package org.exist.backup; import org.exist.client.Messages; -import org.exist.client.MimeTypeFileFilter; +import org.exist.client.MediaTypeFileFilter; import org.exist.security.PermissionDeniedException; import org.exist.xmldb.XmldbURI; import org.xmldb.api.DatabaseManager; import org.xmldb.api.base.Collection; import org.xmldb.api.base.XMLDBException; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.MediaTypeResolver; import javax.swing.*; import java.awt.*; @@ -49,12 +75,13 @@ public class CreateBackupDialog extends JPanel { final String passwd; Path backupDir; final String defaultSelectedCollection; + private final MediaTypeResolver mediaTypeResolver; - public CreateBackupDialog(final String uri, final String user, final String passwd, final Path backupDir) throws HeadlessException { - this(uri, user, passwd, backupDir, null); + public CreateBackupDialog(final String uri, final String user, final String passwd, final Path backupDir, final MediaTypeResolver mediaTypeResolver) throws HeadlessException { + this(uri, user, passwd, backupDir, null, mediaTypeResolver); } - public CreateBackupDialog(final String uri, final String user, final String passwd, final Path backupDir, final String defaultSelectedCollection) throws HeadlessException { + public CreateBackupDialog(final String uri, final String user, final String passwd, final Path backupDir, final String defaultSelectedCollection, final MediaTypeResolver mediaTypeResolver) throws HeadlessException { super(false); this.uri = uri; @@ -62,6 +89,7 @@ public CreateBackupDialog(final String uri, final String user, final String pass this.passwd = passwd; this.backupDir = backupDir; this.defaultSelectedCollection = defaultSelectedCollection; + this.mediaTypeResolver = mediaTypeResolver; setupComponents(); setSize(new Dimension(350, 200)); @@ -147,7 +175,8 @@ private void actionSelect() { final JFileChooser chooser = new JFileChooser(); chooser.setMultiSelectionEnabled(false); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); - chooser.addChoosableFileFilter(new MimeTypeFileFilter("application/zip")); + final MediaType mediaType = mediaTypeResolver.fromString(MediaType.APPLICATION_ZIP); + chooser.addChoosableFileFilter(new MediaTypeFileFilter(mediaType)); chooser.setSelectedFile(Paths.get("eXist-backup.zip").toFile()); chooser.setCurrentDirectory(backupDir.toFile()); diff --git a/exist-core/src/main/java/org/exist/backup/ExportGUI.java b/exist-core/src/main/java/org/exist/backup/ExportGUI.java index 0454f591ed..d50d380164 100644 --- a/exist-core/src/main/java/org/exist/backup/ExportGUI.java +++ b/exist-core/src/main/java/org/exist/backup/ExportGUI.java @@ -53,14 +53,14 @@ import org.exist.storage.DBBroker; import org.exist.storage.txn.Txn; import org.exist.util.Configuration; -import org.exist.util.MimeTable; -import org.exist.util.MimeType; import org.exist.util.OSUtil; import org.exist.util.SystemExitCodes; import org.exist.xquery.TerminatedException; import se.softhouse.jargo.Argument; import se.softhouse.jargo.ArgumentException; import se.softhouse.jargo.CommandLineParser; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.StorageType; import javax.swing.*; import javax.swing.filechooser.FileFilter; @@ -437,19 +437,20 @@ private void btnConfSelectActionPerformed(final java.awt.event.ActionEvent evt) .toFile()); chooser.setCurrentDirectory(dir.resolve("etc").toFile()); chooser.setFileFilter(new FileFilter() { + @Override public boolean accept(final File f) { if (f.isDirectory()) { return (true); } - final MimeType mime = MimeTable.getInstance().getContentTypeFor(f.getName()); + final MediaType mediaType = pool.getMediaTypeService().getMediaTypeResolver().fromFileName(f.toPath()); - if (mime == null) { + if (mediaType == null) { return false; } - return mime.isXMLType(); + return mediaType.getStorageType() == StorageType.XML; } - + @Override public String getDescription() { return ("Database XML configuration file"); } diff --git a/exist-core/src/main/java/org/exist/backup/Main.java b/exist-core/src/main/java/org/exist/backup/Main.java index 7e15f31ea5..f63f98b6f2 100644 --- a/exist-core/src/main/java/org/exist/backup/Main.java +++ b/exist-core/src/main/java/org/exist/backup/Main.java @@ -46,6 +46,7 @@ package org.exist.backup; import org.exist.client.ClientFrame; +import org.exist.mediatype.MediaTypeUtil; import org.exist.start.CompatibleJavaVersionCheck; import org.exist.start.StartException; import org.exist.util.ConfigurationHelper; @@ -58,7 +59,9 @@ import org.xmldb.api.base.Database; import org.xmldb.api.base.XMLDBException; import se.softhouse.jargo.*; +import xyz.elemental.mediatype.MediaTypeResolver; +import javax.annotation.Nullable; import javax.swing.*; import java.io.File; import java.io.IOException; @@ -223,12 +226,17 @@ public static void process(final ParsedArguments arguments) { return; } + // load MediaTypeResolver + final Optional existHome = ConfigurationHelper.getExistHome(); + @Nullable final Path applicationConfigDir = existHome.map(p -> p.resolve("etc")).filter(Files::exists).orElse(null); + @Nullable final MediaTypeResolver mediaTypeResolver = MediaTypeUtil.newMediaTypeResolver(applicationConfigDir); + // process if (backupCollection.isPresent()) { String collection = backupCollection.get(); if (collection.isEmpty()) { if (guiMode) { - final CreateBackupDialog dialog = new CreateBackupDialog(properties.getProperty(URI_PROP, DEFAULT_URI), properties.getProperty(USER_PROP, DEFAULT_USER), properties.getProperty(PASSWORD_PROP, DEFAULT_PASSWORD), Paths.get(preferences.get("directory.backup", System.getProperty("user.dir")))); + final CreateBackupDialog dialog = new CreateBackupDialog(properties.getProperty(URI_PROP, DEFAULT_URI), properties.getProperty(USER_PROP, DEFAULT_USER), properties.getProperty(PASSWORD_PROP, DEFAULT_PASSWORD), Paths.get(preferences.get("directory.backup", System.getProperty("user.dir"))), mediaTypeResolver); if (JOptionPane.showOptionDialog(null, dialog, "Create Backup", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null) == JOptionPane.YES_OPTION) { collection = dialog.getCollection(); diff --git a/exist-core/src/main/java/org/exist/backup/Restore.java b/exist-core/src/main/java/org/exist/backup/Restore.java index 7b38622b11..b66debebf9 100644 --- a/exist-core/src/main/java/org/exist/backup/Restore.java +++ b/exist-core/src/main/java/org/exist/backup/Restore.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -36,6 +60,7 @@ import org.exist.util.XMLReaderPool; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; +import xyz.elemental.mediatype.MediaTypeResolver; import javax.annotation.Nullable; import java.io.IOException; @@ -57,7 +82,7 @@ public class Restore { private static final byte[] ZIP_FILE_MAGIC_NUMBER = {0x50, 0x4B, 0x03, 0x04}; public void restore(final DBBroker broker, @Nullable final Txn transaction, final String newAdminPass, final Path f, - final RestoreListener listener, final boolean overwriteApps) throws EXistException, IOException, SAXException, PermissionDeniedException { + final RestoreListener listener, final boolean overwriteApps, final MediaTypeResolver mediaTypeResolver) throws EXistException, IOException, SAXException, PermissionDeniedException { //set the admin password if (newAdminPass != null) { diff --git a/exist-core/src/main/java/org/exist/backup/SystemExport.java b/exist-core/src/main/java/org/exist/backup/SystemExport.java index c403e170b2..d9eae3b9cb 100644 --- a/exist-core/src/main/java/org/exist/backup/SystemExport.java +++ b/exist-core/src/main/java/org/exist/backup/SystemExport.java @@ -93,6 +93,7 @@ import org.xml.sax.helpers.AttributesImpl; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.NamespaceSupport; +import xyz.elemental.mediatype.MediaType; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; @@ -565,10 +566,10 @@ private void exportDocument(final BackupWriter output, final Date date, final Ba } attr.addAttribute(Namespaces.EXIST_NS, "filename", "filename", "CDATA", Backup.encode(URIUtils.urlDecodeUtf8(doc.getFileURI()))); - String mimeType = "application/xml"; + String mimeType = MediaType.APPLICATION_XML; - if (doc.getMimeType() != null) { - mimeType = Backup.encode(doc.getMimeType()); + if (doc.getMediaType() != null) { + mimeType = Backup.encode(doc.getMediaType()); } attr.addAttribute(Namespaces.EXIST_NS, "mimetype", "mimetype", "CDATA", mimeType); diff --git a/exist-core/src/main/java/org/exist/backup/restore/AbstractRestoreHandler.java b/exist-core/src/main/java/org/exist/backup/restore/AbstractRestoreHandler.java index 218efd7237..34fe394668 100644 --- a/exist-core/src/main/java/org/exist/backup/restore/AbstractRestoreHandler.java +++ b/exist-core/src/main/java/org/exist/backup/restore/AbstractRestoreHandler.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -55,6 +79,10 @@ import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.MediaTypeResolver; +import xyz.elemental.mediatype.StorageType; +import xyz.elemental.mediatype.impl.MediaTypeImpl; import javax.annotation.Nullable; import java.io.IOException; @@ -63,6 +91,7 @@ import static com.evolvedbinary.j8fu.tuple.Tuple.Tuple; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.exist.util.StringUtil.isNullOrEmpty; /** * SAX Content Handler that can act upon @@ -89,7 +118,6 @@ public abstract class AbstractRestoreHandler extends DefaultHandler { @Nullable private final Txn transaction; private final BackupDescriptor descriptor; private final RestoreListener listener; - @Nullable private final Set pathsToIgnore; //handler state @@ -312,7 +340,7 @@ private DeferredPermission restoreResourceEntry(final Attributes attributes) thr final boolean xmlType = Optional.ofNullable(attributes.getValue("type")).filter(s -> s.equals("XMLResource")).isPresent(); final String filename = getAttr(attributes, "filename", commonAttributes.name); - @Nullable final String mimeTypeStr = attributes.getValue("mimetype"); + @Nullable final String mediaTypeStr = attributes.getValue("mimetype"); @Nullable final String dateModifiedStr = attributes.getValue("modified"); @Nullable final String publicId = attributes.getValue("publicid"); @Nullable final String systemId = attributes.getValue("systemid"); @@ -343,12 +371,19 @@ private DeferredPermission restoreResourceEntry(final Attributes attributes) thr } } - final MimeType mimeType; - if (mimeTypeStr == null || mimeTypeStr.trim().isEmpty()) { - mimeType = xmlType ? MimeType.XML_TYPE : MimeType.BINARY_TYPE; - listener.warn("Missing mimetype attribute in the backup __contents__.xml file for: " + commonAttributes.name + ", assuming: " + mimeType); + final MediaTypeResolver mediaTypeResolver = broker.getBrokerPool().getMediaTypeService().getMediaTypeResolver(); + + MediaType mediaType; + if (isNullOrEmpty(mediaTypeStr)) { + mediaType = xmlType ? mediaTypeResolver.fromString(MediaType.APPLICATION_XML) : mediaTypeResolver.forUnknown(); + listener.warn("Missing mimetype attribute in the backup __contents__.xml file for: " + commonAttributes.name + ", assuming: " + mediaType); } else { - mimeType = new MimeType(mimeTypeStr.trim(), xmlType ? MimeType.XML : MimeType.BINARY); + mediaType = mediaTypeResolver.fromString(mediaTypeStr.trim()); + if (xmlType && mediaType.getStorageType() != StorageType.XML) { + mediaType = MediaTypeImpl.builder(mediaTypeStr.trim(), StorageType.XML).build(); + } else if ((!xmlType) && mediaType.getStorageType() != StorageType.BINARY) { + mediaType = MediaTypeImpl.builder(mediaTypeStr.trim(), StorageType.BINARY).build(); + } } Date dateCreated = null; @@ -385,7 +420,7 @@ private DeferredPermission restoreResourceEntry(final Attributes attributes) thr try (final Collection collection = broker.openCollection(currentCollectionUri, Lock.LockMode.WRITE_LOCK); final ManagedDocumentLock docLock = broker.getBrokerPool().getLockManager().acquireDocumentWriteLock(docUri)) { - broker.storeDocument(transaction, docName, is, mimeType, dateCreated, dateModified, null, docType, null, collection); + broker.storeDocument(transaction, docName, is, mediaType, dateCreated, dateModified, null, docType, null, collection); validated = true; notifyStartDocumentRestore(docUri, attributes); @@ -572,6 +607,7 @@ private static String getAttr(final Attributes atts, final String name, final St * @param descriptor the backup descriptor to start restoring from * @param listener the listener to report restore events to * @param pathsToIgnore database paths to ignore in the backup + * * @return a new restore handler */ protected abstract AbstractRestoreHandler newSelf(final DBBroker broker, @Nullable final Txn transaction, diff --git a/exist-core/src/main/java/org/exist/backup/xquery/RetrieveBackup.java b/exist-core/src/main/java/org/exist/backup/xquery/RetrieveBackup.java index 64a54d8746..c481831bb5 100644 --- a/exist-core/src/main/java/org/exist/backup/xquery/RetrieveBackup.java +++ b/exist-core/src/main/java/org/exist/backup/xquery/RetrieveBackup.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -31,6 +55,7 @@ import org.exist.xquery.value.Sequence; import org.exist.xquery.value.SequenceType; import org.exist.xquery.value.Type; +import xyz.elemental.mediatype.MediaType; import java.io.IOException; import java.io.OutputStream; @@ -101,7 +126,7 @@ public Sequence eval(final Sequence[] args, final Sequence contextSequence ) thr throw new XPathException(this, signature.toString() + " can only be used within the EXistServlet or XQueryServlet"); } - response.setContentType("application/zip"); + response.setContentType(MediaType.APPLICATION_ZIP); response.setHeader("Content-Length", String.valueOf(FileUtils.sizeQuietly(backupFile))); try { try(final OutputStream os = response.getOutputStream()) { diff --git a/exist-core/src/main/java/org/exist/client/ClientFrame.java b/exist-core/src/main/java/org/exist/client/ClientFrame.java index d5e722a432..52547f6fbb 100644 --- a/exist-core/src/main/java/org/exist/client/ClientFrame.java +++ b/exist-core/src/main/java/org/exist/client/ClientFrame.java @@ -58,7 +58,6 @@ import org.exist.security.internal.aider.SimpleACLPermissionAider; import org.exist.storage.serializers.EXistOutputKeys; import org.exist.util.FileUtils; -import org.exist.util.MimeTable; import org.exist.util.SystemExitCodes; import org.exist.util.crypto.digest.DigestType; import org.exist.util.crypto.digest.MessageDigest; @@ -73,7 +72,11 @@ import org.xmldb.api.base.Resource; import org.xmldb.api.base.XMLDBException; import org.xmldb.api.modules.XMLResource; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.MediaTypeResolver; +import xyz.elemental.mediatype.StorageType; +import javax.annotation.Nullable; import javax.swing.*; import javax.swing.border.BevelBorder; import javax.swing.filechooser.FileFilter; @@ -298,7 +301,7 @@ private void setupComponents() { // shell window doc = new DefaultStyledDocument(); shell = new JTextPane(doc); - shell.setContentType("text/plain; charset=UTF-8"); //$NON-NLS-1$ + shell.setContentType(MediaType.TEXT_PLAIN + "; charset=UTF-8"); //$NON-NLS-1$ shell.setFont(new Font("Monospaced", Font.PLAIN, 12)); //$NON-NLS-1$ shell.setMargin(new Insets(7, 5, 7, 5)); shell.addKeyListener(this); @@ -998,8 +1001,8 @@ private void uploadAction(final ActionEvent ev) { final JFileChooser chooser = new JFileChooser(preferences.get("directory.last", System.getProperty("user.dir"))); chooser.setMultiSelectionEnabled(true); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); - chooser.addChoosableFileFilter(new BinaryFileFilter()); - chooser.addChoosableFileFilter(new XMLFileFilter()); + chooser.addChoosableFileFilter(new BinaryFileFilter(client.getMediaTypeResolver())); + chooser.addChoosableFileFilter(new XMLFileFilter(client.getMediaTypeResolver())); if (chooser.showDialog(this, Messages.getString("ClientFrame.146")) == JFileChooser.APPROVE_OPTION) { //$NON-NLS-1$ // remember directory in preferences preferences.put("directory.last", chooser.getCurrentDirectory().getAbsolutePath()); @@ -1053,7 +1056,8 @@ private void backupAction(final ActionEvent ev) { properties.getProperty(InteractiveClient.USER, SecurityManager.DBA_USER), properties.getProperty(InteractiveClient.PASSWORD, null), Paths.get(preferences.get("directory.backup", System.getProperty("user.home"))), - defaultSelectedCollection + defaultSelectedCollection, + client.getMediaTypeResolver() ); if (JOptionPane.showOptionDialog(this, dialog, Messages.getString("ClientFrame.157"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null) == JOptionPane.YES_OPTION) { @@ -1320,7 +1324,7 @@ private void setPermAction(final ActionEvent ev) throws PermissionDeniedExceptio final Resource res = collection.getResource(thisName.toString()); thisCreated = DATE_TIME_FORMATTER.format(res.getCreationTime()); thisModified = DATE_TIME_FORMATTER.format(res.getLastModificationTime()); - thisMimeType = ((EXistResource) res).getMimeType(); + thisMimeType = ((EXistResource) res).getMediaType(); if (res instanceof EXistBinaryResource) { final MessageDigest messageDigest = ((EXistBinaryResource) res).getContentDigest(DigestType.BLAKE_256); thisMessageDigestType = messageDigest.getDigestType().getCommonNames()[0]; @@ -1540,7 +1544,7 @@ public void mouseClicked(final MouseEvent e) { try { final Resource doc = client.retrieve(resource.getName(), properties.getProperty(OutputKeys.INDENT, "yes")); //$NON-NLS-1$ - if ("application/xquery".equals(((EXistResource) doc).getMimeType())) { + if (MediaType.APPLICATION_XQUERY.equals(((EXistResource) doc).getMediaType())) { final Collection collection = client.getCollection(); final QueryDialog dialog = new QueryDialog(client, collection, doc, properties); dialog.setVisible(true); @@ -1887,46 +1891,46 @@ public void mouseReleased(final MouseEvent e) { } static class BinaryFileFilter extends FileFilter { + private final MediaTypeResolver mediaTypeResolver; + + public BinaryFileFilter(final MediaTypeResolver mediaTypeResolver) { + this.mediaTypeResolver = mediaTypeResolver; + } - /* (non-Javadoc) - * @see javax.swing.filechooser.FileFilter#getDescription() - */ @Override public String getDescription() { return Messages.getString("ClientFrame.220"); //$NON-NLS-1$ } - /* (non-Javadoc) - * @see javax.swing.filechooser.FileFilter#accept(java.io.File) - */ @Override public boolean accept(final File f) { if (f.isDirectory()) { return true; } - return !MimeTable.getInstance().isXMLContent(f.getName()); + @Nullable MediaType mediaType = mediaTypeResolver.fromFileName(f.toPath().getFileName()); + return mediaType == null || mediaType.getStorageType() != StorageType.XML; } } static class XMLFileFilter extends FileFilter { + private final MediaTypeResolver mediaTypeResolver; + + public XMLFileFilter(final MediaTypeResolver mediaTypeResolver) { + this.mediaTypeResolver = mediaTypeResolver; + } - /* (non-Javadoc) - * @see javax.swing.filechooser.FileFilter#getDescription() - */ @Override public String getDescription() { return Messages.getString("ClientFrame.221"); //$NON-NLS-1$ } - /* (non-Javadoc) - * @see javax.swing.filechooser.FileFilter#accept(java.io.File) - */ @Override public boolean accept(final File f) { if (f.isDirectory()) { return true; } - return MimeTable.getInstance().isXMLContent(f.getName()); + @Nullable MediaType mediaType = mediaTypeResolver.fromFileName(f.toPath().getFileName()); + return mediaType != null && mediaType.getStorageType() == StorageType.XML; } } @@ -1981,7 +1985,7 @@ private List getFilesWin32(final Transferable transferable) throws Unsuppo private List getFilesUnix(final Transferable transferable) throws ClassNotFoundException, UnsupportedFlavorException, IOException, URISyntaxException { List files = null; - final DataFlavor unixFileDataFlavour = new DataFlavor("text/uri-list;class=java.lang.String"); + final DataFlavor unixFileDataFlavour = new DataFlavor(MediaType.TEXT_URI_LIST + ";class=java.lang.String"); final String data = (String) transferable.getTransferData(unixFileDataFlavour); for (final StringTokenizer st = new StringTokenizer(data, "\r\n"); st.hasMoreTokens(); ) { final String token = st.nextToken().trim(); diff --git a/exist-core/src/main/java/org/exist/client/InteractiveClient.java b/exist-core/src/main/java/org/exist/client/InteractiveClient.java index 3346f69fbd..fbcfd5de0b 100644 --- a/exist-core/src/main/java/org/exist/client/InteractiveClient.java +++ b/exist-core/src/main/java/org/exist/client/InteractiveClient.java @@ -65,6 +65,7 @@ import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import javax.annotation.Nullable; import javax.swing.ImageIcon; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; @@ -76,6 +77,7 @@ import org.apache.tools.ant.DirectoryScanner; import org.exist.SystemProperties; import org.exist.dom.persistent.XMLUtil; +import org.exist.mediatype.MediaTypeUtil; import org.exist.security.Account; import org.exist.security.Group; import org.exist.security.Permission; @@ -110,8 +112,12 @@ import org.xmldb.api.base.*; import org.xmldb.api.base.Collection; import org.xmldb.api.modules.BinaryResource; +import org.xmldb.api.modules.XMLResource; import org.xmldb.api.modules.XUpdateQueryService; import se.softhouse.jargo.ArgumentException; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.MediaTypeResolver; +import xyz.elemental.mediatype.StorageType; import static java.nio.charset.StandardCharsets.UTF_8; import static java.time.ZoneOffset.UTC; @@ -226,6 +232,8 @@ public InteractiveClient(CommandlineOptions options) { this.options = options; } + private MediaTypeResolver mediaTypeResolver = null; + /** * Display help on commands */ @@ -1311,21 +1319,25 @@ private void reindex() throws XMLDBException { private void storeBinary(final String fileName) throws XMLDBException { final Path file = Paths.get(fileName).normalize(); if (Files.isReadable(file)) { - final MimeType mime = MimeTable.getInstance().getContentTypeFor(FileUtils.fileName(file)); + @Nullable final MediaType mediaType = mediaTypeResolver.fromFileName(FileUtils.fileName(file)); try (final BinaryResource resource = current.createResource(FileUtils.fileName(file), BinaryResource.class)) { resource.setContent(file); - ((EXistResource) resource).setMimeType(mime == null ? "application/octet-stream" : mime.getName()); + ((EXistResource) resource).setMediaType(mediaType == null ? mediaTypeResolver.forUnknown().getIdentifier() : mediaType.getIdentifier()); current.storeResource(resource); } } } + MediaTypeResolver getMediaTypeResolver() { + return mediaTypeResolver; + } + private synchronized boolean findRecursive(final Collection collection, final Path dir, final XmldbURI base) throws XMLDBException { Collection c; EXistCollectionManagementService mgtService; //The XmldbURIs here aren't really used... XmldbURI next; - MimeType mimeType; + @Nullable MediaType mediaType = null; try { final List files = FileUtils.list(dir); @@ -1348,15 +1360,15 @@ private synchronized boolean findRecursive(final Collection collection, final Pa findRecursive(c, file, next); } else { final long start1 = System.currentTimeMillis(); - mimeType = MimeTable.getInstance().getContentTypeFor(FileUtils.fileName(file)); - if (mimeType == null) { + mediaType = mediaTypeResolver.fromFileName(FileUtils.fileName(file)); + if (mediaType == null) { messageln("File " + FileUtils.fileName(file) + " has an unknown suffix. Cannot determine file type."); - mimeType = MimeType.BINARY_TYPE; + mediaType = mediaTypeResolver.forUnknown(); } - try (final Resource document = collection.createResource(FileUtils.fileName(file), mimeType.getXMLDBType())) { + try (final Resource document = collection.createResource(FileUtils.fileName(file), toResourceTypeClass(mediaType))) { message("storing document " + FileUtils.fileName(file) + " (" + i + " of " + files.size() + ") " + "..."); document.setContent(file); - ((EXistResource) document).setMimeType(mimeType.getName()); + ((EXistResource) document).setMediaType(mediaType.getIdentifier()); collection.storeResource(document); ++filesCount; messageln(" " + FileUtils.sizeQuietly(file) + " bytes in " + (System.currentTimeMillis() - start1) + "ms."); @@ -1373,6 +1385,10 @@ private synchronized boolean findRecursive(final Collection collection, final Pa } } + private static Class toResourceTypeClass(final MediaType mediaType) { + return mediaType.getStorageType() == StorageType.XML ? XMLResource.class : BinaryResource.class; + } + /** * Stores given Resource * @@ -1418,20 +1434,20 @@ protected synchronized boolean parse(final Path file) throws XMLDBException { final long start0 = System.currentTimeMillis(); long bytes = 0; - MimeType mimeType; + @Nullable MediaType mediaType = null; for (int i = 0; i < files.size(); i++) { if (Files.isDirectory(files.get(i))) { continue; } final long start = System.currentTimeMillis(); - mimeType = MimeTable.getInstance().getContentTypeFor(FileUtils.fileName(files.get(i))); - if (mimeType == null) { - mimeType = MimeType.BINARY_TYPE; + mediaType = mediaTypeResolver.fromFileName(FileUtils.fileName(files.get(i))); + if (mediaType == null) { + mediaType = mediaTypeResolver.forUnknown(); } - try (final Resource document = current.createResource(FileUtils.fileName(files.get(i)), mimeType.getXMLDBType())) { + try (final Resource document = current.createResource(FileUtils.fileName(files.get(i)), toResourceTypeClass(mediaType))) { message("storing document " + FileUtils.fileName(files.get(i)) + " (" + (i + 1) + " of " + files.size() + ") ..."); document.setContent(files.get(i)); - ((EXistResource) document).setMimeType(mimeType.getName()); + ((EXistResource) document).setMediaType(mediaType.getIdentifier()); current.storeResource(document); messageln(DONE); messageln("parsing " + FileUtils.sizeQuietly(files.get(i)) + " bytes took " + (System.currentTimeMillis() - start) + "ms." + EOL); @@ -1453,7 +1469,7 @@ private synchronized boolean findGZipRecursive(final Collection collection, fina EXistCollectionManagementService mgtService; //The XmldbURIs here aren't really used... XmldbURI next; - MimeType mimeType; + @Nullable MediaType mediaType = null; int i = 0; for (final Path file : files) { i++; @@ -1485,15 +1501,15 @@ private synchronized boolean findGZipRecursive(final Collection collection, fina break; } } - mimeType = MimeTable.getInstance().getContentTypeFor(localName); - if (mimeType == null) { + mediaType = mediaTypeResolver.fromFileName(localName); + if (mediaType == null) { messageln("File " + compressedName + " has an unknown suffix. Cannot determine file type."); - mimeType = MimeType.BINARY_TYPE; + mediaType = mediaTypeResolver.forUnknown(); } - try (final Resource document = collection.createResource(compressedName, mimeType.getXMLDBType())) { + try (final Resource document = collection.createResource(compressedName, toResourceTypeClass(mediaType))) { message("storing document " + compressedName + " (" + i + " of " + files.size() + ") " + "..."); document.setContent(isCompressed ? new GZIPInputSource(file) : file); - ((EXistResource) document).setMimeType(mimeType.getName()); + ((EXistResource) document).setMediaType(mediaType.getIdentifier()); collection.storeResource(document); ++filesCount; messageln(" " + Files.size(file) + (isCompressed ? " compressed" : "") + " bytes in " @@ -1560,7 +1576,7 @@ protected synchronized boolean parseGZip(String fileName) throws XMLDBException, final long start0 = System.currentTimeMillis(); long bytes = 0; - MimeType mimeType; + @Nullable MediaType mediaType = null; int i = 0; for (final Path p : files) { i++; @@ -1580,15 +1596,15 @@ protected synchronized boolean parseGZip(String fileName) throws XMLDBException, break; } } - mimeType = MimeTable.getInstance().getContentTypeFor(localName); - if (mimeType == null) { - mimeType = MimeType.BINARY_TYPE; + mediaType = mediaTypeResolver.fromFileName(localName); + if (mediaType == null) { + mediaType = mediaTypeResolver.forUnknown(); } - try (final Resource document = current.createResource(compressedName, mimeType.getXMLDBType())) { + try (final Resource document = current.createResource(compressedName, toResourceTypeClass(mediaType))) { message("storing document " + compressedName + " (" + i + " of " + Files.size(p) + ") ..."); document.setContent(isCompressed ? new GZIPInputSource(p) : p); - ((EXistResource) document).setMimeType(mimeType.getName()); + ((EXistResource) document).setMediaType(mediaType.getIdentifier()); current.storeResource(document); messageln(DONE); messageln("parsing " + Files.size(p) + (isCompressed ? " compressed" : "") + " bytes took " @@ -1658,15 +1674,15 @@ protected synchronized boolean parseZip(final Path zipPath) throws XMLDBExceptio if (!ze.isDirectory()) { final String localName = pathSteps[pathSteps.length - 1]; final long start = System.currentTimeMillis(); - MimeType mimeType = MimeTable.getInstance().getContentTypeFor(localName); - if (mimeType == null) { - mimeType = MimeType.BINARY_TYPE; + @Nullable MediaType mediaType = mediaTypeResolver.fromFileName(localName); + if (mediaType == null) { + mediaType = mediaTypeResolver.forUnknown(); } - try (final Resource document = base.createResource(localName, mimeType.getXMLDBType())) { + try (final Resource document = base.createResource(localName, toResourceTypeClass(mediaType))) { message("storing Zip-entry document " + localName + " (" + (number) + " of " + zfile.size() + ") ..."); document.setContent(new ZipEntryInputSource(zfile, ze)); - ((EXistResource) document).setMimeType(mimeType.getName()); + ((EXistResource) document).setMediaType(mediaType.getIdentifier()); base.storeResource(document); messageln(DONE); messageln("parsing " + ze.getSize() + " bytes took " @@ -1783,19 +1799,17 @@ private void store(final Collection collection, final Path file, final UploadDia final long fileSize = FileUtils.sizeQuietly(file); upload.setCurrentSize(fileSize); - MimeType mimeType = MimeTable.getInstance().getContentTypeFor(FileUtils.fileName(file)); + MediaType mediaType = mediaTypeResolver.fromFileName(FileUtils.fileName(file)); // unknown mime type, here prefered is to do nothing - if (mimeType == null) { - upload.showMessage(file.toAbsolutePath() + - " - unknown suffix. No matching mime-type found in : " + - MimeTable.getInstance().getSrc()); + if (mediaType == null) { + upload.showMessage(file.toAbsolutePath() + " - unknown suffix. No matching mime-type found"); // if some one prefers to store it as binary by default, but dangerous - mimeType = MimeType.BINARY_TYPE; + mediaType = mediaTypeResolver.forUnknown(); } - try (final Resource res = collection.createResource(filenameUri.toString(), mimeType.getXMLDBType())) { - ((EXistResource) res).setMimeType(mimeType.getName()); + try (final Resource res = collection.createResource(filenameUri.toString(), toResourceTypeClass(mediaType))) { + ((EXistResource) res).setMediaType(mediaType.getIdentifier()); res.setContent(file); collection.storeResource(res); ++filesCount; @@ -2108,7 +2122,10 @@ public boolean run() throws Exception { final Optional home = ConfigurationHelper.getExistHome(); // get default configuration filename from the driver class and set it in properties - applyDefaultConfig(home); + final Optional configFile = applyDefaultConfig(home); + + @Nullable final Path applicationConfigDir = configFile.map(Path::getParent).filter(Files::exists).orElse(null); + this.mediaTypeResolver = MediaTypeUtil.newMediaTypeResolver(applicationConfigDir); properties.putAll(loadClientProperties()); @@ -2191,7 +2208,7 @@ private boolean checkLoginInfos(boolean interactive) { return false; } - private void applyDefaultConfig(Optional home) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { + private Optional applyDefaultConfig(Optional home) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { Optional configFile = ConfigurationHelper.getFromSystemProperty(); if (!configFile.isPresent()) { final Class cl = Class.forName(properties.getProperty(DRIVER)); @@ -2201,6 +2218,7 @@ private void applyDefaultConfig(Optional home) throws ClassNotFoundExcepti } } configFile.ifPresent(value -> properties.setProperty(CONFIGURATION, value.toString())); + return configFile; } final boolean isInteractive() { diff --git a/exist-core/src/main/java/org/exist/client/MimeTypeFileFilter.java b/exist-core/src/main/java/org/exist/client/MediaTypeFileFilter.java similarity index 52% rename from exist-core/src/main/java/org/exist/client/MimeTypeFileFilter.java rename to exist-core/src/main/java/org/exist/client/MediaTypeFileFilter.java index 611aa6e537..aacdcd9ef5 100644 --- a/exist-core/src/main/java/org/exist/client/MimeTypeFileFilter.java +++ b/exist-core/src/main/java/org/exist/client/MediaTypeFileFilter.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -22,12 +46,10 @@ package org.exist.client; import java.io.File; -import java.util.Iterator; -import java.util.List; import javax.swing.filechooser.FileFilter; -import org.exist.util.MimeTable; +import xyz.elemental.mediatype.MediaType; /** @@ -36,18 +58,16 @@ * * Java 6 API has a similar FileNameExtensionFilter */ -public class MimeTypeFileFilter extends FileFilter { +public class MediaTypeFileFilter extends FileFilter { - private String description = null; - private List extensions = null; + private final MediaType mediaType; - public MimeTypeFileFilter(String mimeType) { - description = MimeTable.getInstance().getContentType(mimeType).getDescription(); - extensions = MimeTable.getInstance().getAllExtensions(mimeType); + public MediaTypeFileFilter(final MediaType mediaType) { + this.mediaType = mediaType; } @Override - public boolean accept(File file) { + public boolean accept(final File file) { if(file.isDirectory()){ //permit directories to be viewed return true; } @@ -60,8 +80,9 @@ public boolean accept(File file) { //check the extension is that of a file as defined in mime-types.xml final String fileExtension = file.getName().substring(extensionOffset).toLowerCase(); - for(final String extension : extensions) { - if(fileExtension.equals(extension)) { + final String[] extensions = mediaType.getKnownFileExtensions(); + for (final String extension : extensions) { + if (fileExtension.equals(extension)) { return true; } } @@ -71,15 +92,16 @@ public boolean accept(File file) { @Override public String getDescription() { - final StringBuilder description = new StringBuilder(this.description); + final StringBuilder description = new StringBuilder(mediaType.getIdentifier()); description.append(" ("); - for(final Iterator itExtensions = extensions.iterator(); itExtensions.hasNext();) { - description.append(itExtensions.next()); - if(itExtensions.hasNext()) { + final String[] extensions = mediaType.getKnownFileExtensions(); + for (int i = 0; i < extensions.length; i++) { + if (i > 0) { description.append(' '); } + description.append(extensions[i]); } description.append(")"); diff --git a/exist-core/src/main/java/org/exist/client/NewResourceDialog.java b/exist-core/src/main/java/org/exist/client/NewResourceDialog.java index 8adcdadcc4..fc7dc739f2 100644 --- a/exist-core/src/main/java/org/exist/client/NewResourceDialog.java +++ b/exist-core/src/main/java/org/exist/client/NewResourceDialog.java @@ -68,6 +68,7 @@ import org.xmldb.api.base.XMLDBException; import org.xmldb.api.modules.BinaryResource; import org.xmldb.api.modules.XMLResource; +import xyz.elemental.mediatype.MediaType; import static org.exist.util.StringUtil.isNullOrEmpty; @@ -91,9 +92,9 @@ public NewResourceDialog(final InteractiveClient client) { } private enum ResourceType { - XML_DOCUMENT("XML Document", "xml", "application/xml", "xml-resource.tmpl"), - XQUERY_MAIN("XQuery Main Module", "xqy", "application/xquery", "xquery-resource.tmpl"), - XQUERY_LIBRARY("XQuery Library Module", "xqm", "application/xquery", "xquery-lib-resource.tmpl"); + XML_DOCUMENT("XML Document", "xml", MediaType.APPLICATION_XML, "xml-resource.tmpl"), + XQUERY_MAIN("XQuery Main Module", "xqy", MediaType.APPLICATION_XQUERY, "xquery-resource.tmpl"), + XQUERY_LIBRARY("XQuery Library Module", "xqm", MediaType.APPLICATION_XQUERY, "xquery-lib-resource.tmpl"); private final String label; private final String fileExtension; @@ -315,7 +316,7 @@ private void createResource(final ResourceType resourceType, final String filena try (final Collection collection = client.current; final Resource resource = collection.createResource(resName, resType)) { resource.setContent(resourceContent); - ((EXistResource) resource).setMimeType(resourceType.getMimeType()); + ((EXistResource) resource).setMediaType(resourceType.getMimeType()); collection.storeResource(resource); } client.reloadCollection(); @@ -323,4 +324,4 @@ private void createResource(final ResourceType resourceType, final String filena ClientFrame.showErrorMessage(xmldbe.getMessage(), xmldbe); } } -} \ No newline at end of file +} diff --git a/exist-core/src/main/java/org/exist/client/QueryDialog.java b/exist-core/src/main/java/org/exist/client/QueryDialog.java index 291cc435b7..1253ac6eaf 100644 --- a/exist-core/src/main/java/org/exist/client/QueryDialog.java +++ b/exist-core/src/main/java/org/exist/client/QueryDialog.java @@ -106,6 +106,7 @@ import org.xmldb.api.base.ResourceIterator; import org.xmldb.api.base.ResourceSet; import org.xmldb.api.base.XMLDBException; +import xyz.elemental.mediatype.MediaType; import static java.nio.charset.StandardCharsets.UTF_8; import static org.xmldb.api.base.ResourceType.XML_RESOURCE; @@ -441,7 +442,7 @@ private void open() { chooser.setCurrentDirectory(Paths.get(workDir).toFile()); chooser.setMultiSelectionEnabled(false); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - chooser.addChoosableFileFilter(new MimeTypeFileFilter("application/xquery")); + chooser.addChoosableFileFilter(new MediaTypeFileFilter(client.getMediaTypeResolver().fromString(MediaType.APPLICATION_XQUERY))); if (chooser.showDialog(this, Messages.getString("QueryDialog.opendialog")) == JFileChooser.APPROVE_OPTION) { final Path selectedDir = chooser.getCurrentDirectory().toPath(); @@ -477,10 +478,10 @@ private void save(String stringToSave, String fileCategory) { chooser.setCurrentDirectory(Paths.get(workDir).toFile()); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); if ("result".equals(fileCategory)) { - chooser.addChoosableFileFilter(new MimeTypeFileFilter("application/xhtml+xml")); - chooser.addChoosableFileFilter(new MimeTypeFileFilter("application/xml")); + chooser.addChoosableFileFilter(new MediaTypeFileFilter(client.getMediaTypeResolver().fromString(MediaType.APPLICATION_XHTML))); + chooser.addChoosableFileFilter(new MediaTypeFileFilter(client.getMediaTypeResolver().fromString(MediaType.APPLICATION_XML))); } else { - chooser.addChoosableFileFilter(new MimeTypeFileFilter("application/xquery")); + chooser.addChoosableFileFilter(new MediaTypeFileFilter(client.getMediaTypeResolver().fromString(MediaType.APPLICATION_XQUERY))); } if (chooser.showDialog(this, Messages.getString("QueryDialog.savedialogpre") + " " + fileCategory + " " + Messages.getString("QueryDialog.savedialogpost")) == JFileChooser.APPROVE_OPTION) { diff --git a/exist-core/src/main/java/org/exist/collections/Collection.java b/exist-core/src/main/java/org/exist/collections/Collection.java index 4e4c2b287f..c7bf145fad 100644 --- a/exist-core/src/main/java/org/exist/collections/Collection.java +++ b/exist-core/src/main/java/org/exist/collections/Collection.java @@ -66,6 +66,7 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; +import xyz.elemental.mediatype.MediaType; import javax.annotation.Nullable; import java.io.IOException; @@ -664,7 +665,7 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * Since the process is dependent on the collection configuration, * the collection acquires a write lock during the process. * - * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} + * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} * * @param transaction The database transaction * @param broker The database broker @@ -678,7 +679,10 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * @throws TriggerException in case of trigger error * @throws EXistException general exception * @throws SAXException internal SAXException + * + * @deprecated Use {@link #storeDocument(Txn, DBBroker, XmldbURI, InputSource, MediaType)} instead. */ + @Deprecated void storeDocument(Txn transaction, DBBroker broker, XmldbURI name, InputSource source, @Nullable MimeType mimeType) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException; /** @@ -686,7 +690,29 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * Since the process is dependent on the collection configuration, * the collection acquires a write lock during the process. * - * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} + * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} + * + * @param transaction The database transaction + * @param broker The database broker + * @param name The name (without path) of the document + * @param source The source of the content for the new document to store + * @param mediaType The Internet Media Type of the document to store, or null if unknown. + * + * @throws PermissionDeniedException if user has not sufficient rights + * @throws LockException if broker is locked + * @throws IOException in case of I/O errors + * @throws TriggerException in case of trigger error + * @throws EXistException general exception + * @throws SAXException internal SAXException + */ + void storeDocument(Txn transaction, DBBroker broker, XmldbURI name, InputSource source, @Nullable MediaType mediaType) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException; + + /** + * Stores a document. + * Since the process is dependent on the collection configuration, + * the collection acquires a write lock during the process. + * + * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} * * @param transaction The database transaction * @param broker The database broker @@ -706,7 +732,10 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * @throws TriggerException in case of trigger error * @throws EXistException general exception * @throws SAXException internal SAXException + * + * @deprecated Use {@link #storeDocument(Txn, DBBroker, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader)} instead. */ + @Deprecated void storeDocument(Txn transaction, DBBroker broker, XmldbURI name, InputSource source, @Nullable MimeType mimeType, @Nullable Date createdDate, @Nullable Date lastModifiedDate, @Nullable Permission permission, @Nullable DocumentType documentType, @Nullable XMLReader xmlReader) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException; /** @@ -714,7 +743,35 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * Since the process is dependent on the collection configuration, * the collection acquires a write lock during the process. * - * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, Node, MimeType, Collection)} + * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} + * + * @param transaction The database transaction + * @param broker The database broker + * @param name The name (without path) of the document + * @param source The source of the content for the new document to store + * @param mediaType The Internet Media Type of the document to store, or null if unknown. + * If null, application/octet-stream will be used to store a binary document. + * @param createdDate The created date to set for the document, or if null the date is set to 'now' + * @param lastModifiedDate The lastModified date to set for the document, or if null the date is set to the {@code createdDate} + * @param permission A specific permission to set on the document, or null for the default permission + * @param documentType A document type declaration, or null if absent or a binary document is being stored + * @param xmlReader A custom XML Reader (e.g. a HTML to XHTML converting reader), or null to use the default XML reader or if a binary document is being stored + * + * @throws PermissionDeniedException if user has not sufficient rights + * @throws LockException if broker is locked + * @throws IOException in case of I/O errors + * @throws TriggerException in case of trigger error + * @throws EXistException general exception + * @throws SAXException internal SAXException + */ + void storeDocument(Txn transaction, DBBroker broker, XmldbURI name, InputSource source, @Nullable MediaType mediaType, @Nullable Date createdDate, @Nullable Date lastModifiedDate, @Nullable Permission permission, @Nullable DocumentType documentType, @Nullable XMLReader xmlReader) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException; + + /** + * Stores a document. + * Since the process is dependent on the collection configuration, + * the collection acquires a write lock during the process. + * + * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, Node, MediaType, Collection)} * * @param transaction The database transaction * @param broker The database broker @@ -728,7 +785,10 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * @throws TriggerException in case of trigger error * @throws EXistException general exception * @throws SAXException internal SAXException + * + * @deprecated Use {@link #storeDocument(Txn, DBBroker, XmldbURI, Node, MediaType)} instead. */ + @Deprecated void storeDocument(Txn transaction, DBBroker broker, XmldbURI name, Node node, @Nullable MimeType mimeType) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException; /** @@ -736,7 +796,29 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * Since the process is dependent on the collection configuration, * the collection acquires a write lock during the process. * - * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, Node, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} + * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, Node, MediaType, Collection)} + * + * @param transaction The database transaction + * @param broker The database broker + * @param name The name (without path) of the document + * @param node The DOM Node to store as a new document + * @param mediaType The Internet Media Type of the document to store, or null if unknown. + * + * @throws PermissionDeniedException if user has not sufficient rights + * @throws LockException if broker is locked + * @throws IOException in case of I/O errors + * @throws TriggerException in case of trigger error + * @throws EXistException general exception + * @throws SAXException internal SAXException + */ + void storeDocument(Txn transaction, DBBroker broker, XmldbURI name, Node node, @Nullable MediaType mediaType) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException; + + /** + * Stores a document. + * Since the process is dependent on the collection configuration, + * the collection acquires a write lock during the process. + * + * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, Node, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} * * @param transaction The database transaction * @param broker The database broker @@ -756,9 +838,40 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * @throws TriggerException in case of trigger error * @throws EXistException general exception * @throws SAXException internal SAXException + * + * @deprecated Use {@link #storeDocument(Txn, DBBroker, XmldbURI, Node, MediaType, Date, Date, Permission, DocumentType, XMLReader)} instead. */ + @Deprecated void storeDocument(Txn transaction, DBBroker broker, XmldbURI name, Node node, @Nullable MimeType mimeType, @Nullable Date createdDate, @Nullable Date lastModifiedDate, @Nullable Permission permission, @Nullable DocumentType documentType, @Nullable XMLReader xmlReader) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException; + /** + * Stores a document. + * Since the process is dependent on the collection configuration, + * the collection acquires a write lock during the process. + * + * NOTE: This should only be called from {@link NativeBroker#storeDocument(Txn, XmldbURI, Node, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} + * + * @param transaction The database transaction + * @param broker The database broker + * @param name The name (without path) of the document + * @param node The DOM Node to store as a new document + * @param mediaType The Internet Media Type of the document to store, or null if unknown. + * If null, application/octet-stream will be used to store a binary document. + * @param createdDate The created date to set for the document, or if null the date is set to 'now' + * @param lastModifiedDate The lastModified date to set for the document, or if null the date is set to the {@code createdDate} + * @param permission A specific permission to set on the document, or null for the default permission + * @param documentType A document type declaration, or null if absent or a binary document is being stored + * @param xmlReader A custom XML Reader (e.g. a HTML to XHTML converting reader), or null to use the default XML reader or if a binary document is being stored + * + * @throws PermissionDeniedException if user has not sufficient rights + * @throws LockException if broker is locked + * @throws IOException in case of I/O errors + * @throws TriggerException in case of trigger error + * @throws EXistException general exception + * @throws SAXException internal SAXException + */ + void storeDocument(Txn transaction, DBBroker broker, XmldbURI name, Node node, @Nullable MediaType mediaType, @Nullable Date createdDate, @Nullable Date lastModifiedDate, @Nullable Permission permission, @Nullable DocumentType documentType, @Nullable XMLReader xmlReader) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException; + /** * Validates an XML document and prepares it for further storage. * Launches prepare and postValidate triggers. @@ -779,7 +892,7 @@ void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl doc) * @throws EXistException general exception * @throws SAXException internal SAXException * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated IndexInfo validateXMLResource(Txn transaction, DBBroker broker, XmldbURI name, InputSource source) @@ -807,7 +920,7 @@ IndexInfo validateXMLResource(Txn transaction, DBBroker broker, XmldbURI name, I * @throws EXistException general exception * @throws SAXException internal SAXException * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated IndexInfo validateXMLResource(Txn transaction, DBBroker broker, XmldbURI name, InputSource source, XMLReader reader) @@ -833,7 +946,7 @@ IndexInfo validateXMLResource(Txn transaction, DBBroker broker, XmldbURI name, I * @throws EXistException general exception * @throws SAXException internal SAXException * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated IndexInfo validateXMLResource(Txn transaction, DBBroker broker, XmldbURI name, String data) @@ -859,7 +972,7 @@ IndexInfo validateXMLResource(Txn transaction, DBBroker broker, XmldbURI name, S * @throws EXistException general exception * @throws SAXException internal SAXException * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, Node, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, Node, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated IndexInfo validateXMLResource(Txn transaction, DBBroker broker, XmldbURI name, Node node) @@ -882,7 +995,7 @@ IndexInfo validateXMLResource(Txn transaction, DBBroker broker, XmldbURI name, N * @throws EXistException general exception * @throws SAXException internal SAXException * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated void store(Txn transaction, DBBroker broker, IndexInfo info, InputSource source) @@ -906,7 +1019,7 @@ void store(Txn transaction, DBBroker broker, IndexInfo info, InputSource source) * @throws EXistException general exception * @throws SAXException internal SAXException * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated void store(final Txn transaction, final DBBroker broker, final IndexInfo info, final InputSource source, final XMLReader reader) @@ -929,7 +1042,7 @@ void store(final Txn transaction, final DBBroker broker, final IndexInfo info, f * @throws EXistException general exception * @throws SAXException internal SAXException * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated void store(Txn transaction, DBBroker broker, IndexInfo info, String data) @@ -952,7 +1065,7 @@ void store(Txn transaction, DBBroker broker, IndexInfo info, String data) * @throws EXistException general exception * @throws SAXException internal SAXException * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, Node, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, Node, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated void store(Txn transaction, DBBroker broker, IndexInfo info, Node node) @@ -972,7 +1085,7 @@ void store(Txn transaction, DBBroker broker, IndexInfo info, Node node) * @throws IOException in case of I/O errors * @throws TriggerException in case of trigger error * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated BinaryDocument validateBinaryResource(Txn transaction, DBBroker broker, XmldbURI name) @@ -990,7 +1103,7 @@ BinaryDocument validateBinaryResource(Txn transaction, DBBroker broker, XmldbURI * @param broker The database broker * @param name the name (without path) of the document * @param is The content for the document - * @param mimeType The Internet Media Type of the document + * @param mediaType The Internet Media Type of the document * @param size The size in bytes of the document (unused - size is calculated during storage) * @param created The created timestamp of the document * @param modified The modified timestamp of the document @@ -1003,10 +1116,10 @@ BinaryDocument validateBinaryResource(Txn transaction, DBBroker broker, XmldbURI * @throws TriggerException in case of trigger error * @throws EXistException general exception* * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated - BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, InputStream is, String mimeType, + BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, InputStream is, String mediaType, @Deprecated long size, Date created, Date modified) throws EXistException, PermissionDeniedException, LockException, TriggerException, IOException; @@ -1022,7 +1135,7 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @param broker The database broker * @param name the name (without path) of the document * @param is The content for the document - * @param mimeType The Internet Media Type of the document + * @param mediaType The Internet Media Type of the document * @param size The size in bytes of the document (unused - size is calculated during storage) * @param created The created timestamp of the document * @param modified The modified timestamp of the document @@ -1036,10 +1149,10 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @throws TriggerException in case of trigger error * @throws EXistException general exception* * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated - BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, InputStream is, String mimeType, + BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, InputStream is, String mediaType, @Deprecated long size, Date created, Date modified, @Nullable Permission permission) throws EXistException, PermissionDeniedException, LockException, TriggerException, IOException; @@ -1055,7 +1168,7 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @param broker The database broker * @param name the name (without path) of the document * @param data The content for the document - * @param mimeType The Internet Media Type of the document + * @param mediaType The Internet Media Type of the document * * @return The stored Binary Document object * @@ -1068,7 +1181,7 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @deprecated Use {@link #addBinaryResource(Txn, DBBroker, XmldbURI, InputStream, String, long)} */ @Deprecated - BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, byte[] data, String mimeType) + BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, byte[] data, String mediaType) throws EXistException, PermissionDeniedException, LockException, TriggerException, IOException; /** @@ -1083,7 +1196,7 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @param broker The database broker * @param name the name (without path) of the document * @param data The content for the document - * @param mimeType The Internet Media Type of the document + * @param mediaType The Internet Media Type of the document * @param created The created timestamp of the document * @param modified The modified timestamp of the document * @@ -1098,7 +1211,7 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @deprecated Use {@link #addBinaryResource(Txn, DBBroker, BinaryDocument, InputStream, String, long, Date, Date)} */ @Deprecated - BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, byte[] data, String mimeType, + BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, byte[] data, String mediaType, Date created, Date modified) throws EXistException, PermissionDeniedException, LockException, TriggerException, IOException; @@ -1114,7 +1227,7 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @param broker The database broker * @param name the name (without path) of the document * @param is The content for the document - * @param mimeType The Internet Media Type of the document + * @param mediaType The Internet Media Type of the document * @param size The size in bytes of the document (unused - size is calculated during storage) * * @return The stored Binary Document object @@ -1129,7 +1242,7 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name */ @Deprecated BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name, InputStream is, - String mimeType, @Deprecated long size) throws EXistException, PermissionDeniedException, LockException, + String mediaType, @Deprecated long size) throws EXistException, PermissionDeniedException, LockException, TriggerException, IOException; /** @@ -1144,7 +1257,7 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @param broker The database broker * @param blob the binary resource to store the data into * @param is The content for the document - * @param mimeType The Internet Media Type of the document + * @param mediaType The Internet Media Type of the document * @param size The size in bytes of the document (unused - size is calculated during storage) * @param created The created timestamp of the document * @param modified The modified timestamp of the document @@ -1157,11 +1270,11 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, XmldbURI name * @throws TriggerException in case of trigger error * @throws EXistException general exception * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, BinaryDocument blob, InputStream is, - String mimeType, @Deprecated long size, Date created, Date modified) throws EXistException, PermissionDeniedException, + String mediaType, @Deprecated long size, Date created, Date modified) throws EXistException, PermissionDeniedException, LockException, TriggerException, IOException; /** @@ -1176,7 +1289,7 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, BinaryDocumen * @param broker The database broker * @param blob the binary resource to store the data into * @param is The content for the document - * @param mimeType The Internet Media Type of the document + * @param mediaType The Internet Media Type of the document * @param size The size in bytes of the document (unused - size is calculated during storage) * @param created The created timestamp of the document * @param modified The modified timestamp of the document @@ -1192,11 +1305,11 @@ BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, BinaryDocumen * @throws TriggerException in case of trigger error * @throws EXistException general exception * - * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MimeType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. + * @deprecated Use {@link DBBroker#storeDocument(Txn, XmldbURI, InputSource, MediaType, Date, Date, Permission, DocumentType, XMLReader, Collection)} instead. */ @Deprecated BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, BinaryDocument blob, InputStream is, - String mimeType, @Deprecated long size, Date created, Date modified, DBBroker.PreserveType preserve) + String mediaType, @Deprecated long size, Date created, Date modified, DBBroker.PreserveType preserve) throws EXistException, PermissionDeniedException, LockException, TriggerException, IOException; /** diff --git a/exist-core/src/main/java/org/exist/collections/CollectionConfigurationManager.java b/exist-core/src/main/java/org/exist/collections/CollectionConfigurationManager.java index c0f6c21a90..c6de4bf4b0 100644 --- a/exist-core/src/main/java/org/exist/collections/CollectionConfigurationManager.java +++ b/exist-core/src/main/java/org/exist/collections/CollectionConfigurationManager.java @@ -60,7 +60,6 @@ import org.exist.storage.txn.TransactionManager; import org.exist.storage.txn.Txn; import org.exist.util.LockException; -import org.exist.util.MimeType; import org.exist.util.StringInputSource; import org.exist.util.XMLReaderPool; import org.exist.util.sanity.SanityCheck; @@ -69,6 +68,7 @@ import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; +import xyz.elemental.mediatype.MediaType; import java.io.IOException; import java.io.StringReader; @@ -155,7 +155,8 @@ public void addConfiguration(final Txn txn, final DBBroker broker, final Collect broker.saveCollection(txn, confCol); - broker.storeDocument(txn, configurationDocumentName, new StringInputSource(config), MimeType.XML_TYPE, confCol); + final MediaType xmlMediaType = broker.getBrokerPool().getMediaTypeService().getMediaTypeResolver().fromString(MediaType.APPLICATION_XML); + broker.storeDocument(txn, configurationDocumentName, new StringInputSource(config), xmlMediaType, confCol); // broker.sync(Sync.MAJOR_SYNC); } catch (final CollectionConfigurationException e) { diff --git a/exist-core/src/main/java/org/exist/collections/LockedCollection.java b/exist-core/src/main/java/org/exist/collections/LockedCollection.java index 758af4957b..6ab9bf34ce 100644 --- a/exist-core/src/main/java/org/exist/collections/LockedCollection.java +++ b/exist-core/src/main/java/org/exist/collections/LockedCollection.java @@ -66,6 +66,7 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; +import xyz.elemental.mediatype.MediaType; import javax.annotation.Nullable; import java.io.IOException; @@ -386,21 +387,41 @@ public void storeDocument(final Txn transaction, final DBBroker broker, final Xm broker.storeDocument(transaction, name, source, mimeType, collection); } + @Override + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable final MediaType mediaType) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException { + broker.storeDocument(transaction, name, source, mediaType, collection); + } + @Override public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable final MimeType mimeType, @Nullable final Date createdDate, @Nullable final Date lastModifiedDate, @Nullable final Permission permission, @Nullable final DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException { collection.storeDocument(transaction, broker, name, source, mimeType, createdDate, lastModifiedDate, permission, documentType, xmlReader); } + @Override + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable final MediaType mediaType, @Nullable final Date createdDate, @Nullable final Date lastModifiedDate, @Nullable final Permission permission, @Nullable final DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException { + collection.storeDocument(transaction, broker, name, source, mediaType, createdDate, lastModifiedDate, permission, documentType, xmlReader); + } + @Override public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable final MimeType mimeType) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException { broker.storeDocument(transaction, name, node, mimeType, collection); } + @Override + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable final MediaType mediaType) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException { + broker.storeDocument(transaction, name, node, mediaType, collection); + } + @Override public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable final MimeType mimeType, @Nullable final Date createdDate, @Nullable final Date lastModifiedDate, @Nullable final Permission permission, @Nullable final DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException { collection.storeDocument(transaction, broker, name, node, mimeType, createdDate, lastModifiedDate, permission, documentType, xmlReader); } + @Override + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable final MediaType mediaType, @Nullable final Date createdDate, @Nullable final Date lastModifiedDate, @Nullable final Permission permission, @Nullable final DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException { + collection.storeDocument(transaction, broker, name, node, mediaType, createdDate, lastModifiedDate, permission, documentType, xmlReader); + } + @Deprecated @Override public IndexInfo validateXMLResource(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source) throws EXistException, PermissionDeniedException, TriggerException, SAXException, LockException, IOException { diff --git a/exist-core/src/main/java/org/exist/collections/MutableCollection.java b/exist-core/src/main/java/org/exist/collections/MutableCollection.java index 81b51376a9..03eb981dc0 100644 --- a/exist-core/src/main/java/org/exist/collections/MutableCollection.java +++ b/exist-core/src/main/java/org/exist/collections/MutableCollection.java @@ -92,6 +92,8 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.StorageType; import javax.annotation.Nullable; @@ -1124,17 +1126,27 @@ public void removeBinaryResource(final Txn transaction, final DBBroker broker, f } @Override - public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable MimeType mimeType) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable final MimeType mimeType) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { storeDocument(transaction, broker, name, source, mimeType, null, null, null, null, null); } @Override - public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable MimeType mimeType, final @Nullable Date createdDate, final @Nullable Date lastModifiedDate, final @Nullable Permission permission, final @Nullable DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { - if (mimeType == null) { - mimeType = MimeType.BINARY_TYPE; + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable final MediaType mediaType) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + storeDocument(transaction, broker, name, source, mediaType, null, null, null, null, null); + } + + @Override + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable final MimeType mimeType, final @Nullable Date createdDate, final @Nullable Date lastModifiedDate, final @Nullable Permission permission, final @Nullable DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + storeDocument(transaction, broker, name, source, mimeType.toMediaType(), createdDate, lastModifiedDate, permission, documentType, xmlReader); + } + + @Override + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final InputSource source, @Nullable MediaType mediaType, final @Nullable Date createdDate, final @Nullable Date lastModifiedDate, final @Nullable Permission permission, final @Nullable DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + if (mediaType == null) { + mediaType = broker.getBrokerPool().getMediaTypeService().getMediaTypeResolver().forUnknown(); } - if (mimeType.isXMLType()) { + if (mediaType.getStorageType() == StorageType.XML) { // Store XML Document final BiConsumer2E validatorFn = (xmlReader1, validateIndexInfo) -> { @@ -1157,7 +1169,7 @@ public void storeDocument(final Txn transaction, final DBBroker broker, final Xm } }; - storeXmlDocument(transaction, broker, name, mimeType, createdDate, lastModifiedDate, permission, documentType, xmlReader, validatorFn, parserFn); + storeXmlDocument(transaction, broker, name, mediaType, createdDate, lastModifiedDate, permission, documentType, xmlReader, validatorFn, parserFn); } else { // Store Binary Document @@ -1165,23 +1177,33 @@ public void storeDocument(final Txn transaction, final DBBroker broker, final Xm if (is == null) { throw new IOException("storeDocument received a null InputStream when trying to store a Binary Document"); } - addBinaryResource(transaction, broker, name, is, mimeType.getName(), -1, createdDate, lastModifiedDate, permission); + addBinaryResource(transaction, broker, name, is, mediaType.getIdentifier(), -1, createdDate, lastModifiedDate, permission); } } } @Override - public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable MimeType mimeType) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable final MimeType mimeType) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { storeDocument(transaction, broker, name, node, mimeType, null, null, null, null, null); } @Override - public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable MimeType mimeType, final @Nullable Date createdDate, final @Nullable Date lastModifiedDate, final @Nullable Permission permission, final @Nullable DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { - if (mimeType == null) { - mimeType = MimeType.BINARY_TYPE; + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable final MediaType mediaType) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + storeDocument(transaction, broker, name, node, mediaType, null, null, null, null, null); + } + + @Override + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable final MimeType mimeType, final @Nullable Date createdDate, final @Nullable Date lastModifiedDate, final @Nullable Permission permission, final @Nullable DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + storeDocument(transaction, broker, name, node, mimeType.toMediaType(), createdDate, lastModifiedDate, permission, documentType, xmlReader); + } + + @Override + public void storeDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final Node node, @Nullable MediaType mediaType, final @Nullable Date createdDate, final @Nullable Date lastModifiedDate, final @Nullable Permission permission, final @Nullable DocumentType documentType, @Nullable final XMLReader xmlReader) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + if (mediaType == null) { + mediaType = broker.getBrokerPool().getMediaTypeService().getMediaTypeResolver().forUnknown(); } - if (mimeType.isXMLType()) { + if (mediaType.getStorageType() == StorageType.XML) { // Store XML Document final BiConsumer2E validatorFn = (xmlReader1, validateIndexInfo) -> { validateIndexInfo.setReader(xmlReader1, null); @@ -1194,14 +1216,14 @@ public void storeDocument(final Txn transaction, final DBBroker broker, final Xm storeIndexInfo.getDOMStreamer().serialize(node, true); }; - storeXmlDocument(transaction, broker, name, mimeType, createdDate, lastModifiedDate, permission, documentType, xmlReader, validatorFn, parserFn); + storeXmlDocument(transaction, broker, name, mediaType, createdDate, lastModifiedDate, permission, documentType, xmlReader, validatorFn, parserFn); } else { throw new EXistException("Cannot store DOM Node as a Binary Document to URI: " + getURI().append(name)); } } - private void storeXmlDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final MimeType mimeType, final @Nullable Date createdDate, final @Nullable Date lastModifiedDate, final @Nullable Permission permission, final @Nullable DocumentType documentType, @Nullable final XMLReader xmlReader, final BiConsumer2E validatorFn, final BiConsumer2E parserFn) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { + private void storeXmlDocument(final Txn transaction, final DBBroker broker, final XmldbURI name, final MediaType mediaType, final @Nullable Date createdDate, final @Nullable Date lastModifiedDate, final @Nullable Permission permission, final @Nullable DocumentType documentType, @Nullable final XMLReader xmlReader, final BiConsumer2E validatorFn, final BiConsumer2E parserFn) throws EXistException, PermissionDeniedException, SAXException, LockException, IOException { final CollectionConfiguration colconf = getConfiguration(broker); // borrow a default XML Reader if needed @@ -1220,7 +1242,7 @@ private void storeXmlDocument(final Txn transaction, final DBBroker broker, fina // Phase 2 of 3 - Set the metadata for the document final DocumentImpl document = indexInfo.getDocument(); - document.setMimeType(mimeType.getName()); + document.setMediaType(mediaType.getIdentifier()); if (createdDate != null) { document.setCreated(createdDate.getTime()); if (lastModifiedDate == null) { @@ -1832,7 +1854,7 @@ public BinaryDocument addBinaryResource(final Txn transaction, final DBBroker br } private BinaryDocument addBinaryResource(final Database db, final Txn transaction, final DBBroker broker, - final BinaryDocument blob, final InputStream is, final String mimeType, @Deprecated final long size, final Date created, + final BinaryDocument blob, final InputStream is, final String mediaType, @Deprecated final long size, final Date created, final Date modified, @Nullable final Permission permission, final DBBroker.PreserveType preserve, final DocumentImpl oldDoc, final ManagedCollectionLock collectionLock) throws EXistException, PermissionDeniedException, LockException, TriggerException, IOException { @@ -1846,7 +1868,7 @@ private BinaryDocument addBinaryResource(final Database db, final Txn transactio if (!broker.preserveOnCopy(preserve)) { blob.copyOf(broker, blob, oldDoc); } - blob.setMimeType(mimeType == null ? MimeType.BINARY_TYPE.getName() : mimeType); + blob.setMediaType(mediaType != null ? mediaType : MediaType.APPLICATION_OCTET_STREAM); if (created != null) { blob.setCreated(created.getTime()); } diff --git a/exist-core/src/main/java/org/exist/collections/triggers/XQueryStartupTrigger.java b/exist-core/src/main/java/org/exist/collections/triggers/XQueryStartupTrigger.java index 66b826441f..5c7d909028 100644 --- a/exist-core/src/main/java/org/exist/collections/triggers/XQueryStartupTrigger.java +++ b/exist-core/src/main/java/org/exist/collections/triggers/XQueryStartupTrigger.java @@ -67,6 +67,7 @@ import org.exist.xquery.XQuery; import org.exist.xquery.XQueryContext; import org.exist.xquery.value.Sequence; +import xyz.elemental.mediatype.MediaType; import static org.exist.util.StringUtil.endsWith; import static org.exist.util.StringUtil.substringBeforeLast; @@ -104,7 +105,7 @@ public class XQueryStartupTrigger implements StartupTrigger { private static final String XQUERY = "xquery"; private static final String AUTOSTART_COLLECTION = "/db/system/autostart"; private static final String[] XQUERY_EXTENSIONS = {".xq", ".xquery", ".xqy"}; - private static final String REQUIRED_MIMETYPE = "application/xquery"; + private static final String REQUIRED_MIMETYPE = MediaType.APPLICATION_XQUERY; @Override public void execute(DBBroker broker, final Txn transaction, Map> params) { @@ -208,7 +209,7 @@ private boolean isPermissionsOK(final DocumentImpl document) { return (perms.getOwner().hasDbaRole() && perms.getGroup().getName().equals(SecurityManager.DBA_GROUP) && perms.getMode() == Permission.DEFAULT_SYSTEM_SECURITY_COLLECTION_PERM - && document.getMimeType().equals(REQUIRED_MIMETYPE)); + && document.getMediaType().equals(REQUIRED_MIMETYPE)); } diff --git a/exist-core/src/main/java/org/exist/config/Configurator.java b/exist-core/src/main/java/org/exist/config/Configurator.java index 56477b5d33..ada04750a9 100644 --- a/exist-core/src/main/java/org/exist/config/Configurator.java +++ b/exist-core/src/main/java/org/exist/config/Configurator.java @@ -93,7 +93,6 @@ import org.exist.storage.txn.Txn; import org.exist.util.ExistSAXParserFactory; import org.exist.util.LockException; -import org.exist.util.MimeType; import com.evolvedbinary.j8fu.function.ConsumerE; import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; import org.exist.util.StringInputSource; @@ -105,6 +104,7 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; +import xyz.elemental.mediatype.MediaType; import static java.lang.invoke.MethodType.methodType; import static javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING; @@ -1334,7 +1334,8 @@ public static DocumentImpl save(final Configurable instance, final DBBroker brok systemResourcePermission.setGroup(systemSubject.getDefaultGroup()); systemResourcePermission.setMode(Permission.DEFAULT_SYSTEM_RESOURCE_PERM); - broker.storeDocument(txn, uri, new StringInputSource(data), MimeType.XML_TYPE, null, null, systemResourcePermission, null, null, collection); + final MediaType xmlMediaType = broker.getBrokerPool().getMediaTypeService().getMediaTypeResolver().fromString(MediaType.APPLICATION_XML); + broker.storeDocument(txn, uri, new StringInputSource(data), xmlMediaType, null, null, systemResourcePermission, null, null, collection); broker.saveCollection(txn, collection); if (!txnInProgress) { diff --git a/exist-core/src/main/java/org/exist/dom/persistent/BinaryDocument.java b/exist-core/src/main/java/org/exist/dom/persistent/BinaryDocument.java index be14a09b74..36583072a0 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/BinaryDocument.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/BinaryDocument.java @@ -205,7 +205,7 @@ public void write(final VariableByteOutput ostream) throws IOException { // document attributes ostream.writeLong(created); ostream.writeLong(lastModified); - ostream.writeInt(pool.getSymbols().getMimeTypeId(mimeType)); + ostream.writeInt(pool.getSymbols().getMimeTypeId(mediaType)); ostream.writeInt(pageCount); ostream.writeInt(userLock); if (docType != null) { diff --git a/exist-core/src/main/java/org/exist/dom/persistent/DocumentImpl.java b/exist-core/src/main/java/org/exist/dom/persistent/DocumentImpl.java index b0a8f0405f..e5a0f919b8 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/DocumentImpl.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/DocumentImpl.java @@ -63,7 +63,6 @@ import org.exist.storage.lock.EnsureContainerLocked; import org.exist.storage.lock.EnsureLocked; import org.exist.storage.txn.Txn; -import org.exist.util.MimeType; import org.exist.util.XMLString; import org.exist.xmldb.XmldbURI; import org.exist.xquery.Constants; @@ -71,6 +70,7 @@ import org.exist.xquery.NameTest; import org.exist.xquery.value.Type; import org.w3c.dom.*; +import xyz.elemental.mediatype.MediaType; import javax.annotation.Nullable; import javax.xml.XMLConstants; @@ -145,7 +145,7 @@ public class DocumentImpl extends NodeImpl implements Resource, Do /** * The mimeType of the document */ - protected String mimeType = MimeType.XML_TYPE.getName(); + protected String mediaType = MediaType.APPLICATION_XML; /** * The creation time of this document @@ -272,7 +272,7 @@ public DocumentImpl(final Expression expression, final int docId, final Document * @param childAddress the addresses of the child nodes * @param created the created time of the document * @param lastModified the last modified time of the document, or null to use the {@code created} time - * @param mimeType the media type of the document, or null for application/xml + * @param mediaType the media type of the document, or null for application/xml * @param docType the document type, or null * * @deprecated Use {@link DocumentImpl(BrokerPool, Collection, int, XmldbURI, Permission, int, long[], long, Long, String, XMLDeclarationImpl, DocumentType)} @@ -281,9 +281,9 @@ public DocumentImpl(final Expression expression, final int docId, final Document public DocumentImpl(final BrokerPool pool, @Nullable final Collection collection, final int docId, final XmldbURI fileURI, final Permission permissions, final int children, @Nullable final long[] childAddress, - final long created, @Nullable final Long lastModified, @Nullable final String mimeType, + final long created, @Nullable final Long lastModified, @Nullable final String mediaType, @Nullable final DocumentType docType) { - this(null, pool, collection, docId, fileURI, permissions, children, childAddress, created, lastModified, mimeType, null, docType); + this(null, pool, collection, docId, fileURI, permissions, children, childAddress, created, lastModified, mediaType, null, docType); } /** @@ -298,16 +298,16 @@ public DocumentImpl(final BrokerPool pool, @Nullable final Collection collection * @param childAddress the addresses of the child nodes * @param created the created time of the document * @param lastModified the last modified time of the document, or null to use the {@code created} time - * @param mimeType the media type of the document, or null for application/xml + * @param mediaType the media type of the document, or null for application/xml * @param xmlDecl the XML Declaration, or null * @param docType the document type, or null */ public DocumentImpl(final BrokerPool pool, @Nullable final Collection collection, final int docId, final XmldbURI fileURI, final Permission permissions, final int children, @Nullable final long[] childAddress, - final long created, @Nullable final Long lastModified, @Nullable final String mimeType, + final long created, @Nullable final Long lastModified, @Nullable final String mediaType, @Nullable final XMLDeclarationImpl xmlDecl, @Nullable final DocumentType docType) { - this(null, pool, collection, docId, fileURI, permissions, children, childAddress, created, lastModified, mimeType, xmlDecl, docType); + this(null, pool, collection, docId, fileURI, permissions, children, childAddress, created, lastModified, mediaType, xmlDecl, docType); } /** @@ -323,7 +323,7 @@ public DocumentImpl(final BrokerPool pool, @Nullable final Collection collection * @param childAddress the addresses of the child nodes * @param created the created time of the document * @param lastModified the last modified time of the document, or null to use the {@code created} time - * @param mimeType the media type of the document, or null for application/xml + * @param mediaType the media type of the document, or null for application/xml * @param docType the document type, or null * * @deprecated Use {@link DocumentImpl(Expression, BrokerPool, Collection, int ,XmldbURI, Permission, int, long[], long, Long, String, XMLDeclarationImpl, DocumentType)} @@ -332,9 +332,9 @@ public DocumentImpl(final BrokerPool pool, @Nullable final Collection collection public DocumentImpl(final Expression expression, final BrokerPool pool, @Nullable final Collection collection, final int docId, final XmldbURI fileURI, final Permission permissions, final int children, @Nullable final long[] childAddress, - final long created, @Nullable final Long lastModified, @Nullable final String mimeType, + final long created, @Nullable final Long lastModified, @Nullable final String mediaType, @Nullable final DocumentType docType) { - this(expression, pool, collection, docId, fileURI, permissions, children, childAddress, created, lastModified, mimeType, null, docType); + this(expression, pool, collection, docId, fileURI, permissions, children, childAddress, created, lastModified, mediaType, null, docType); } /** @@ -350,14 +350,14 @@ public DocumentImpl(final Expression expression, final BrokerPool pool, @Nullabl * @param childAddress the addresses of the child nodes * @param created the created time of the document * @param lastModified the last modified time of the document, or null to use the {@code created} time - * @param mimeType the media type of the document, or null for application/xml + * @param mediaType the media type of the document, or null for application/xml * @param xmlDecl the XML Declaration, or null * @param docType the document type, or null */ public DocumentImpl(final Expression expression, final BrokerPool pool, @Nullable final Collection collection, final int docId, final XmldbURI fileURI, final Permission permissions, final int children, @Nullable final long[] childAddress, - final long created, @Nullable final Long lastModified, @Nullable final String mimeType, + final long created, @Nullable final Long lastModified, @Nullable final String mediaType, @Nullable final XMLDeclarationImpl xmlDecl, @Nullable final DocumentType docType) { super(expression); this.pool = pool; @@ -372,7 +372,7 @@ public DocumentImpl(final Expression expression, final BrokerPool pool, @Nullabl this.childAddress = childAddress; this.created = created; this.lastModified = lastModified == null ? created : lastModified; - this.mimeType = mimeType == null ? MimeType.XML_TYPE.getName() : mimeType; + this.mediaType = mediaType != null ? mediaType : MediaType.APPLICATION_XML; this.xmlDecl = xmlDecl; this.docType = docType; @@ -489,12 +489,42 @@ public void setLastModified(final long lastModified) { this.lastModified = lastModified; } + /** + * Get the Internet Media Type of the document. + * + * @return the Internet Media Type of the document. + * + * @deprecated Use {@link #getMediaType()} instead. + */ + @Deprecated public String getMimeType() { - return mimeType; + return mediaType; } + /** + * Set the Internet Media Type of the document. + * + * @deprecated Use {@link #setMediaType(String)} instead. + */ + @Deprecated public void setMimeType(final String mimeType) { - this.mimeType = mimeType; + this.mediaType = mimeType; + } + + /** + * Get the Internet Media Type of the document. + * + * @return the Internet Media Type of the document. + */ + public String getMediaType() { + return mediaType; + } + + /** + * Set the Internet Media Type of the document. + */ + public void setMediaType(final String mediaType) { + this.mediaType = mediaType; } /** @@ -683,7 +713,7 @@ private void copyOf(final DBBroker broker, @EnsureLocked(mode=READ_LOCK) final D this.created = other.created; this.lastModified = other.lastModified; - this.mimeType = other.mimeType; + this.mediaType = other.mediaType; this.docType = other.docType; final long timestamp = System.currentTimeMillis(); @@ -888,7 +918,7 @@ public void write(final VariableByteOutput ostream) throws IOException { void writeDocumentAttributes(final SymbolTable symbolTable, final VariableByteOutput ostream) throws IOException { ostream.writeLong(created); ostream.writeLong(lastModified); - ostream.writeInt(symbolTable.getMimeTypeId(mimeType)); + ostream.writeInt(symbolTable.getMimeTypeId(mediaType)); ostream.writeInt(pageCount); ostream.writeInt(userLock); if (xmlDecl != null) { diff --git a/exist-core/src/main/java/org/exist/dom/persistent/DocumentMetadata.java b/exist-core/src/main/java/org/exist/dom/persistent/DocumentMetadata.java index 38fbe79c54..6b6252f1b3 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/DocumentMetadata.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/DocumentMetadata.java @@ -95,12 +95,12 @@ public void setLastModified(final long lastModified) { @Deprecated public String getMimeType() { - return doc.getMimeType(); + return doc.getMediaType(); } @Deprecated public void setMimeType(final String mimeType) { - doc.setMimeType(mimeType); + doc.setMediaType(mimeType); } @Deprecated @@ -133,7 +133,7 @@ public void read(final SymbolTable symbolTable, final VariableByteInput istream) final long created = istream.readLong(); final long lastModified = istream.readLong(); final int mimeTypeSymbolsIndex = istream.readInt(); - final String mimeType = symbolTable.getMimeType(mimeTypeSymbolsIndex); + final String mediaType = symbolTable.getMimeType(mimeTypeSymbolsIndex); final int pageCount = istream.readInt(); final int userLock = istream.readInt(); final DocumentTypeImpl docType; @@ -151,7 +151,7 @@ public void read(final SymbolTable symbolTable, final VariableByteInput istream) doc.setCreated(created); doc.setLastModified(lastModified); - doc.setMimeType(mimeType); + doc.setMediaType(mediaType); doc.setPageCount(pageCount); doc.setUserLock(userLock); doc.setDocType(docType); diff --git a/exist-core/src/main/java/org/exist/http/RESTServer.java b/exist-core/src/main/java/org/exist/http/RESTServer.java index 84430b4531..8254b7743d 100644 --- a/exist-core/src/main/java/org/exist/http/RESTServer.java +++ b/exist-core/src/main/java/org/exist/http/RESTServer.java @@ -108,6 +108,8 @@ import org.xml.sax.XMLReader; import org.xml.sax.helpers.AttributesImpl; import org.xml.sax.helpers.XMLFilterImpl; +import xyz.elemental.mediatype.MediaType; +import xyz.elemental.mediatype.MediaTypeResolver; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -147,7 +149,7 @@ public class RESTServer { static { defaultProperties.setProperty(OutputKeys.INDENT, "yes"); - defaultProperties.setProperty(OutputKeys.MEDIA_TYPE, MimeType.XML_TYPE.getName()); + defaultProperties.setProperty(OutputKeys.MEDIA_TYPE, MediaType.APPLICATION_XML); defaultProperties.setProperty(EXistOutputKeys.EXPAND_XINCLUDES, "yes"); defaultProperties.setProperty(EXistOutputKeys.HIGHLIGHT_MATCHES, "elements"); defaultProperties.setProperty(EXistOutputKeys.PROCESS_XSL_PI, "yes"); @@ -158,8 +160,7 @@ public class RESTServer { defaultOutputKeysProperties.setProperty(EXistOutputKeys.OMIT_ORIGINAL_XML_DECLARATION, "no"); defaultOutputKeysProperties.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); defaultOutputKeysProperties.setProperty(OutputKeys.INDENT, "yes"); - defaultOutputKeysProperties.setProperty(OutputKeys.MEDIA_TYPE, - MimeType.XML_TYPE.getName()); + defaultOutputKeysProperties.setProperty(OutputKeys.MEDIA_TYPE, MediaType.APPLICATION_XML); } private final static String QUERY_ERROR_HEAD = "" + "" + "Query Error" + "