From 503258eebcd0a8923de51b9a4e2d0eb1f7a804fc Mon Sep 17 00:00:00 2001 From: David Walluck Date: Sun, 23 Mar 2025 09:02:43 -0400 Subject: [PATCH 01/11] GH-188: Implement package type providers This uses the Java Service Provider Interface via `ServiceLoader` to register new types, where each type gets its own class. --- .../com/github/packageurl/PackageURL.java | 68 +++--- .../packageurl/ValidationException.java | 4 + .../type/ApkPackageTypeProvider.java | 24 ++ .../type/BitbucketPackageTypeProvider.java | 24 ++ .../type/BitnamiPackageTypeProvider.java | 24 ++ .../type/CocoapodsPackageTypeProvider.java | 48 ++++ .../type/ComposerPackageTypeProvider.java | 24 ++ .../type/ConanPackageTypeProvider.java | 47 ++++ .../type/CpanPackageTypeProvider.java | 45 ++++ .../type/CranPackageTypeProvider.java | 43 ++++ .../type/DebPackageTypeProvider.java | 24 ++ .../type/GenericPackageTypeProvider.java | 24 ++ .../type/GithubPackageTypeProvider.java | 24 ++ .../type/GolangPackageTypeProvider.java | 24 ++ .../type/HackagePackageTypeProvider.java | 43 ++++ .../type/HexPackageTypeProvider.java | 24 ++ .../type/HuggingfacePackageTypeProvider.java | 24 ++ ...caseNameAndVersionPackageTypeProvider.java | 48 ++++ .../LowercaseNamePackageTypeProvider.java | 42 ++++ ...LowercaseNamespaceAndNameTypeProvider.java | 48 ++++ ...LowercaseNamespacePackageTypeProvider.java | 43 ++++ .../LowercaseVersionPackageTypeProvider.java | 43 ++++ .../type/LuarocksPackageTypeProvider.java | 24 ++ .../type/MavenPackageTypeProvider.java | 43 ++++ .../type/MlflowPackageTypeProvider.java | 83 +++++++ .../type/OciPackageTypeProvider.java | 62 ++++++ .../packageurl/type/PackageTypeFactory.java | 209 ++++++++++++++++++ .../packageurl/type/PackageTypeProvider.java | 71 ++++++ .../type/PubPackageTypeProvider.java | 24 ++ .../type/PypiPackageTypeProvider.java | 43 ++++ .../type/QpkgPackageTypeProvider.java | 24 ++ .../type/RpmPackageTypeProvider.java | 24 ++ .../type/SwiftPackageTypeProvider.java | 47 ++++ .../github/packageurl/type/package-info.java | 29 +++ ...github.packageurl.type.PackageTypeProvider | 24 ++ .../com/github/packageurl/PackageURLTest.java | 111 +++++++++- 36 files changed, 1547 insertions(+), 33 deletions(-) create mode 100644 src/main/java/com/github/packageurl/type/ApkPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/BitbucketPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/BitnamiPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/CocoapodsPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/ComposerPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/ConanPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/CpanPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/CranPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/DebPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/GenericPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/GithubPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/GolangPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/HackagePackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/HexPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/HuggingfacePackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/LowercaseNameAndVersionPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/LowercaseNamePackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/LowercaseNamespaceAndNameTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/LowercaseNamespacePackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/LowercaseVersionPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/LuarocksPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/MavenPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/MlflowPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/OciPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/PackageTypeFactory.java create mode 100644 src/main/java/com/github/packageurl/type/PackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/PubPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/PypiPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/QpkgPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/RpmPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/SwiftPackageTypeProvider.java create mode 100644 src/main/java/com/github/packageurl/type/package-info.java create mode 100644 src/main/resources/META-INF/services/com.github.packageurl.type.PackageTypeProvider diff --git a/src/main/java/com/github/packageurl/PackageURL.java b/src/main/java/com/github/packageurl/PackageURL.java index 5745c3d9..9d5a95e9 100644 --- a/src/main/java/com/github/packageurl/PackageURL.java +++ b/src/main/java/com/github/packageurl/PackageURL.java @@ -23,6 +23,7 @@ import static java.util.Objects.requireNonNull; +import com.github.packageurl.type.PackageTypeFactory; import java.io.Serializable; import java.net.URI; import java.net.URISyntaxException; @@ -77,34 +78,34 @@ public final class PackageURL implements Serializable { private final String type; /** - * The name prefix such as a Maven groupid, a Docker image owner, a GitHub user or organization. + * The name prefix such as a Maven groupId, a Docker image owner, a GitHub user or organization. * Optional and type-specific. */ - private final @Nullable String namespace; + private @Nullable String namespace; /** * The name of the package. * Required. */ - private final String name; + private String name; /** * The version of the package. * Optional. */ - private final @Nullable String version; + private @Nullable String version; /** * Extra qualifying data for a package such as an OS, architecture, a distro, etc. * Optional and type-specific. */ - private final @Nullable Map qualifiers; + private @Nullable Map qualifiers; /** * Extra subpath within a package, relative to the package root. * Optional. */ - private final @Nullable String subpath; + private @Nullable String subpath; /** * Constructs a new PackageURL object by parsing the specified string. @@ -194,7 +195,6 @@ public PackageURL(final String purl) throws MalformedPackageURLException { remainder = remainder.substring(0, index); this.namespace = validateNamespace(this.type, parsePath(remainder.substring(start), false)); } - verifyTypeConstraints(this.type, this.namespace, this.name); } catch (URISyntaxException e) { throw new MalformedPackageURLException("Invalid purl: " + e.getMessage(), e); } @@ -264,7 +264,6 @@ public PackageURL( this.version = validateVersion(this.type, version); this.qualifiers = parseQualifiers(qualifiers); this.subpath = validateSubpath(subpath); - verifyTypeConstraints(this.type, this.namespace, this.name); } /** @@ -360,11 +359,11 @@ private static String validateType(final String value) throws MalformedPackageUR return value; } - private static boolean isValidCharForType(int c) { + public static boolean isValidCharForType(int c) { return (isAlphaNumeric(c) || c == '.' || c == '+' || c == '-'); } - private static boolean isValidCharForKey(int c) { + public static boolean isValidCharForKey(int c) { return (isAlphaNumeric(c) || c == '.' || c == '_' || c == '-'); } @@ -538,6 +537,12 @@ private static void validateValue(final String key, final @Nullable String value } } + public PackageURL normalize() throws MalformedPackageURLException { + PackageTypeFactory.getInstance().validateComponents(type, namespace, name, version, qualifiers, subpath); + return PackageTypeFactory.getInstance() + .normalizeComponents(type, namespace, name, version, qualifiers, subpath); + } + /** * Returns the canonicalized representation of the purl. * @@ -565,6 +570,17 @@ public String canonicalize() { * @since 1.3.2 */ private String canonicalize(boolean coordinatesOnly) { + try { + PackageURL packageURL = normalize(); + namespace = packageURL.getNamespace(); + name = packageURL.getName(); + version = packageURL.getVersion(); + qualifiers = packageURL.getQualifiers(); + subpath = packageURL.getSubpath(); + } catch (MalformedPackageURLException e) { + throw new ValidationException("Normalization failed", e); + } + final StringBuilder purl = new StringBuilder(); purl.append(SCHEME_PART).append(type).append('/'); if (namespace != null) { @@ -577,7 +593,7 @@ private String canonicalize(boolean coordinatesOnly) { } if (!coordinatesOnly) { - if (qualifiers != null) { + if (!qualifiers.isEmpty()) { purl.append('?'); Set> entries = qualifiers.entrySet(); boolean separator = false; @@ -606,7 +622,7 @@ private static boolean shouldEncode(int c) { return !isUnreserved(c); } - private static boolean isAlpha(int c) { + public static boolean isAlpha(int c) { return (isLowerCase(c) || isUpperCase(c)); } @@ -614,10 +630,14 @@ private static boolean isDigit(int c) { return (c >= '0' && c <= '9'); } - private static boolean isAlphaNumeric(int c) { + public static boolean isAlphaNumeric(int c) { return (isDigit(c) || isAlpha(c)); } + public static boolean isWhitespace(int c) { + return (c == ' ' || c == '\t' || c == '\r' || c == '\n'); + } + private static boolean isUpperCase(int c) { return (c >= 'A' && c <= 'Z'); } @@ -642,7 +662,7 @@ private static int toLowerCase(int c) { return isUpperCase(c) ? (c ^ 0x20) : c; } - static String toLowerCase(String s) { + public static String toLowerCase(String s) { int pos = indexOfFirstUpperCaseChar(s); if (pos == -1) { @@ -770,22 +790,6 @@ static String percentEncode(final String source) { return changed ? new String(buffer.array(), 0, buffer.position(), StandardCharsets.UTF_8) : source; } - /** - * Some purl types may have specific constraints. This method attempts to verify them. - * @param type the purl type - * @param namespace the purl namespace - * @throws MalformedPackageURLException if constraints are not met - */ - private static void verifyTypeConstraints(String type, @Nullable String namespace, @Nullable String name) - throws MalformedPackageURLException { - if (StandardTypes.MAVEN.equals(type)) { - if (isEmpty(namespace) || isEmpty(name)) { - throw new MalformedPackageURLException( - "The PackageURL specified is invalid. Maven requires both a namespace and name."); - } - } - } - private static @Nullable Map parseQualifiers(final @Nullable Map qualifiers) throws MalformedPackageURLException { if (qualifiers == null || qualifiers.isEmpty()) { @@ -1107,7 +1111,7 @@ public static final class StandardTypes { * @deprecated use {@link #DEB} instead */ @Deprecated - public static final String DEBIAN = "deb"; + public static final String DEBIAN = DEB; /** * Nixos packages. * @@ -1115,7 +1119,7 @@ public static final class StandardTypes { * @deprecated use {@link #NIX} instead */ @Deprecated - public static final String NIXPKGS = "nix"; + public static final String NIXPKGS = NIX; private StandardTypes() {} } diff --git a/src/main/java/com/github/packageurl/ValidationException.java b/src/main/java/com/github/packageurl/ValidationException.java index 4cb3ee93..c3db6ad1 100644 --- a/src/main/java/com/github/packageurl/ValidationException.java +++ b/src/main/java/com/github/packageurl/ValidationException.java @@ -38,4 +38,8 @@ class ValidationException extends RuntimeException { ValidationException(String msg) { super(msg); } + + ValidationException(String msg, Throwable cause) { + super(msg, cause); + } } diff --git a/src/main/java/com/github/packageurl/type/ApkPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/ApkPackageTypeProvider.java new file mode 100644 index 00000000..48f3e5be --- /dev/null +++ b/src/main/java/com/github/packageurl/type/ApkPackageTypeProvider.java @@ -0,0 +1,24 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +public class ApkPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/BitbucketPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/BitbucketPackageTypeProvider.java new file mode 100644 index 00000000..d2113c99 --- /dev/null +++ b/src/main/java/com/github/packageurl/type/BitbucketPackageTypeProvider.java @@ -0,0 +1,24 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +public class BitbucketPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/BitnamiPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/BitnamiPackageTypeProvider.java new file mode 100644 index 00000000..40b12d18 --- /dev/null +++ b/src/main/java/com/github/packageurl/type/BitnamiPackageTypeProvider.java @@ -0,0 +1,24 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +public class BitnamiPackageTypeProvider extends LowercaseNamespacePackageTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/CocoapodsPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/CocoapodsPackageTypeProvider.java new file mode 100644 index 00000000..33155afe --- /dev/null +++ b/src/main/java/com/github/packageurl/type/CocoapodsPackageTypeProvider.java @@ -0,0 +1,48 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import com.github.packageurl.PackageURL; +import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class CocoapodsPackageTypeProvider implements PackageTypeProvider { + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + if (namespace != null && !namespace.isEmpty()) { + throw new MalformedPackageURLException("invalid cocoapods purl cannot have a namespace"); + } + + if (name.chars().anyMatch(PackageURL::isWhitespace) || name.startsWith(".") || name.contains("+")) { + throw new MalformedPackageURLException("invalid cocoapods purl invalid name"); + } + } +} diff --git a/src/main/java/com/github/packageurl/type/ComposerPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/ComposerPackageTypeProvider.java new file mode 100644 index 00000000..3e6dc2cb --- /dev/null +++ b/src/main/java/com/github/packageurl/type/ComposerPackageTypeProvider.java @@ -0,0 +1,24 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +public class ComposerPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/ConanPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/ConanPackageTypeProvider.java new file mode 100644 index 00000000..d99533cf --- /dev/null +++ b/src/main/java/com/github/packageurl/type/ConanPackageTypeProvider.java @@ -0,0 +1,47 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class ConanPackageTypeProvider implements PackageTypeProvider { + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + boolean hasChannel = (qualifiers != null && !qualifiers.isEmpty()); + + if ((namespace != null && !namespace.isEmpty()) && !hasChannel) { + throw new MalformedPackageURLException("invalid conan purl only namespace"); + } else if ((namespace == null || namespace.isEmpty()) && hasChannel) { + throw new MalformedPackageURLException("invalid conan purl only channel qualifier"); + } + } +} diff --git a/src/main/java/com/github/packageurl/type/CpanPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/CpanPackageTypeProvider.java new file mode 100644 index 00000000..c915cc04 --- /dev/null +++ b/src/main/java/com/github/packageurl/type/CpanPackageTypeProvider.java @@ -0,0 +1,45 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class CpanPackageTypeProvider implements PackageTypeProvider { + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + if ((namespace == null || namespace.isEmpty()) && name.indexOf('-') != -1) { + throw new MalformedPackageURLException("cpan module name like distribution name"); + } else if ((namespace != null && !namespace.isEmpty()) && name.contains("::")) { + throw new MalformedPackageURLException("cpan distribution name like module name"); + } + } +} diff --git a/src/main/java/com/github/packageurl/type/CranPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/CranPackageTypeProvider.java new file mode 100644 index 00000000..7da94c7f --- /dev/null +++ b/src/main/java/com/github/packageurl/type/CranPackageTypeProvider.java @@ -0,0 +1,43 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class CranPackageTypeProvider implements PackageTypeProvider { + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + if (version == null || version.isEmpty()) { + throw new MalformedPackageURLException("invalid cran purl without version"); + } + } +} diff --git a/src/main/java/com/github/packageurl/type/DebPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/DebPackageTypeProvider.java new file mode 100644 index 00000000..a9e909d8 --- /dev/null +++ b/src/main/java/com/github/packageurl/type/DebPackageTypeProvider.java @@ -0,0 +1,24 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +public class DebPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/GenericPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/GenericPackageTypeProvider.java new file mode 100644 index 00000000..9921ad13 --- /dev/null +++ b/src/main/java/com/github/packageurl/type/GenericPackageTypeProvider.java @@ -0,0 +1,24 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +public class GenericPackageTypeProvider implements PackageTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/GithubPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/GithubPackageTypeProvider.java new file mode 100644 index 00000000..37f3d205 --- /dev/null +++ b/src/main/java/com/github/packageurl/type/GithubPackageTypeProvider.java @@ -0,0 +1,24 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +public class GithubPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/GolangPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/GolangPackageTypeProvider.java new file mode 100644 index 00000000..2476ca84 --- /dev/null +++ b/src/main/java/com/github/packageurl/type/GolangPackageTypeProvider.java @@ -0,0 +1,24 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +public class GolangPackageTypeProvider extends LowercaseNamespacePackageTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/HackagePackageTypeProvider.java b/src/main/java/com/github/packageurl/type/HackagePackageTypeProvider.java new file mode 100644 index 00000000..2229d06e --- /dev/null +++ b/src/main/java/com/github/packageurl/type/HackagePackageTypeProvider.java @@ -0,0 +1,43 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class HackagePackageTypeProvider implements PackageTypeProvider { + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + if (version == null || version.isEmpty()) { + throw new MalformedPackageURLException("name and version are always required"); + } + } +} diff --git a/src/main/java/com/github/packageurl/type/HexPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/HexPackageTypeProvider.java new file mode 100644 index 00000000..cd502ac1 --- /dev/null +++ b/src/main/java/com/github/packageurl/type/HexPackageTypeProvider.java @@ -0,0 +1,24 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +public class HexPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/HuggingfacePackageTypeProvider.java b/src/main/java/com/github/packageurl/type/HuggingfacePackageTypeProvider.java new file mode 100644 index 00000000..15c5e328 --- /dev/null +++ b/src/main/java/com/github/packageurl/type/HuggingfacePackageTypeProvider.java @@ -0,0 +1,24 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +public class HuggingfacePackageTypeProvider extends LowercaseVersionPackageTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/LowercaseNameAndVersionPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/LowercaseNameAndVersionPackageTypeProvider.java new file mode 100644 index 00000000..ffe64bcc --- /dev/null +++ b/src/main/java/com/github/packageurl/type/LowercaseNameAndVersionPackageTypeProvider.java @@ -0,0 +1,48 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import com.github.packageurl.PackageURL; +import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class LowercaseNameAndVersionPackageTypeProvider implements PackageTypeProvider { + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL( + type, + namespace, + PackageURL.toLowerCase(name), + version != null ? PackageURL.toLowerCase(version) : null, + qualifiers, + subpath); + } +} diff --git a/src/main/java/com/github/packageurl/type/LowercaseNamePackageTypeProvider.java b/src/main/java/com/github/packageurl/type/LowercaseNamePackageTypeProvider.java new file mode 100644 index 00000000..a2862340 --- /dev/null +++ b/src/main/java/com/github/packageurl/type/LowercaseNamePackageTypeProvider.java @@ -0,0 +1,42 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import com.github.packageurl.PackageURL; +import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class LowercaseNamePackageTypeProvider implements PackageTypeProvider { + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL(type, namespace, PackageURL.toLowerCase(name), version, qualifiers, subpath); + } +} diff --git a/src/main/java/com/github/packageurl/type/LowercaseNamespaceAndNameTypeProvider.java b/src/main/java/com/github/packageurl/type/LowercaseNamespaceAndNameTypeProvider.java new file mode 100644 index 00000000..87a87539 --- /dev/null +++ b/src/main/java/com/github/packageurl/type/LowercaseNamespaceAndNameTypeProvider.java @@ -0,0 +1,48 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import com.github.packageurl.PackageURL; +import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class LowercaseNamespaceAndNameTypeProvider implements PackageTypeProvider { + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL( + type, + namespace != null ? PackageURL.toLowerCase(namespace) : null, + PackageURL.toLowerCase(name), + version, + qualifiers, + subpath); + } +} diff --git a/src/main/java/com/github/packageurl/type/LowercaseNamespacePackageTypeProvider.java b/src/main/java/com/github/packageurl/type/LowercaseNamespacePackageTypeProvider.java new file mode 100644 index 00000000..5eeb505f --- /dev/null +++ b/src/main/java/com/github/packageurl/type/LowercaseNamespacePackageTypeProvider.java @@ -0,0 +1,43 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import com.github.packageurl.PackageURL; +import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class LowercaseNamespacePackageTypeProvider implements PackageTypeProvider { + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL( + type, namespace != null ? PackageURL.toLowerCase(namespace) : null, name, version, qualifiers, subpath); + } +} diff --git a/src/main/java/com/github/packageurl/type/LowercaseVersionPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/LowercaseVersionPackageTypeProvider.java new file mode 100644 index 00000000..c05bf361 --- /dev/null +++ b/src/main/java/com/github/packageurl/type/LowercaseVersionPackageTypeProvider.java @@ -0,0 +1,43 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import com.github.packageurl.PackageURL; +import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class LowercaseVersionPackageTypeProvider implements PackageTypeProvider { + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL( + type, namespace, name, version != null ? PackageURL.toLowerCase(version) : null, qualifiers, subpath); + } +} diff --git a/src/main/java/com/github/packageurl/type/LuarocksPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/LuarocksPackageTypeProvider.java new file mode 100644 index 00000000..ea54556c --- /dev/null +++ b/src/main/java/com/github/packageurl/type/LuarocksPackageTypeProvider.java @@ -0,0 +1,24 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +public class LuarocksPackageTypeProvider extends LowercaseVersionPackageTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/MavenPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/MavenPackageTypeProvider.java new file mode 100644 index 00000000..3d50959f --- /dev/null +++ b/src/main/java/com/github/packageurl/type/MavenPackageTypeProvider.java @@ -0,0 +1,43 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class MavenPackageTypeProvider implements PackageTypeProvider { + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + if (namespace == null || namespace.isEmpty()) { + throw new MalformedPackageURLException("a namespace is required"); + } + } +} diff --git a/src/main/java/com/github/packageurl/type/MlflowPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/MlflowPackageTypeProvider.java new file mode 100644 index 00000000..86eb861b --- /dev/null +++ b/src/main/java/com/github/packageurl/type/MlflowPackageTypeProvider.java @@ -0,0 +1,83 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import com.github.packageurl.PackageURL; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class MlflowPackageTypeProvider implements PackageTypeProvider { + private static @Nullable String normalizeName(@Nullable String name, @Nullable Map qualifiers) + throws MalformedPackageURLException { + if (qualifiers != null) { + String repositoryUrl = qualifiers.get("repository_url"); + + if (repositoryUrl != null) { + String host; + + try { + URI url = new URI(repositoryUrl); + host = url.getHost(); + + if (name != null && host.matches(".*[.]?azuredatabricks.net$")) { + return PackageURL.toLowerCase(name); + } + } catch (URISyntaxException e) { + throw new MalformedPackageURLException( + "'" + repositoryUrl + "' is not a valid URL for repository_url", e); + } + } + } + + return name; + } + + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + if (namespace != null && !namespace.isEmpty()) { + throw new MalformedPackageURLException("a namespace is not allowed for type '" + type + "'"); + } + } + + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL(type, namespace, normalizeName(name, qualifiers), version, qualifiers, subpath); + } +} diff --git a/src/main/java/com/github/packageurl/type/OciPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/OciPackageTypeProvider.java new file mode 100644 index 00000000..8ae3ee4c --- /dev/null +++ b/src/main/java/com/github/packageurl/type/OciPackageTypeProvider.java @@ -0,0 +1,62 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import com.github.packageurl.PackageURL; +import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class OciPackageTypeProvider implements PackageTypeProvider { + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + if (namespace != null && !namespace.isEmpty()) { + throw new MalformedPackageURLException("a namespace is not allowed for type '" + type + "'"); + } + } + + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL( + type, + namespace, + PackageURL.toLowerCase(name), + version != null ? PackageURL.toLowerCase(version) : null, + qualifiers, + subpath); + } +} diff --git a/src/main/java/com/github/packageurl/type/PackageTypeFactory.java b/src/main/java/com/github/packageurl/type/PackageTypeFactory.java new file mode 100644 index 00000000..cd3959e5 --- /dev/null +++ b/src/main/java/com/github/packageurl/type/PackageTypeFactory.java @@ -0,0 +1,209 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import com.github.packageurl.PackageURL; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.TreeMap; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public final class PackageTypeFactory implements PackageTypeProvider { + private static final @NonNull PackageTypeFactory INSTANCE = new PackageTypeFactory(); + + public static final @NonNull String TYPE = "__packagetypefactory__"; + + private @Nullable Map<@NonNull String, @NonNull PackageTypeProvider> packageTypeProviders; + + private PackageTypeFactory() {} + + public static @NonNull PackageTypeFactory getInstance() { + return INSTANCE; + } + + private static @NonNull String normalizeType(@NonNull String type) { + return PackageURL.toLowerCase(type); + } + + private static @Nullable String normalizeSubpath(@Nullable String subpath) { + if (subpath == null) { + return null; + } + + String[] segments = subpath.split("/", -1); + List segmentList = new ArrayList<>(segments.length); + + for (String segment : segments) { + if (!"..".equals(segment) && !".".equals(segment)) { + segmentList.add(segment); + } + } + + return String.join("/", segmentList); + } + + private static @Nullable Map normalizeQualifiers(@Nullable Map qualifiers) + throws MalformedPackageURLException { + if (qualifiers == null) { + return null; + } + + Set> entries = qualifiers.entrySet(); + Map map = new TreeMap<>(); + + for (Map.Entry entry : entries) { + String key = PackageURL.toLowerCase(entry.getKey()); + + if (map.put(key, entry.getValue()) != null) { + throw new MalformedPackageURLException("duplicate qualifiers key '" + key + "'"); + } + } + + return Collections.unmodifiableMap(map); + } + + private static void validateQualifiers(@Nullable Map qualifiers) + throws MalformedPackageURLException { + if (qualifiers == null || qualifiers.isEmpty()) { + return; + } + + Set> entries = qualifiers.entrySet(); + + for (Map.Entry entry : entries) { + String key = entry.getKey(); + + if (!key.chars().allMatch(PackageURL::isValidCharForKey)) { + throw new MalformedPackageURLException("checks for invalid qualifier keys. The qualifier key '" + key + + "' contains invalid characters"); + } + } + } + + static void validateType(@NonNull String type) throws MalformedPackageURLException { + if (type.isEmpty()) { + throw new MalformedPackageURLException("a type is always required"); + } + + char first = type.charAt(0); + + if (!PackageURL.isAlpha(first)) { + throw new MalformedPackageURLException("check for type that starts with number: '" + first + "'"); + } + + Map map = new LinkedHashMap<>(type.length()); + type.chars().filter(c -> !PackageURL.isValidCharForType(c)).forEach(c -> map.put(c, (char) c)); + + if (!map.isEmpty()) { + throw new MalformedPackageURLException("check for invalid characters in type: " + map); + } + } + + static void validateName(@NonNull String name) throws MalformedPackageURLException { + if (name.isEmpty()) { + throw new MalformedPackageURLException("a name is always required"); + } + } + + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + validateType(type); + validateName(name); + validateQualifiers(qualifiers); + + String normalizedType = normalizeType(type); + Map normalizedQualifiers = normalizeQualifiers(qualifiers); + String normalizedSubpath = normalizeSubpath(subpath); + PackageTypeProvider archiveStreamProvider = getPackageTypeProviders().get(normalizedType); + + if (archiveStreamProvider != null) { + archiveStreamProvider.validateComponents( + normalizedType, namespace, name, version, normalizedQualifiers, normalizedSubpath); + } + } + + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + String normalizedType = normalizeType(type); + Map normalizedQualifiers = normalizeQualifiers(qualifiers); + String normalizedSubpath = normalizeSubpath(subpath); + PackageTypeProvider archiveStreamProvider = getPackageTypeProviders().get(normalizedType); + + if (archiveStreamProvider != null) { + return archiveStreamProvider.normalizeComponents( + normalizedType, namespace, name, version, normalizedQualifiers, normalizedSubpath); + } + + return new PackageURL(normalizedType, namespace, name, version, normalizedQualifiers, normalizedSubpath); + } + + @Override + public @NonNull String getPackageType() { + return TYPE; + } + + @SuppressWarnings("removal") + private static @NonNull Map<@NonNull String, @NonNull PackageTypeProvider> findAvailablePackageTypeProviders() { + return AccessController.doPrivileged((PrivilegedAction>) () -> { + Map map = new TreeMap<>(); + ServiceLoader loader = + ServiceLoader.load(PackageTypeProvider.class, ClassLoader.getSystemClassLoader()); + + for (PackageTypeProvider provider : loader) { + map.put(provider.getPackageType(), provider); + } + + return Collections.unmodifiableMap(map); + }); + } + + public @NonNull Map getPackageTypeProviders() { + if (packageTypeProviders == null) { + packageTypeProviders = findAvailablePackageTypeProviders(); + } + + return Collections.unmodifiableMap(packageTypeProviders); + } +} diff --git a/src/main/java/com/github/packageurl/type/PackageTypeProvider.java b/src/main/java/com/github/packageurl/type/PackageTypeProvider.java new file mode 100644 index 00000000..c3989c37 --- /dev/null +++ b/src/main/java/com/github/packageurl/type/PackageTypeProvider.java @@ -0,0 +1,71 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import com.github.packageurl.PackageURL; +import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public interface PackageTypeProvider { + default void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException {} + + default @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL(type, namespace, name, version, qualifiers, subpath); + } + + default @NonNull String getPackageType() { + String simpleName = getClass().getSimpleName(); + String suffix = PackageTypeProvider.class.getSimpleName(); + int index = simpleName.lastIndexOf(suffix); + + if (index <= 0 || index != (simpleName.length() - suffix.length())) { + throw new IllegalArgumentException("Invalid class name for package type provider '" + simpleName + "'"); + } + + String type = PackageURL.toLowerCase(simpleName.substring(0, index)); + + try { + PackageTypeFactory.validateType(type); + } catch (MalformedPackageURLException e) { + throw new IllegalArgumentException( + "Package type provider name '" + type + "' is not a valid package type", e); + } + + return PackageURL.toLowerCase(type); + } +} diff --git a/src/main/java/com/github/packageurl/type/PubPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/PubPackageTypeProvider.java new file mode 100644 index 00000000..da5524ae --- /dev/null +++ b/src/main/java/com/github/packageurl/type/PubPackageTypeProvider.java @@ -0,0 +1,24 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +public class PubPackageTypeProvider extends LowercaseNamePackageTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/PypiPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/PypiPackageTypeProvider.java new file mode 100644 index 00000000..4522ae80 --- /dev/null +++ b/src/main/java/com/github/packageurl/type/PypiPackageTypeProvider.java @@ -0,0 +1,43 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import com.github.packageurl.PackageURL; +import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class PypiPackageTypeProvider implements PackageTypeProvider { + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL( + type, namespace, PackageURL.toLowerCase(name).replace('_', '-'), version, qualifiers, subpath); + } +} diff --git a/src/main/java/com/github/packageurl/type/QpkgPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/QpkgPackageTypeProvider.java new file mode 100644 index 00000000..6f3d5548 --- /dev/null +++ b/src/main/java/com/github/packageurl/type/QpkgPackageTypeProvider.java @@ -0,0 +1,24 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +public class QpkgPackageTypeProvider extends LowercaseNamespacePackageTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/RpmPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/RpmPackageTypeProvider.java new file mode 100644 index 00000000..89eca6ba --- /dev/null +++ b/src/main/java/com/github/packageurl/type/RpmPackageTypeProvider.java @@ -0,0 +1,24 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +public class RpmPackageTypeProvider extends LowercaseNamespacePackageTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/SwiftPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/SwiftPackageTypeProvider.java new file mode 100644 index 00000000..ec68bdbc --- /dev/null +++ b/src/main/java/com/github/packageurl/type/SwiftPackageTypeProvider.java @@ -0,0 +1,47 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.packageurl.type; + +import com.github.packageurl.MalformedPackageURLException; +import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public class SwiftPackageTypeProvider implements PackageTypeProvider { + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @Nullable String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + if (namespace == null || namespace.isEmpty()) { + throw new MalformedPackageURLException("invalid swift purl without namespace"); + } + + if (version == null || version.isEmpty()) { + throw new MalformedPackageURLException("invalid swift purl without version"); + } + } +} diff --git a/src/main/java/com/github/packageurl/type/package-info.java b/src/main/java/com/github/packageurl/type/package-info.java new file mode 100644 index 00000000..5a69aa2e --- /dev/null +++ b/src/main/java/com/github/packageurl/type/package-info.java @@ -0,0 +1,29 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + *

Java implementation of the Package-URL Specification.

+ *

https://github.com/package-url/purl-spec

+ */ +@NullMarked +package com.github.packageurl.type; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/resources/META-INF/services/com.github.packageurl.type.PackageTypeProvider b/src/main/resources/META-INF/services/com.github.packageurl.type.PackageTypeProvider new file mode 100644 index 00000000..43b36ad5 --- /dev/null +++ b/src/main/resources/META-INF/services/com.github.packageurl.type.PackageTypeProvider @@ -0,0 +1,24 @@ +com.github.packageurl.type.ApkPackageTypeProvider +com.github.packageurl.type.BitbucketPackageTypeProvider +com.github.packageurl.type.BitnamiPackageTypeProvider +com.github.packageurl.type.CocoapodsPackageTypeProvider +com.github.packageurl.type.ComposerPackageTypeProvider +com.github.packageurl.type.ConanPackageTypeProvider +com.github.packageurl.type.CpanPackageTypeProvider +com.github.packageurl.type.CranPackageTypeProvider +com.github.packageurl.type.DebPackageTypeProvider +com.github.packageurl.type.GenericPackageTypeProvider +com.github.packageurl.type.GithubPackageTypeProvider +com.github.packageurl.type.GolangPackageTypeProvider +com.github.packageurl.type.HackagePackageTypeProvider +com.github.packageurl.type.HexPackageTypeProvider +com.github.packageurl.type.HuggingfacePackageTypeProvider +com.github.packageurl.type.LuarocksPackageTypeProvider +com.github.packageurl.type.MavenPackageTypeProvider +com.github.packageurl.type.MlflowPackageTypeProvider +com.github.packageurl.type.OciPackageTypeProvider +com.github.packageurl.type.PubPackageTypeProvider +com.github.packageurl.type.PypiPackageTypeProvider +com.github.packageurl.type.QpkgPackageTypeProvider +com.github.packageurl.type.RpmPackageTypeProvider +com.github.packageurl.type.SwiftPackageTypeProvider diff --git a/src/test/java/com/github/packageurl/PackageURLTest.java b/src/test/java/com/github/packageurl/PackageURLTest.java index 18fb3458..6803a210 100644 --- a/src/test/java/com/github/packageurl/PackageURLTest.java +++ b/src/test/java/com/github/packageurl/PackageURLTest.java @@ -21,6 +21,7 @@ */ package com.github.packageurl; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -39,6 +40,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; /** * Test cases for PackageURL parsing @@ -109,7 +111,10 @@ void constructorParsing( boolean invalid) throws Exception { if (invalid) { - assertThrows(getExpectedException(purlString), () -> new PackageURL(purlString)); + assertThrows( + getExpectedException(purlString), + () -> new PackageURL(purlString), + "Parsing '" + purlString + "' should have failed because " + description); } else { PackageURL purl = new PackageURL(purlString); assertPurlEquals(parameters, purl); @@ -228,6 +233,7 @@ void standardTypes() { assertEquals("luarocks", PackageURL.StandardTypes.LUAROCKS); assertEquals("maven", PackageURL.StandardTypes.MAVEN); assertEquals("mlflow", PackageURL.StandardTypes.MLFLOW); + assertEquals("nix", PackageURL.StandardTypes.NIX); assertEquals("npm", PackageURL.StandardTypes.NPM); assertEquals("nuget", PackageURL.StandardTypes.NUGET); assertEquals("qpkg", PackageURL.StandardTypes.QPKG); @@ -280,4 +286,107 @@ void npmCaseSensitive() throws Exception { assertEquals("Base64", base64Uppercase.getName()); assertEquals("1.0.0", base64Uppercase.getVersion()); } + + @ParameterizedTest + @ValueSource( + strings = { + "pkg:alpm/arch/pacman@6.0.1-1?arch=x86_64", + "pkg:alpm/arch/python-pip@21.0-1?arch=any", + "pkg:alpm/arch/containers-common@1:0.47.4-4?arch=x86_64", + "pkg:apk/alpine/curl@7.83.0-r0?arch=x86", + "pkg:apk/alpine/apk@2.12.9-r3?arch=x86", + "pkg:bitbucket/birkenfeld/pygments-main@244fd47e07d1014f0aed9c", + "pkg:bitnami/wordpress?distro=debian-12", + "pkg:bitnami/wordpress@6.2.0?distro=debian-12", + "pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=debian-12", + "pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=photon-4", + "pkg:cocoapods/AFNetworking@4.0.1", + "pkg:cocoapods/MapsIndoors@3.24.0", + "pkg:cocoapods/ShareKit@2.0#Twitter", + "pkg:cocoapods/GoogleUtilities@7.5.2#NSData+zlib", + "pkg:cocoapods/GoogleUtilities@7.5.2#NSData+zlib", + "pkg:cargo/rand@0.7.2", + "pkg:cargo/clap@2.33.0", + "pkg:cargo/structopt@0.3.11", + "pkg:composer/laravel/laravel@5.5.0", + "pkg:conan/openssl@3.0.3", + "pkg:conan/openssl.org/openssl@3.0.3?user=bincrafters&channel=stable", + "pkg:conan/openssl.org/openssl@3.0.3?arch=x86_64&build_type=Debug&compiler=Visual%20Studio&compiler.runtime=MDd&compiler.version=16&os=Windows&shared=True&rrev=93a82349c31917d2d674d22065c7a9ef9f380c8e&prev=b429db8a0e324114c25ec387bfd8281f330d7c5c", + "pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2", + "pkg:cpan/Perl::Version@1.013", + "pkg:cpan/DROLSKY/DateTime@1.55", + "pkg:cpan/DateTime@1.55", + "pkg:cpan/GDT/URI-PackageURL", + "pkg:cpan/LWP::UserAgent", + "pkg:cpan/OALDERS/libwww-perl@6.76", + "pkg:cpan/URI", + "pkg:cran/A3@1.0.0", + "pkg:cran/rJava@1.0-4", + "pkg:cran/caret@6.0-88", + "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie", + "pkg:deb/debian/dpkg@1.19.0.4?arch=amd64&distro=stretch", + "pkg:deb/ubuntu/dpkg@1.19.0.4?arch=amd64", + "pkg:deb/debian/attr@1:2.4.47-2?arch=source", + "pkg:deb/debian/attr@1:2.4.47-2%2Bb1?arch=amd64", + "pkg:docker/cassandra@latest", + "pkg:docker/smartentry/debian@dc437cc87d10", + "pkg:docker/customer/dockerimage@sha256%3A244fd47e07d10?repository_url=gcr.io", + "pkg:gem/ruby-advisory-db-check@0.12.4", + "pkg:gem/jruby-launcher@1.1.2?platform=java", + "pkg:generic/openssl@1.1.10g", + "pkg:generic/openssl@1.1.10g?download_url=https://openssl.org/source/openssl-1.1.0g.tar.gz&checksum=sha256:de4d501267da", + "pkg:generic/bitwarderl?vcs_url=git%2Bhttps://git.fsfe.org/dxtr/bitwarderl%40cc55108da32", + "pkg:github/package-url/purl-spec@244fd47e07d1004", + "pkg:github/package-url/purl-spec@244fd47e07d1004#everybody/loves/dogs", + "pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c", + "pkg:golang/google.golang.org/genproto#googleapis/api/annotations", + "pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c#api", + "pkg:hackage/a50@0.5", + "pkg:hackage/AC-HalfInteger@1.2.1", + "pkg:hackage/3d-graphics-examples@0.0.0.2", + "pkg:hex/jason@1.1.2", + "pkg:hex/acme/foo@2.3.", + "pkg:hex/phoenix_html@2.13.3#priv/static/phoenix_html.js", + "pkg:hex/bar@1.2.3?repository_url=https://myrepo.example.com", + "pkg:huggingface/distilbert-base-uncased@043235d6088ecd3dd5fb5ca3592b6913fd516027", + "pkg:huggingface/microsoft/deberta-v3-base@559062ad13d311b87b2c455e67dcd5f1c8f65111?repository_url=https://hub-ci.huggingface.co", + "pkg:luarocks/luasocket@3.1.0-1", + "pkg:luarocks/hisham/luafilesystem@1.8.0-1", + "pkg:luarocks/username/packagename@0.1.0-1?repository_url=https://example.com/private_rocks_server/", + "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1", + "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=pom", + "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources", + "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=zip&classifier=dist", + "pkg:maven/net.sf.jacob-projec/jacob@1.14.3?classifier=x86&type=dll", + "pkg:maven/net.sf.jacob-projec/jacob@1.14.3?classifier=x64&type=dll", + "pkg:maven/groovy/groovy@1.0?repository_url=https://maven.google.com", + "pkg:mlflow/creditfraud@3?repository_url=https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace", + "pkg:mlflow/trafficsigns@10?model_uuid=36233173b22f4c89b451f1228d700d49&run_id=410a3121-2709-4f88-98dd-dba0ef056b0a&repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", + "pkg:npm/foobar@12.3.1", + "pkg:npm/%40angular/animation@12.3.1", + "pkg:npm/mypackage@12.4.5?vcs_url=git://host.com/path/to/repo.git%404345abcd34343", + "pkg:nuget/EnterpriseLibrary.Common@6.0.1304", + "pkg:qpkg/blackberry/com.qnx.sdp@7.0.0.SGA201702151847", + "pkg:qpkg/blackberry/com.qnx.qnx710.foo.bar.qux@0.0.4.01449T202205040833L", + "pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=docker.io/library/debian&arch=amd64&tag=latest", + "pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=ghcr.io/debian&tag=bullseye", + "pkg:oci/static@sha256%3A244fd47e07d10?repository_url=gcr.io/distroless/static&tag=latest", + "pkg:oci/hello-wasm@sha256%3A244fd47e07d10?tag=v1", + "pkg:pub/characters@1.2.0", + "pkg:pub/flutter@0.0.0", + "pkg:pypi/django@1.11.1", + "pkg:pypi/django@1.11.1?filename=Django-1.11.1.tar.gz", + "pkg:pypi/django@1.11.1?filename=Django-1.11.1-py2.py3-none-any.whl", + "pkg:pypi/django-allauth@12.23", + "pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25", + "pkg:rpm/centerim@4.22.10-1.el6?arch=i686&epoch=1&distro=fedora-25", + "pkg:swid/Acme/example.com/Enterprise+Server@1.0.0?tag_id=75b8c285-fa7b-485b-b199-4745e3004d0d", + "pkg:swid/Fedora@29?tag_id=org.fedoraproject.Fedora-29", + "pkg:swid/Adobe+Systems+Incorporated/Adobe+InDesign@CC?tag_id=CreativeCloud-CS6-Win-GM-MUL", + "pkg:swift/github.com/Alamofire/Alamofire@5.4.3", + "pkg:swift/github.com/RxSwiftCommunity/RxFlow@2.12.4" + }) + void parseValidTypes(String purl) { + assertDoesNotThrow(() -> new PackageURL(purl)); + } } From ac200a8ad6c83caa1b93bdcd5b726eb08feaddb6 Mon Sep 17 00:00:00 2001 From: David Walluck Date: Thu, 27 Mar 2025 15:22:03 +0100 Subject: [PATCH 02/11] chore: refactor based on suggestions --- pom.xml | 13 +- .../com/github/packageurl/PackageURL.java | 2 +- .../PackageTypeFactory.java | 11 +- .../internal/PackageTypeProviders.java | 381 ++++++++++++++++++ .../{type => spi}/PackageTypeProvider.java | 3 +- .../{type => spi}/package-info.java | 6 +- .../type/ApkPackageTypeProvider.java | 24 -- .../type/BitbucketPackageTypeProvider.java | 24 -- .../type/BitnamiPackageTypeProvider.java | 24 -- .../type/CocoapodsPackageTypeProvider.java | 48 --- .../type/ComposerPackageTypeProvider.java | 24 -- .../type/ConanPackageTypeProvider.java | 47 --- .../type/CpanPackageTypeProvider.java | 45 --- .../type/CranPackageTypeProvider.java | 43 -- .../type/DebPackageTypeProvider.java | 24 -- .../type/GenericPackageTypeProvider.java | 24 -- .../type/GithubPackageTypeProvider.java | 24 -- .../type/GolangPackageTypeProvider.java | 24 -- .../type/HackagePackageTypeProvider.java | 43 -- .../type/HexPackageTypeProvider.java | 24 -- .../type/HuggingfacePackageTypeProvider.java | 24 -- ...caseNameAndVersionPackageTypeProvider.java | 49 --- .../LowercaseNamePackageTypeProvider.java | 43 -- ...LowercaseNamespaceAndNameTypeProvider.java | 49 --- ...LowercaseNamespacePackageTypeProvider.java | 44 -- .../LowercaseVersionPackageTypeProvider.java | 44 -- .../type/LuarocksPackageTypeProvider.java | 24 -- .../type/MavenPackageTypeProvider.java | 43 -- .../type/MlflowPackageTypeProvider.java | 84 ---- .../type/OciPackageTypeProvider.java | 63 --- .../type/PubPackageTypeProvider.java | 24 -- .../type/PypiPackageTypeProvider.java | 44 -- .../type/QpkgPackageTypeProvider.java | 24 -- .../type/RpmPackageTypeProvider.java | 24 -- .../type/SwiftPackageTypeProvider.java | 47 --- ....github.packageurl.spi.PackageTypeProvider | 24 ++ ...github.packageurl.type.PackageTypeProvider | 24 -- 37 files changed, 430 insertions(+), 1106 deletions(-) rename src/main/java/com/github/packageurl/{type => internal}/PackageTypeFactory.java (94%) create mode 100644 src/main/java/com/github/packageurl/internal/PackageTypeProviders.java rename src/main/java/com/github/packageurl/{type => spi}/PackageTypeProvider.java (96%) rename src/main/java/com/github/packageurl/{type => spi}/package-info.java (78%) delete mode 100644 src/main/java/com/github/packageurl/type/ApkPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/BitbucketPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/BitnamiPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/CocoapodsPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/ComposerPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/ConanPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/CpanPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/CranPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/DebPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/GenericPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/GithubPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/GolangPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/HackagePackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/HexPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/HuggingfacePackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/LowercaseNameAndVersionPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/LowercaseNamePackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/LowercaseNamespaceAndNameTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/LowercaseNamespacePackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/LowercaseVersionPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/LuarocksPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/MavenPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/MlflowPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/OciPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/PubPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/PypiPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/QpkgPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/RpmPackageTypeProvider.java delete mode 100644 src/main/java/com/github/packageurl/type/SwiftPackageTypeProvider.java create mode 100644 src/main/resources/META-INF/services/com.github.packageurl.spi.PackageTypeProvider delete mode 100644 src/main/resources/META-INF/services/com.github.packageurl.type.PackageTypeProvider diff --git a/pom.xml b/pom.xml index e1e48663..ac79d0a8 100644 --- a/pom.xml +++ b/pom.xml @@ -142,6 +142,9 @@ 20250107 5.12.1 1.4.0 + 7.1.0 + 1.0.0 + 2.0.0 @@ -158,6 +161,12 @@ + + biz.aQute.bnd + biz.aQute.bnd.annotation + ${biz.aQute.bnd.annotation.version} + provided + jakarta.validation jakarta.validation-api @@ -168,13 +177,13 @@ org.osgi org.osgi.annotation.bundle - 2.0.0 + ${org.osgi.annotation.bundle.version} provided org.jspecify jspecify - 1.0.0 + ${jspecify.version} provided true diff --git a/src/main/java/com/github/packageurl/PackageURL.java b/src/main/java/com/github/packageurl/PackageURL.java index 67aa16ad..b8a81ca5 100644 --- a/src/main/java/com/github/packageurl/PackageURL.java +++ b/src/main/java/com/github/packageurl/PackageURL.java @@ -24,7 +24,7 @@ import static java.util.Objects.requireNonNull; import com.github.packageurl.internal.StringUtil; -import com.github.packageurl.type.PackageTypeFactory; +import com.github.packageurl.internal.PackageTypeFactory; import java.io.Serializable; import java.net.URI; import java.net.URISyntaxException; diff --git a/src/main/java/com/github/packageurl/type/PackageTypeFactory.java b/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java similarity index 94% rename from src/main/java/com/github/packageurl/type/PackageTypeFactory.java rename to src/main/java/com/github/packageurl/internal/PackageTypeFactory.java index d6bbfb89..77a07414 100644 --- a/src/main/java/com/github/packageurl/type/PackageTypeFactory.java +++ b/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java @@ -19,11 +19,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.packageurl.type; +package com.github.packageurl.internal; +import aQute.bnd.annotation.spi.ServiceConsumer; import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; -import com.github.packageurl.internal.StringUtil; + import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; @@ -34,9 +35,13 @@ import java.util.ServiceLoader; import java.util.Set; import java.util.TreeMap; + +import com.github.packageurl.spi.PackageTypeProvider; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; +import org.osgi.annotation.bundle.Requirement; +@ServiceConsumer(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY, cardinality = Requirement.Cardinality.MULTIPLE) public final class PackageTypeFactory implements PackageTypeProvider { private static final @NonNull PackageTypeFactory INSTANCE = new PackageTypeFactory(); @@ -109,7 +114,7 @@ private static void validateQualifiers(@Nullable Map qualifiers) } } - static void validateType(@NonNull String type) throws MalformedPackageURLException { + public static void validateType(@NonNull String type) throws MalformedPackageURLException { if (type.isEmpty()) { throw new MalformedPackageURLException("a type is always required"); } diff --git a/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java b/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java new file mode 100644 index 00000000..5d5008f5 --- /dev/null +++ b/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java @@ -0,0 +1,381 @@ +package com.github.packageurl.internal; + +import aQute.bnd.annotation.spi.ServiceProvider; +import com.github.packageurl.MalformedPackageURLException; +import com.github.packageurl.PackageURL; +import com.github.packageurl.spi.PackageTypeProvider; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.osgi.annotation.bundle.Requirement; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Map; + +public final class PackageTypeProviders { + private PackageTypeProviders() {} + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class ApkPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class BitbucketPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class BitnamiPackageTypeProvider extends LowercaseNamespacePackageTypeProvider {} + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class CocoapodsPackageTypeProvider implements PackageTypeProvider { + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + if (namespace != null && !namespace.isEmpty()) { + throw new MalformedPackageURLException("invalid cocoapods purl cannot have a namespace"); + } + + if (name.chars().anyMatch(StringUtil::isWhitespace) || name.startsWith(".") || name.contains("+")) { + throw new MalformedPackageURLException("invalid cocoapods purl invalid name"); + } + } + } + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class ComposerPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class ConanPackageTypeProvider implements PackageTypeProvider { + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + boolean hasChannel = (qualifiers != null && !qualifiers.isEmpty()); + + if ((namespace != null && !namespace.isEmpty()) && !hasChannel) { + throw new MalformedPackageURLException("invalid conan purl only namespace"); + } else if ((namespace == null || namespace.isEmpty()) && hasChannel) { + throw new MalformedPackageURLException("invalid conan purl only channel qualifier"); + } + } + } + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class CpanPackageTypeProvider implements PackageTypeProvider { + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + if ((namespace == null || namespace.isEmpty()) && name.indexOf('-') != -1) { + throw new MalformedPackageURLException("cpan module name like distribution name"); + } else if ((namespace != null && !namespace.isEmpty()) && name.contains("::")) { + throw new MalformedPackageURLException("cpan distribution name like module name"); + } + } + } + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class CranPackageTypeProvider implements PackageTypeProvider { + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + if (version == null || version.isEmpty()) { + throw new MalformedPackageURLException("invalid cran purl without version"); + } + } + } + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class DebPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class GenericPackageTypeProvider implements PackageTypeProvider {} + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class GithubPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class GolangPackageTypeProvider extends LowercaseNamespacePackageTypeProvider {} + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class HackagePackageTypeProvider implements PackageTypeProvider { + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + if (version == null || version.isEmpty()) { + throw new MalformedPackageURLException("name and version are always required"); + } + } + } + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class HexPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class HuggingfacePackageTypeProvider extends LowercaseVersionPackageTypeProvider {} + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class LuarocksPackageTypeProvider extends LowercaseVersionPackageTypeProvider {} + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class MavenPackageTypeProvider implements PackageTypeProvider { + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + if (namespace == null || namespace.isEmpty()) { + throw new MalformedPackageURLException("a namespace is required"); + } + } + } + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class MlflowPackageTypeProvider implements PackageTypeProvider { + private static @Nullable String normalizeName(@Nullable String name, @Nullable Map qualifiers) + throws MalformedPackageURLException { + if (qualifiers != null) { + String repositoryUrl = qualifiers.get("repository_url"); + + if (repositoryUrl != null) { + String host; + + try { + URI url = new URI(repositoryUrl); + host = url.getHost(); + + if (name != null && host.matches(".*[.]?azuredatabricks.net$")) { + return StringUtil.toLowerCase(name); + } + } catch (URISyntaxException e) { + throw new MalformedPackageURLException( + "'" + repositoryUrl + "' is not a valid URL for repository_url", e); + } + } + } + + return name; + } + + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + if (namespace != null && !namespace.isEmpty()) { + throw new MalformedPackageURLException("a namespace is not allowed for type '" + type + "'"); + } + } + + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL(type, namespace, normalizeName(name, qualifiers), version, qualifiers, subpath); + } + } + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class OciPackageTypeProvider implements PackageTypeProvider { + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + if (namespace != null && !namespace.isEmpty()) { + throw new MalformedPackageURLException("a namespace is not allowed for type '" + type + "'"); + } + } + + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL( + type, + namespace, + StringUtil.toLowerCase(name), + version != null ? StringUtil.toLowerCase(version) : null, + qualifiers, + subpath); + } + } + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class PubPackageTypeProvider extends LowercaseNamePackageTypeProvider {} + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class PypiPackageTypeProvider implements PackageTypeProvider { + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL( + type, namespace, StringUtil.toLowerCase(name).replace('_', '-'), version, qualifiers, subpath); + } + } + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class QpkgPackageTypeProvider extends LowercaseNamespacePackageTypeProvider {} + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class RpmPackageTypeProvider extends LowercaseNamespacePackageTypeProvider {} + + @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + public static class SwiftPackageTypeProvider implements PackageTypeProvider { + @Override + public void validateComponents( + @NonNull String type, + @Nullable String namespace, + @Nullable String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + if (namespace == null || namespace.isEmpty()) { + throw new MalformedPackageURLException("invalid swift purl without namespace"); + } + + if (version == null || version.isEmpty()) { + throw new MalformedPackageURLException("invalid swift purl without version"); + } + } + } + + public static class LowercaseNameAndVersionPackageTypeProvider implements PackageTypeProvider { + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL( + type, + namespace, + StringUtil.toLowerCase(name), + version != null ? StringUtil.toLowerCase(version) : null, + qualifiers, + subpath); + } + } + + public static class LowercaseNamePackageTypeProvider implements PackageTypeProvider { + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL(type, namespace, StringUtil.toLowerCase(name), version, qualifiers, subpath); + } + } + + public static class LowercaseNamespaceAndNameTypeProvider implements PackageTypeProvider { + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL( + type, + namespace != null ? StringUtil.toLowerCase(namespace) : null, + StringUtil.toLowerCase(name), + version, + qualifiers, + subpath); + } + } + + public static class LowercaseNamespacePackageTypeProvider implements PackageTypeProvider { + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL( + type, namespace != null ? StringUtil.toLowerCase(namespace) : null, name, version, qualifiers, subpath); + } + } + + public static class LowercaseVersionPackageTypeProvider implements PackageTypeProvider { + @Override + public @NonNull PackageURL normalizeComponents( + @NonNull String type, + @Nullable String namespace, + @NonNull String name, + @Nullable String version, + @Nullable Map qualifiers, + @Nullable String subpath) + throws MalformedPackageURLException { + return new PackageURL( + type, namespace, name, version != null ? StringUtil.toLowerCase(version) : null, qualifiers, subpath); + } + } +} diff --git a/src/main/java/com/github/packageurl/type/PackageTypeProvider.java b/src/main/java/com/github/packageurl/spi/PackageTypeProvider.java similarity index 96% rename from src/main/java/com/github/packageurl/type/PackageTypeProvider.java rename to src/main/java/com/github/packageurl/spi/PackageTypeProvider.java index 383ee83f..c3a09ff9 100644 --- a/src/main/java/com/github/packageurl/type/PackageTypeProvider.java +++ b/src/main/java/com/github/packageurl/spi/PackageTypeProvider.java @@ -19,10 +19,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.packageurl.type; +package com.github.packageurl.spi; import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; +import com.github.packageurl.internal.PackageTypeFactory; import com.github.packageurl.internal.StringUtil; import java.util.Map; import org.jspecify.annotations.NonNull; diff --git a/src/main/java/com/github/packageurl/type/package-info.java b/src/main/java/com/github/packageurl/spi/package-info.java similarity index 78% rename from src/main/java/com/github/packageurl/type/package-info.java rename to src/main/java/com/github/packageurl/spi/package-info.java index 5a69aa2e..3befeecf 100644 --- a/src/main/java/com/github/packageurl/type/package-info.java +++ b/src/main/java/com/github/packageurl/spi/package-info.java @@ -20,10 +20,10 @@ * SOFTWARE. */ /** - *

Java implementation of the Package-URL Specification.

- *

https://github.com/package-url/purl-spec

+ *

Java implementation of the Package-URL Specification SPI for PURL types.

+ *

https://raw.githubusercontent.com/package-url/purl-spec/refs/heads/main/PURL-TYPES.rst

*/ @NullMarked -package com.github.packageurl.type; +package com.github.packageurl.spi; import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/com/github/packageurl/type/ApkPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/ApkPackageTypeProvider.java deleted file mode 100644 index 48f3e5be..00000000 --- a/src/main/java/com/github/packageurl/type/ApkPackageTypeProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -public class ApkPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/BitbucketPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/BitbucketPackageTypeProvider.java deleted file mode 100644 index d2113c99..00000000 --- a/src/main/java/com/github/packageurl/type/BitbucketPackageTypeProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -public class BitbucketPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/BitnamiPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/BitnamiPackageTypeProvider.java deleted file mode 100644 index 40b12d18..00000000 --- a/src/main/java/com/github/packageurl/type/BitnamiPackageTypeProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -public class BitnamiPackageTypeProvider extends LowercaseNamespacePackageTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/CocoapodsPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/CocoapodsPackageTypeProvider.java deleted file mode 100644 index 1d626db4..00000000 --- a/src/main/java/com/github/packageurl/type/CocoapodsPackageTypeProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -import com.github.packageurl.MalformedPackageURLException; -import com.github.packageurl.internal.StringUtil; -import java.util.Map; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class CocoapodsPackageTypeProvider implements PackageTypeProvider { - @Override - public void validateComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - if (namespace != null && !namespace.isEmpty()) { - throw new MalformedPackageURLException("invalid cocoapods purl cannot have a namespace"); - } - - if (name.chars().anyMatch(StringUtil::isWhitespace) || name.startsWith(".") || name.contains("+")) { - throw new MalformedPackageURLException("invalid cocoapods purl invalid name"); - } - } -} diff --git a/src/main/java/com/github/packageurl/type/ComposerPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/ComposerPackageTypeProvider.java deleted file mode 100644 index 3e6dc2cb..00000000 --- a/src/main/java/com/github/packageurl/type/ComposerPackageTypeProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -public class ComposerPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/ConanPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/ConanPackageTypeProvider.java deleted file mode 100644 index d99533cf..00000000 --- a/src/main/java/com/github/packageurl/type/ConanPackageTypeProvider.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -import com.github.packageurl.MalformedPackageURLException; -import java.util.Map; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class ConanPackageTypeProvider implements PackageTypeProvider { - @Override - public void validateComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - boolean hasChannel = (qualifiers != null && !qualifiers.isEmpty()); - - if ((namespace != null && !namespace.isEmpty()) && !hasChannel) { - throw new MalformedPackageURLException("invalid conan purl only namespace"); - } else if ((namespace == null || namespace.isEmpty()) && hasChannel) { - throw new MalformedPackageURLException("invalid conan purl only channel qualifier"); - } - } -} diff --git a/src/main/java/com/github/packageurl/type/CpanPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/CpanPackageTypeProvider.java deleted file mode 100644 index c915cc04..00000000 --- a/src/main/java/com/github/packageurl/type/CpanPackageTypeProvider.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -import com.github.packageurl.MalformedPackageURLException; -import java.util.Map; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class CpanPackageTypeProvider implements PackageTypeProvider { - @Override - public void validateComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - if ((namespace == null || namespace.isEmpty()) && name.indexOf('-') != -1) { - throw new MalformedPackageURLException("cpan module name like distribution name"); - } else if ((namespace != null && !namespace.isEmpty()) && name.contains("::")) { - throw new MalformedPackageURLException("cpan distribution name like module name"); - } - } -} diff --git a/src/main/java/com/github/packageurl/type/CranPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/CranPackageTypeProvider.java deleted file mode 100644 index 7da94c7f..00000000 --- a/src/main/java/com/github/packageurl/type/CranPackageTypeProvider.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -import com.github.packageurl.MalformedPackageURLException; -import java.util.Map; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class CranPackageTypeProvider implements PackageTypeProvider { - @Override - public void validateComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - if (version == null || version.isEmpty()) { - throw new MalformedPackageURLException("invalid cran purl without version"); - } - } -} diff --git a/src/main/java/com/github/packageurl/type/DebPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/DebPackageTypeProvider.java deleted file mode 100644 index a9e909d8..00000000 --- a/src/main/java/com/github/packageurl/type/DebPackageTypeProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -public class DebPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/GenericPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/GenericPackageTypeProvider.java deleted file mode 100644 index 9921ad13..00000000 --- a/src/main/java/com/github/packageurl/type/GenericPackageTypeProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -public class GenericPackageTypeProvider implements PackageTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/GithubPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/GithubPackageTypeProvider.java deleted file mode 100644 index 37f3d205..00000000 --- a/src/main/java/com/github/packageurl/type/GithubPackageTypeProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -public class GithubPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/GolangPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/GolangPackageTypeProvider.java deleted file mode 100644 index 2476ca84..00000000 --- a/src/main/java/com/github/packageurl/type/GolangPackageTypeProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -public class GolangPackageTypeProvider extends LowercaseNamespacePackageTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/HackagePackageTypeProvider.java b/src/main/java/com/github/packageurl/type/HackagePackageTypeProvider.java deleted file mode 100644 index 2229d06e..00000000 --- a/src/main/java/com/github/packageurl/type/HackagePackageTypeProvider.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -import com.github.packageurl.MalformedPackageURLException; -import java.util.Map; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class HackagePackageTypeProvider implements PackageTypeProvider { - @Override - public void validateComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - if (version == null || version.isEmpty()) { - throw new MalformedPackageURLException("name and version are always required"); - } - } -} diff --git a/src/main/java/com/github/packageurl/type/HexPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/HexPackageTypeProvider.java deleted file mode 100644 index cd502ac1..00000000 --- a/src/main/java/com/github/packageurl/type/HexPackageTypeProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -public class HexPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/HuggingfacePackageTypeProvider.java b/src/main/java/com/github/packageurl/type/HuggingfacePackageTypeProvider.java deleted file mode 100644 index 15c5e328..00000000 --- a/src/main/java/com/github/packageurl/type/HuggingfacePackageTypeProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -public class HuggingfacePackageTypeProvider extends LowercaseVersionPackageTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/LowercaseNameAndVersionPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/LowercaseNameAndVersionPackageTypeProvider.java deleted file mode 100644 index ca89f8e4..00000000 --- a/src/main/java/com/github/packageurl/type/LowercaseNameAndVersionPackageTypeProvider.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -import com.github.packageurl.MalformedPackageURLException; -import com.github.packageurl.PackageURL; -import com.github.packageurl.internal.StringUtil; -import java.util.Map; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class LowercaseNameAndVersionPackageTypeProvider implements PackageTypeProvider { - @Override - public @NonNull PackageURL normalizeComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - return new PackageURL( - type, - namespace, - StringUtil.toLowerCase(name), - version != null ? StringUtil.toLowerCase(version) : null, - qualifiers, - subpath); - } -} diff --git a/src/main/java/com/github/packageurl/type/LowercaseNamePackageTypeProvider.java b/src/main/java/com/github/packageurl/type/LowercaseNamePackageTypeProvider.java deleted file mode 100644 index d2376061..00000000 --- a/src/main/java/com/github/packageurl/type/LowercaseNamePackageTypeProvider.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -import com.github.packageurl.MalformedPackageURLException; -import com.github.packageurl.PackageURL; -import com.github.packageurl.internal.StringUtil; -import java.util.Map; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class LowercaseNamePackageTypeProvider implements PackageTypeProvider { - @Override - public @NonNull PackageURL normalizeComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - return new PackageURL(type, namespace, StringUtil.toLowerCase(name), version, qualifiers, subpath); - } -} diff --git a/src/main/java/com/github/packageurl/type/LowercaseNamespaceAndNameTypeProvider.java b/src/main/java/com/github/packageurl/type/LowercaseNamespaceAndNameTypeProvider.java deleted file mode 100644 index d14b942b..00000000 --- a/src/main/java/com/github/packageurl/type/LowercaseNamespaceAndNameTypeProvider.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -import com.github.packageurl.MalformedPackageURLException; -import com.github.packageurl.PackageURL; -import com.github.packageurl.internal.StringUtil; -import java.util.Map; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class LowercaseNamespaceAndNameTypeProvider implements PackageTypeProvider { - @Override - public @NonNull PackageURL normalizeComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - return new PackageURL( - type, - namespace != null ? StringUtil.toLowerCase(namespace) : null, - StringUtil.toLowerCase(name), - version, - qualifiers, - subpath); - } -} diff --git a/src/main/java/com/github/packageurl/type/LowercaseNamespacePackageTypeProvider.java b/src/main/java/com/github/packageurl/type/LowercaseNamespacePackageTypeProvider.java deleted file mode 100644 index 3bf907c6..00000000 --- a/src/main/java/com/github/packageurl/type/LowercaseNamespacePackageTypeProvider.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -import com.github.packageurl.MalformedPackageURLException; -import com.github.packageurl.PackageURL; -import com.github.packageurl.internal.StringUtil; -import java.util.Map; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class LowercaseNamespacePackageTypeProvider implements PackageTypeProvider { - @Override - public @NonNull PackageURL normalizeComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - return new PackageURL( - type, namespace != null ? StringUtil.toLowerCase(namespace) : null, name, version, qualifiers, subpath); - } -} diff --git a/src/main/java/com/github/packageurl/type/LowercaseVersionPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/LowercaseVersionPackageTypeProvider.java deleted file mode 100644 index 44c52b7f..00000000 --- a/src/main/java/com/github/packageurl/type/LowercaseVersionPackageTypeProvider.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -import com.github.packageurl.MalformedPackageURLException; -import com.github.packageurl.PackageURL; -import com.github.packageurl.internal.StringUtil; -import java.util.Map; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class LowercaseVersionPackageTypeProvider implements PackageTypeProvider { - @Override - public @NonNull PackageURL normalizeComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - return new PackageURL( - type, namespace, name, version != null ? StringUtil.toLowerCase(version) : null, qualifiers, subpath); - } -} diff --git a/src/main/java/com/github/packageurl/type/LuarocksPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/LuarocksPackageTypeProvider.java deleted file mode 100644 index ea54556c..00000000 --- a/src/main/java/com/github/packageurl/type/LuarocksPackageTypeProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -public class LuarocksPackageTypeProvider extends LowercaseVersionPackageTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/MavenPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/MavenPackageTypeProvider.java deleted file mode 100644 index 3d50959f..00000000 --- a/src/main/java/com/github/packageurl/type/MavenPackageTypeProvider.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -import com.github.packageurl.MalformedPackageURLException; -import java.util.Map; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class MavenPackageTypeProvider implements PackageTypeProvider { - @Override - public void validateComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - if (namespace == null || namespace.isEmpty()) { - throw new MalformedPackageURLException("a namespace is required"); - } - } -} diff --git a/src/main/java/com/github/packageurl/type/MlflowPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/MlflowPackageTypeProvider.java deleted file mode 100644 index 41c3bcd8..00000000 --- a/src/main/java/com/github/packageurl/type/MlflowPackageTypeProvider.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -import com.github.packageurl.MalformedPackageURLException; -import com.github.packageurl.PackageURL; -import com.github.packageurl.internal.StringUtil; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Map; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class MlflowPackageTypeProvider implements PackageTypeProvider { - private static @Nullable String normalizeName(@Nullable String name, @Nullable Map qualifiers) - throws MalformedPackageURLException { - if (qualifiers != null) { - String repositoryUrl = qualifiers.get("repository_url"); - - if (repositoryUrl != null) { - String host; - - try { - URI url = new URI(repositoryUrl); - host = url.getHost(); - - if (name != null && host.matches(".*[.]?azuredatabricks.net$")) { - return StringUtil.toLowerCase(name); - } - } catch (URISyntaxException e) { - throw new MalformedPackageURLException( - "'" + repositoryUrl + "' is not a valid URL for repository_url", e); - } - } - } - - return name; - } - - @Override - public void validateComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - if (namespace != null && !namespace.isEmpty()) { - throw new MalformedPackageURLException("a namespace is not allowed for type '" + type + "'"); - } - } - - @Override - public @NonNull PackageURL normalizeComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - return new PackageURL(type, namespace, normalizeName(name, qualifiers), version, qualifiers, subpath); - } -} diff --git a/src/main/java/com/github/packageurl/type/OciPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/OciPackageTypeProvider.java deleted file mode 100644 index 3c9f47d3..00000000 --- a/src/main/java/com/github/packageurl/type/OciPackageTypeProvider.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -import com.github.packageurl.MalformedPackageURLException; -import com.github.packageurl.PackageURL; -import com.github.packageurl.internal.StringUtil; -import java.util.Map; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class OciPackageTypeProvider implements PackageTypeProvider { - @Override - public void validateComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - if (namespace != null && !namespace.isEmpty()) { - throw new MalformedPackageURLException("a namespace is not allowed for type '" + type + "'"); - } - } - - @Override - public @NonNull PackageURL normalizeComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - return new PackageURL( - type, - namespace, - StringUtil.toLowerCase(name), - version != null ? StringUtil.toLowerCase(version) : null, - qualifiers, - subpath); - } -} diff --git a/src/main/java/com/github/packageurl/type/PubPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/PubPackageTypeProvider.java deleted file mode 100644 index da5524ae..00000000 --- a/src/main/java/com/github/packageurl/type/PubPackageTypeProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -public class PubPackageTypeProvider extends LowercaseNamePackageTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/PypiPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/PypiPackageTypeProvider.java deleted file mode 100644 index 2f5b4691..00000000 --- a/src/main/java/com/github/packageurl/type/PypiPackageTypeProvider.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -import com.github.packageurl.MalformedPackageURLException; -import com.github.packageurl.PackageURL; -import com.github.packageurl.internal.StringUtil; -import java.util.Map; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class PypiPackageTypeProvider implements PackageTypeProvider { - @Override - public @NonNull PackageURL normalizeComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - return new PackageURL( - type, namespace, StringUtil.toLowerCase(name).replace('_', '-'), version, qualifiers, subpath); - } -} diff --git a/src/main/java/com/github/packageurl/type/QpkgPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/QpkgPackageTypeProvider.java deleted file mode 100644 index 6f3d5548..00000000 --- a/src/main/java/com/github/packageurl/type/QpkgPackageTypeProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -public class QpkgPackageTypeProvider extends LowercaseNamespacePackageTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/RpmPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/RpmPackageTypeProvider.java deleted file mode 100644 index 89eca6ba..00000000 --- a/src/main/java/com/github/packageurl/type/RpmPackageTypeProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -public class RpmPackageTypeProvider extends LowercaseNamespacePackageTypeProvider {} diff --git a/src/main/java/com/github/packageurl/type/SwiftPackageTypeProvider.java b/src/main/java/com/github/packageurl/type/SwiftPackageTypeProvider.java deleted file mode 100644 index ec68bdbc..00000000 --- a/src/main/java/com/github/packageurl/type/SwiftPackageTypeProvider.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.packageurl.type; - -import com.github.packageurl.MalformedPackageURLException; -import java.util.Map; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -public class SwiftPackageTypeProvider implements PackageTypeProvider { - @Override - public void validateComponents( - @NonNull String type, - @Nullable String namespace, - @Nullable String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - if (namespace == null || namespace.isEmpty()) { - throw new MalformedPackageURLException("invalid swift purl without namespace"); - } - - if (version == null || version.isEmpty()) { - throw new MalformedPackageURLException("invalid swift purl without version"); - } - } -} diff --git a/src/main/resources/META-INF/services/com.github.packageurl.spi.PackageTypeProvider b/src/main/resources/META-INF/services/com.github.packageurl.spi.PackageTypeProvider new file mode 100644 index 00000000..a9cf1259 --- /dev/null +++ b/src/main/resources/META-INF/services/com.github.packageurl.spi.PackageTypeProvider @@ -0,0 +1,24 @@ +com.github.packageurl.internal.PackageTypeProviders$ApkPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$BitbucketPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$BitnamiPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$CocoapodsPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$ComposerPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$ConanPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$CpanPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$CranPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$DebPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$GenericPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$GithubPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$GolangPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$HackagePackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$HexPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$HuggingfacePackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$LuarocksPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$MavenPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$MlflowPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$OciPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$PubPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$PypiPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$QpkgPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$RpmPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$SwiftPackageTypeProvider diff --git a/src/main/resources/META-INF/services/com.github.packageurl.type.PackageTypeProvider b/src/main/resources/META-INF/services/com.github.packageurl.type.PackageTypeProvider deleted file mode 100644 index 43b36ad5..00000000 --- a/src/main/resources/META-INF/services/com.github.packageurl.type.PackageTypeProvider +++ /dev/null @@ -1,24 +0,0 @@ -com.github.packageurl.type.ApkPackageTypeProvider -com.github.packageurl.type.BitbucketPackageTypeProvider -com.github.packageurl.type.BitnamiPackageTypeProvider -com.github.packageurl.type.CocoapodsPackageTypeProvider -com.github.packageurl.type.ComposerPackageTypeProvider -com.github.packageurl.type.ConanPackageTypeProvider -com.github.packageurl.type.CpanPackageTypeProvider -com.github.packageurl.type.CranPackageTypeProvider -com.github.packageurl.type.DebPackageTypeProvider -com.github.packageurl.type.GenericPackageTypeProvider -com.github.packageurl.type.GithubPackageTypeProvider -com.github.packageurl.type.GolangPackageTypeProvider -com.github.packageurl.type.HackagePackageTypeProvider -com.github.packageurl.type.HexPackageTypeProvider -com.github.packageurl.type.HuggingfacePackageTypeProvider -com.github.packageurl.type.LuarocksPackageTypeProvider -com.github.packageurl.type.MavenPackageTypeProvider -com.github.packageurl.type.MlflowPackageTypeProvider -com.github.packageurl.type.OciPackageTypeProvider -com.github.packageurl.type.PubPackageTypeProvider -com.github.packageurl.type.PypiPackageTypeProvider -com.github.packageurl.type.QpkgPackageTypeProvider -com.github.packageurl.type.RpmPackageTypeProvider -com.github.packageurl.type.SwiftPackageTypeProvider From ad05c2d54c1d04728ef6d5f7efdd3b55fe3150ca Mon Sep 17 00:00:00 2001 From: David Walluck Date: Thu, 27 Mar 2025 15:30:28 +0100 Subject: [PATCH 03/11] Rename inner classes --- .../internal/PackageTypeProviders.java | 66 +++++++------------ ....github.packageurl.spi.PackageTypeProvider | 48 +++++++------- 2 files changed, 48 insertions(+), 66 deletions(-) diff --git a/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java b/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java index 5d5008f5..a3aec2a3 100644 --- a/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java +++ b/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java @@ -16,16 +16,16 @@ public final class PackageTypeProviders { private PackageTypeProviders() {} @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class ApkPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} + public static class Apk extends LowercaseNamespaceAndNameTypeProvider {} @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class BitbucketPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} + public static class Bitbucket extends LowercaseNamespaceAndNameTypeProvider {} @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class BitnamiPackageTypeProvider extends LowercaseNamespacePackageTypeProvider {} + public static class Bitnami extends LowercaseNamespacePackageTypeProvider {} @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class CocoapodsPackageTypeProvider implements PackageTypeProvider { + public static class Cocoapods implements PackageTypeProvider { @Override public void validateComponents( @NonNull String type, @@ -46,10 +46,10 @@ public void validateComponents( } @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class ComposerPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} + public static class Composer extends LowercaseNamespaceAndNameTypeProvider {} @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class ConanPackageTypeProvider implements PackageTypeProvider { + public static class Conan implements PackageTypeProvider { @Override public void validateComponents( @NonNull String type, @@ -70,7 +70,7 @@ public void validateComponents( } @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class CpanPackageTypeProvider implements PackageTypeProvider { + public static class Cpan implements PackageTypeProvider { @Override public void validateComponents( @NonNull String type, @@ -89,7 +89,7 @@ public void validateComponents( } @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class CranPackageTypeProvider implements PackageTypeProvider { + public static class Cran implements PackageTypeProvider { @Override public void validateComponents( @NonNull String type, @@ -106,19 +106,19 @@ public void validateComponents( } @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class DebPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} + public static class Deb extends LowercaseNamespaceAndNameTypeProvider {} @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class GenericPackageTypeProvider implements PackageTypeProvider {} + public static class Generic implements PackageTypeProvider {} @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class GithubPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} + public static class Github extends LowercaseNamespaceAndNameTypeProvider {} @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class GolangPackageTypeProvider extends LowercaseNamespacePackageTypeProvider {} + public static class Golang extends LowercaseNamespacePackageTypeProvider {} @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class HackagePackageTypeProvider implements PackageTypeProvider { + public static class Hackage implements PackageTypeProvider { @Override public void validateComponents( @NonNull String type, @@ -135,16 +135,16 @@ public void validateComponents( } @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class HexPackageTypeProvider extends LowercaseNamespaceAndNameTypeProvider {} + public static class Hex extends LowercaseNamespaceAndNameTypeProvider {} @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class HuggingfacePackageTypeProvider extends LowercaseVersionPackageTypeProvider {} + public static class Huggingface extends LowercaseVersionPackageTypeProvider {} @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class LuarocksPackageTypeProvider extends LowercaseVersionPackageTypeProvider {} + public static class Luarocks extends LowercaseVersionPackageTypeProvider {} @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class MavenPackageTypeProvider implements PackageTypeProvider { + public static class Maven implements PackageTypeProvider { @Override public void validateComponents( @NonNull String type, @@ -161,7 +161,7 @@ public void validateComponents( } @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class MlflowPackageTypeProvider implements PackageTypeProvider { + public static class Mlflow implements PackageTypeProvider { private static @Nullable String normalizeName(@Nullable String name, @Nullable Map qualifiers) throws MalformedPackageURLException { if (qualifiers != null) { @@ -215,7 +215,7 @@ public void validateComponents( } @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class OciPackageTypeProvider implements PackageTypeProvider { + public static class Oci extends LowercaseNameAndVersionPackageTypeProvider { @Override public void validateComponents( @NonNull String type, @@ -229,31 +229,13 @@ public void validateComponents( throw new MalformedPackageURLException("a namespace is not allowed for type '" + type + "'"); } } - - @Override - public @NonNull PackageURL normalizeComponents( - @NonNull String type, - @Nullable String namespace, - @NonNull String name, - @Nullable String version, - @Nullable Map qualifiers, - @Nullable String subpath) - throws MalformedPackageURLException { - return new PackageURL( - type, - namespace, - StringUtil.toLowerCase(name), - version != null ? StringUtil.toLowerCase(version) : null, - qualifiers, - subpath); - } } @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class PubPackageTypeProvider extends LowercaseNamePackageTypeProvider {} + public static class Pub extends LowercaseNamePackageTypeProvider {} @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class PypiPackageTypeProvider implements PackageTypeProvider { + public static class Pypi implements PackageTypeProvider { @Override public @NonNull PackageURL normalizeComponents( @NonNull String type, @@ -269,13 +251,13 @@ public static class PypiPackageTypeProvider implements PackageTypeProvider { } @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class QpkgPackageTypeProvider extends LowercaseNamespacePackageTypeProvider {} + public static class Qpkg extends LowercaseNamespacePackageTypeProvider {} @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class RpmPackageTypeProvider extends LowercaseNamespacePackageTypeProvider {} + public static class Rpm extends LowercaseNamespacePackageTypeProvider {} @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) - public static class SwiftPackageTypeProvider implements PackageTypeProvider { + public static class Swift implements PackageTypeProvider { @Override public void validateComponents( @NonNull String type, diff --git a/src/main/resources/META-INF/services/com.github.packageurl.spi.PackageTypeProvider b/src/main/resources/META-INF/services/com.github.packageurl.spi.PackageTypeProvider index a9cf1259..1c4e86d2 100644 --- a/src/main/resources/META-INF/services/com.github.packageurl.spi.PackageTypeProvider +++ b/src/main/resources/META-INF/services/com.github.packageurl.spi.PackageTypeProvider @@ -1,24 +1,24 @@ -com.github.packageurl.internal.PackageTypeProviders$ApkPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$BitbucketPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$BitnamiPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$CocoapodsPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$ComposerPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$ConanPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$CpanPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$CranPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$DebPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$GenericPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$GithubPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$GolangPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$HackagePackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$HexPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$HuggingfacePackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$LuarocksPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$MavenPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$MlflowPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$OciPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$PubPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$PypiPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$QpkgPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$RpmPackageTypeProvider -com.github.packageurl.internal.PackageTypeProviders$SwiftPackageTypeProvider +com.github.packageurl.internal.PackageTypeProviders$Apk +com.github.packageurl.internal.PackageTypeProviders$Bitbucket +com.github.packageurl.internal.PackageTypeProviders$Bitnami +com.github.packageurl.internal.PackageTypeProviders$Cocoapods +com.github.packageurl.internal.PackageTypeProviders$Composer +com.github.packageurl.internal.PackageTypeProviders$Conan +com.github.packageurl.internal.PackageTypeProviders$Cpan +com.github.packageurl.internal.PackageTypeProviders$Cran +com.github.packageurl.internal.PackageTypeProviders$Deb +com.github.packageurl.internal.PackageTypeProviders$Generic +com.github.packageurl.internal.PackageTypeProviders$Github +com.github.packageurl.internal.PackageTypeProviders$Golang +com.github.packageurl.internal.PackageTypeProviders$Hackage +com.github.packageurl.internal.PackageTypeProviders$Hex +com.github.packageurl.internal.PackageTypeProviders$Huggingface +com.github.packageurl.internal.PackageTypeProviders$Luarocks +com.github.packageurl.internal.PackageTypeProviders$Maven +com.github.packageurl.internal.PackageTypeProviders$Mlflow +com.github.packageurl.internal.PackageTypeProviders$Oci +com.github.packageurl.internal.PackageTypeProviders$Pub +com.github.packageurl.internal.PackageTypeProviders$Pypi +com.github.packageurl.internal.PackageTypeProviders$Qpkg +com.github.packageurl.internal.PackageTypeProviders$Rpm +com.github.packageurl.internal.PackageTypeProviders$Swift From 4502dfdc54428063a61075119c6e0c69d868b384 Mon Sep 17 00:00:00 2001 From: David Walluck Date: Thu, 27 Mar 2025 15:34:16 +0100 Subject: [PATCH 04/11] Update `getPackageType` for new names --- .../com/github/packageurl/PackageURL.java | 2 +- .../internal/PackageTypeFactory.java | 9 ++-- .../internal/PackageTypeProviders.java | 42 ++++++++++++++++--- .../packageurl/spi/PackageTypeProvider.java | 12 +----- 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/github/packageurl/PackageURL.java b/src/main/java/com/github/packageurl/PackageURL.java index b8a81ca5..127a95bc 100644 --- a/src/main/java/com/github/packageurl/PackageURL.java +++ b/src/main/java/com/github/packageurl/PackageURL.java @@ -23,8 +23,8 @@ import static java.util.Objects.requireNonNull; -import com.github.packageurl.internal.StringUtil; import com.github.packageurl.internal.PackageTypeFactory; +import com.github.packageurl.internal.StringUtil; import java.io.Serializable; import java.net.URI; import java.net.URISyntaxException; diff --git a/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java b/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java index 77a07414..aab57964 100644 --- a/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java +++ b/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java @@ -24,7 +24,7 @@ import aQute.bnd.annotation.spi.ServiceConsumer; import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; - +import com.github.packageurl.spi.PackageTypeProvider; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; @@ -35,13 +35,14 @@ import java.util.ServiceLoader; import java.util.Set; import java.util.TreeMap; - -import com.github.packageurl.spi.PackageTypeProvider; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.osgi.annotation.bundle.Requirement; -@ServiceConsumer(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY, cardinality = Requirement.Cardinality.MULTIPLE) +@ServiceConsumer( + value = PackageTypeProvider.class, + resolution = Requirement.Resolution.MANDATORY, + cardinality = Requirement.Cardinality.MULTIPLE) public final class PackageTypeFactory implements PackageTypeProvider { private static final @NonNull PackageTypeFactory INSTANCE = new PackageTypeFactory(); diff --git a/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java b/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java index a3aec2a3..bda855d3 100644 --- a/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java +++ b/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java @@ -1,16 +1,36 @@ +/* + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ package com.github.packageurl.internal; import aQute.bnd.annotation.spi.ServiceProvider; import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; import com.github.packageurl.spi.PackageTypeProvider; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; -import org.osgi.annotation.bundle.Requirement; - import java.net.URI; import java.net.URISyntaxException; import java.util.Map; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.osgi.annotation.bundle.Requirement; public final class PackageTypeProviders { private PackageTypeProviders() {} @@ -342,7 +362,12 @@ public static class LowercaseNamespacePackageTypeProvider implements PackageType @Nullable String subpath) throws MalformedPackageURLException { return new PackageURL( - type, namespace != null ? StringUtil.toLowerCase(namespace) : null, name, version, qualifiers, subpath); + type, + namespace != null ? StringUtil.toLowerCase(namespace) : null, + name, + version, + qualifiers, + subpath); } } @@ -357,7 +382,12 @@ public static class LowercaseVersionPackageTypeProvider implements PackageTypePr @Nullable String subpath) throws MalformedPackageURLException { return new PackageURL( - type, namespace, name, version != null ? StringUtil.toLowerCase(version) : null, qualifiers, subpath); + type, + namespace, + name, + version != null ? StringUtil.toLowerCase(version) : null, + qualifiers, + subpath); } } } diff --git a/src/main/java/com/github/packageurl/spi/PackageTypeProvider.java b/src/main/java/com/github/packageurl/spi/PackageTypeProvider.java index c3a09ff9..1fc02da9 100644 --- a/src/main/java/com/github/packageurl/spi/PackageTypeProvider.java +++ b/src/main/java/com/github/packageurl/spi/PackageTypeProvider.java @@ -51,15 +51,7 @@ default void validateComponents( } default @NonNull String getPackageType() { - String simpleName = getClass().getSimpleName(); - String suffix = PackageTypeProvider.class.getSimpleName(); - int index = simpleName.lastIndexOf(suffix); - - if (index <= 0 || index != (simpleName.length() - suffix.length())) { - throw new IllegalArgumentException("Invalid class name for package type provider '" + simpleName + "'"); - } - - String type = StringUtil.toLowerCase(simpleName.substring(0, index)); + String type = StringUtil.toLowerCase(getClass().getSimpleName()); try { PackageTypeFactory.validateType(type); @@ -68,6 +60,6 @@ default void validateComponents( "Package type provider name '" + type + "' is not a valid package type", e); } - return StringUtil.toLowerCase(type); + return type; } } From 7909ee185ca8531bde13a18eb954a764f738d2cb Mon Sep 17 00:00:00 2001 From: David Walluck Date: Thu, 27 Mar 2025 15:39:58 +0100 Subject: [PATCH 05/11] Add `@Export` --- src/main/java/com/github/packageurl/spi/package-info.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/github/packageurl/spi/package-info.java b/src/main/java/com/github/packageurl/spi/package-info.java index 3befeecf..f956b891 100644 --- a/src/main/java/com/github/packageurl/spi/package-info.java +++ b/src/main/java/com/github/packageurl/spi/package-info.java @@ -23,7 +23,9 @@ *

Java implementation of the Package-URL Specification SPI for PURL types.

*

https://raw.githubusercontent.com/package-url/purl-spec/refs/heads/main/PURL-TYPES.rst

*/ +@Export @NullMarked package com.github.packageurl.spi; import org.jspecify.annotations.NullMarked; +import org.osgi.annotation.bundle.Export; From 2e8625c2661ebd0c7d265850ac3de133eddc3403 Mon Sep 17 00:00:00 2001 From: David Walluck Date: Thu, 27 Mar 2025 15:49:42 +0100 Subject: [PATCH 06/11] Call normalize or type-specific validations will not run --- src/test/java/com/github/packageurl/PackageURLTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/github/packageurl/PackageURLTest.java b/src/test/java/com/github/packageurl/PackageURLTest.java index b5a75696..7615e946 100644 --- a/src/test/java/com/github/packageurl/PackageURLTest.java +++ b/src/test/java/com/github/packageurl/PackageURLTest.java @@ -376,7 +376,7 @@ void npmCaseSensitive() throws Exception { "pkg:swift/github.com/Alamofire/Alamofire@5.4.3", "pkg:swift/github.com/RxSwiftCommunity/RxFlow@2.12.4" }) - void parseValidTypes(String purl) { - assertDoesNotThrow(() -> new PackageURL(purl)); + void parseValidTypes(final String purl) { + assertDoesNotThrow(() -> new PackageURL(purl).normalize()); } } From 13730fbc3f8dfe410880351ad4f94f8697e26a64 Mon Sep 17 00:00:00 2001 From: David Walluck Date: Tue, 1 Apr 2025 10:25:09 -0400 Subject: [PATCH 07/11] Add id for developer --- pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2cdf04e4..aec51628 100644 --- a/pom.xml +++ b/pom.xml @@ -43,10 +43,11 @@ + steve.springett Steve Springett Steve.Springett@owasp.org OWASP - http://www.owasp.org/ + https://www.owasp.org/ Architect Developer From d7175c9224d0a39a20f72be0926ea59e83fee514 Mon Sep 17 00:00:00 2001 From: David Walluck Date: Tue, 1 Apr 2025 10:25:26 -0400 Subject: [PATCH 08/11] Improve imports --- .../internal/PackageTypeFactory.java | 7 +-- .../internal/PackageTypeProviders.java | 50 +++++++++---------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java b/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java index aab57964..ed4ac8e3 100644 --- a/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java +++ b/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java @@ -37,12 +37,13 @@ import java.util.TreeMap; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; -import org.osgi.annotation.bundle.Requirement; +import org.osgi.annotation.bundle.Requirement.Cardinality; +import org.osgi.annotation.bundle.Requirement.Resolution; @ServiceConsumer( value = PackageTypeProvider.class, - resolution = Requirement.Resolution.MANDATORY, - cardinality = Requirement.Cardinality.MULTIPLE) + resolution = Resolution.MANDATORY, + cardinality = Cardinality.MULTIPLE) public final class PackageTypeFactory implements PackageTypeProvider { private static final @NonNull PackageTypeFactory INSTANCE = new PackageTypeFactory(); diff --git a/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java b/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java index bda855d3..e6551013 100644 --- a/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java +++ b/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java @@ -30,21 +30,21 @@ import java.util.Map; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; -import org.osgi.annotation.bundle.Requirement; +import org.osgi.annotation.bundle.Requirement.Resolution; public final class PackageTypeProviders { private PackageTypeProviders() {} - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Apk extends LowercaseNamespaceAndNameTypeProvider {} - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Bitbucket extends LowercaseNamespaceAndNameTypeProvider {} - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Bitnami extends LowercaseNamespacePackageTypeProvider {} - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Cocoapods implements PackageTypeProvider { @Override public void validateComponents( @@ -65,10 +65,10 @@ public void validateComponents( } } - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Composer extends LowercaseNamespaceAndNameTypeProvider {} - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Conan implements PackageTypeProvider { @Override public void validateComponents( @@ -89,7 +89,7 @@ public void validateComponents( } } - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Cpan implements PackageTypeProvider { @Override public void validateComponents( @@ -108,7 +108,7 @@ public void validateComponents( } } - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Cran implements PackageTypeProvider { @Override public void validateComponents( @@ -125,19 +125,19 @@ public void validateComponents( } } - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Deb extends LowercaseNamespaceAndNameTypeProvider {} - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Generic implements PackageTypeProvider {} - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Github extends LowercaseNamespaceAndNameTypeProvider {} - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Golang extends LowercaseNamespacePackageTypeProvider {} - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Hackage implements PackageTypeProvider { @Override public void validateComponents( @@ -154,16 +154,16 @@ public void validateComponents( } } - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Hex extends LowercaseNamespaceAndNameTypeProvider {} - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Huggingface extends LowercaseVersionPackageTypeProvider {} - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Luarocks extends LowercaseVersionPackageTypeProvider {} - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Maven implements PackageTypeProvider { @Override public void validateComponents( @@ -180,7 +180,7 @@ public void validateComponents( } } - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Mlflow implements PackageTypeProvider { private static @Nullable String normalizeName(@Nullable String name, @Nullable Map qualifiers) throws MalformedPackageURLException { @@ -234,7 +234,7 @@ public void validateComponents( } } - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Oci extends LowercaseNameAndVersionPackageTypeProvider { @Override public void validateComponents( @@ -251,10 +251,10 @@ public void validateComponents( } } - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Pub extends LowercaseNamePackageTypeProvider {} - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Pypi implements PackageTypeProvider { @Override public @NonNull PackageURL normalizeComponents( @@ -270,13 +270,13 @@ public static class Pypi implements PackageTypeProvider { } } - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Qpkg extends LowercaseNamespacePackageTypeProvider {} - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Rpm extends LowercaseNamespacePackageTypeProvider {} - @ServiceProvider(value = PackageTypeProvider.class, resolution = Requirement.Resolution.MANDATORY) + @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Swift implements PackageTypeProvider { @Override public void validateComponents( From 2e7fdec439bea8a3f7c8eb610d75785107b2cade Mon Sep 17 00:00:00 2001 From: David Walluck Date: Wed, 2 Apr 2025 09:00:03 -0400 Subject: [PATCH 09/11] Remove unused method --- .../java/com/github/packageurl/PackageURL.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/main/java/com/github/packageurl/PackageURL.java b/src/main/java/com/github/packageurl/PackageURL.java index aab2b437..133b3532 100644 --- a/src/main/java/com/github/packageurl/PackageURL.java +++ b/src/main/java/com/github/packageurl/PackageURL.java @@ -583,22 +583,6 @@ private String canonicalize(boolean coordinatesOnly) { return purl.toString(); } - /** - * Some purl types may have specific constraints. This method attempts to verify them. - * @param type the purl type - * @param namespace the purl namespace - * @throws MalformedPackageURLException if constraints are not met - */ - private static void verifyTypeConstraints(String type, @Nullable String namespace, @Nullable String name) - throws MalformedPackageURLException { - if (StandardTypes.MAVEN.equals(type)) { - if (isEmpty(namespace) || isEmpty(name)) { - throw new MalformedPackageURLException( - "The PackageURL specified is invalid. Maven requires both a namespace and name."); - } - } - } - private static @Nullable Map parseQualifiers(final @Nullable Map qualifiers) throws MalformedPackageURLException { if (qualifiers == null || qualifiers.isEmpty()) { From bce744b28f091c1b9d2175c8ded9b918e42be1fd Mon Sep 17 00:00:00 2001 From: David Walluck Date: Tue, 8 Apr 2025 08:43:06 -0400 Subject: [PATCH 10/11] Import the correct classes --- .../com/github/packageurl/internal/PackageTypeFactory.java | 4 ++-- .../com/github/packageurl/internal/PackageTypeProviders.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java b/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java index ed4ac8e3..f9727d50 100644 --- a/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java +++ b/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java @@ -21,6 +21,8 @@ */ package com.github.packageurl.internal; +import aQute.bnd.annotation.Cardinality; +import aQute.bnd.annotation.Resolution; import aQute.bnd.annotation.spi.ServiceConsumer; import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; @@ -37,8 +39,6 @@ import java.util.TreeMap; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; -import org.osgi.annotation.bundle.Requirement.Cardinality; -import org.osgi.annotation.bundle.Requirement.Resolution; @ServiceConsumer( value = PackageTypeProvider.class, diff --git a/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java b/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java index e6551013..2c1454fa 100644 --- a/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java +++ b/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java @@ -21,6 +21,7 @@ */ package com.github.packageurl.internal; +import aQute.bnd.annotation.Resolution; import aQute.bnd.annotation.spi.ServiceProvider; import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; @@ -30,7 +31,6 @@ import java.util.Map; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; -import org.osgi.annotation.bundle.Requirement.Resolution; public final class PackageTypeProviders { private PackageTypeProviders() {} From 41dc21285b839265e9eafea72a3c7c2b37a281cc Mon Sep 17 00:00:00 2001 From: David Walluck Date: Tue, 8 Apr 2025 09:16:22 -0400 Subject: [PATCH 11/11] Add javadoc and fix one null issue --- .../internal/PackageTypeFactory.java | 25 ++++- .../internal/PackageTypeProviders.java | 96 ++++++++++++++++++- .../packageurl/internal/StringUtil.java | 25 ++--- .../packageurl/spi/PackageTypeProvider.java | 42 ++++++++ 4 files changed, 173 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java b/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java index f9727d50..35a58972 100644 --- a/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java +++ b/src/main/java/com/github/packageurl/internal/PackageTypeFactory.java @@ -40,6 +40,11 @@ import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; +/** + * The PackageTypeFactory is a singleton that provides a way to normalize and validate package URLs. + * It uses the ServiceLoader mechanism to load available PackageTypeProvider implementations. + * This class is not intended to be instantiated directly. + */ @ServiceConsumer( value = PackageTypeProvider.class, resolution = Resolution.MANDATORY, @@ -47,12 +52,17 @@ public final class PackageTypeFactory implements PackageTypeProvider { private static final @NonNull PackageTypeFactory INSTANCE = new PackageTypeFactory(); - public static final @NonNull String TYPE = "__packagetypefactory__"; + private static final @NonNull String TYPE = "__packagetypefactory__"; private @Nullable Map<@NonNull String, @NonNull PackageTypeProvider> packageTypeProviders; private PackageTypeFactory() {} + /** + * Returns the singleton instance of PackageTypeFactory. + * + * @return the singleton instance of PackageTypeFactory + */ public static @NonNull PackageTypeFactory getInstance() { return INSTANCE; } @@ -116,6 +126,13 @@ private static void validateQualifiers(@Nullable Map qualifiers) } } + /** + * Validates the type of the package URL. The type must start with an alphabetic character and + * can only contain alphanumeric characters, underscores, and hyphens. + * + * @param type the type of the package URL + * @throws MalformedPackageURLException if the type is invalid + */ public static void validateType(@NonNull String type) throws MalformedPackageURLException { if (type.isEmpty()) { throw new MalformedPackageURLException("a type is always required"); @@ -207,6 +224,12 @@ public void validateComponents( }); } + /** + * Returns a map of available package type providers. The map is unmodifiable and contains the + * package type as the key and the corresponding PackageTypeProvider as the value. + * + * @return a map of available package type providers + */ public @NonNull Map getPackageTypeProviders() { if (packageTypeProviders == null) { packageTypeProviders = findAvailablePackageTypeProviders(); diff --git a/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java b/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java index 2c1454fa..4fd31aee 100644 --- a/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java +++ b/src/main/java/com/github/packageurl/internal/PackageTypeProviders.java @@ -32,18 +32,35 @@ import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; +/** + * This class provides a set of package type providers for different package types. + * Each provider implements the PackageTypeProvider interface and provides its own + * validation and normalization logic for the components of a package URL. + */ public final class PackageTypeProviders { private PackageTypeProviders() {} + /** + * This class provides a package type provider for the "apk" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Apk extends LowercaseNamespaceAndNameTypeProvider {} + /** + * This class provides a package type provider for the "bitbucket" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Bitbucket extends LowercaseNamespaceAndNameTypeProvider {} + /** + * This class provides a package type provider for the "bitnami" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Bitnami extends LowercaseNamespacePackageTypeProvider {} + /** + * This class provides a package type provider for the "cocoapods" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Cocoapods implements PackageTypeProvider { @Override @@ -65,9 +82,15 @@ public void validateComponents( } } + /** + * This class provides a package type provider for the "composer" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Composer extends LowercaseNamespaceAndNameTypeProvider {} + /** + * This class provides a package type provider for the "conan" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Conan implements PackageTypeProvider { @Override @@ -89,6 +112,9 @@ public void validateComponents( } } + /** + * This class provides a package type provider for the "cpan" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Cpan implements PackageTypeProvider { @Override @@ -108,6 +134,9 @@ public void validateComponents( } } + /** + * This class provides a package type provider for the "cran" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Cran implements PackageTypeProvider { @Override @@ -125,18 +154,33 @@ public void validateComponents( } } + /** + * This class provides a package type provider for the "deb" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Deb extends LowercaseNamespaceAndNameTypeProvider {} + /** + * This class provides a package type provider for the "generic" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Generic implements PackageTypeProvider {} + /** + * This class provides a package type provider for the "github" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Github extends LowercaseNamespaceAndNameTypeProvider {} + /** + * This class provides a package type provider for the "golang" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Golang extends LowercaseNamespacePackageTypeProvider {} + /** + * This class provides a package type provider for the "hackage" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Hackage implements PackageTypeProvider { @Override @@ -154,15 +198,27 @@ public void validateComponents( } } + /** + * This class provides a package type provider for the "hex" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Hex extends LowercaseNamespaceAndNameTypeProvider {} + /** + * This class provides a package type provider for the "huggingface" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Huggingface extends LowercaseVersionPackageTypeProvider {} + /** + * This class provides a package type provider for the "luarocks" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Luarocks extends LowercaseVersionPackageTypeProvider {} + /** + * This class provides a package type provider for the "maven" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Maven implements PackageTypeProvider { @Override @@ -180,9 +236,12 @@ public void validateComponents( } } + /** + * This class provides a package type provider for the "mlflow" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Mlflow implements PackageTypeProvider { - private static @Nullable String normalizeName(@Nullable String name, @Nullable Map qualifiers) + private static @NonNull String normalizeName(@NonNull String name, @Nullable Map qualifiers) throws MalformedPackageURLException { if (qualifiers != null) { String repositoryUrl = qualifiers.get("repository_url"); @@ -194,7 +253,7 @@ public static class Mlflow implements PackageTypeProvider { URI url = new URI(repositoryUrl); host = url.getHost(); - if (name != null && host.matches(".*[.]?azuredatabricks.net$")) { + if (host.matches(".*[.]?azuredatabricks.net$")) { return StringUtil.toLowerCase(name); } } catch (URISyntaxException e) { @@ -234,6 +293,9 @@ public void validateComponents( } } + /** + * This class provides a package type provider for the "oci" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Oci extends LowercaseNameAndVersionPackageTypeProvider { @Override @@ -251,9 +313,15 @@ public void validateComponents( } } + /** + * This class provides a package type provider for the "pub" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Pub extends LowercaseNamePackageTypeProvider {} + /** + * This class provides a package type provider for the "pypi" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Pypi implements PackageTypeProvider { @Override @@ -270,12 +338,21 @@ public static class Pypi implements PackageTypeProvider { } } + /** + * This class provides a package type provider for the "qpkg" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Qpkg extends LowercaseNamespacePackageTypeProvider {} + /** + * This class provides a package type provider for the "rpm" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Rpm extends LowercaseNamespacePackageTypeProvider {} + /** + * This class provides a package type provider for the "swift" package type. + */ @ServiceProvider(value = PackageTypeProvider.class, resolution = Resolution.MANDATORY) public static class Swift implements PackageTypeProvider { @Override @@ -297,6 +374,9 @@ public void validateComponents( } } + /** + * This class provides a common interface for the lowercase name and version package types. + */ public static class LowercaseNameAndVersionPackageTypeProvider implements PackageTypeProvider { @Override public @NonNull PackageURL normalizeComponents( @@ -317,6 +397,9 @@ public static class LowercaseNameAndVersionPackageTypeProvider implements Packag } } + /** + * This class provides a common interface for the lowercase name package types. + */ public static class LowercaseNamePackageTypeProvider implements PackageTypeProvider { @Override public @NonNull PackageURL normalizeComponents( @@ -331,6 +414,9 @@ public static class LowercaseNamePackageTypeProvider implements PackageTypeProvi } } + /** + * This class provides a common interface for the lowercase namespace and name package types. + */ public static class LowercaseNamespaceAndNameTypeProvider implements PackageTypeProvider { @Override public @NonNull PackageURL normalizeComponents( @@ -351,6 +437,9 @@ public static class LowercaseNamespaceAndNameTypeProvider implements PackageType } } + /** + * This class provides a common interface for the lowercase namespace package types. + */ public static class LowercaseNamespacePackageTypeProvider implements PackageTypeProvider { @Override public @NonNull PackageURL normalizeComponents( @@ -371,6 +460,9 @@ public static class LowercaseNamespacePackageTypeProvider implements PackageType } } + /** + * This class provides a common interface for the lowercase version package types. + */ public static class LowercaseVersionPackageTypeProvider implements PackageTypeProvider { @Override public @NonNull PackageURL normalizeComponents( diff --git a/src/main/java/com/github/packageurl/internal/StringUtil.java b/src/main/java/com/github/packageurl/internal/StringUtil.java index bfc1dee6..e61da2d9 100644 --- a/src/main/java/com/github/packageurl/internal/StringUtil.java +++ b/src/main/java/com/github/packageurl/internal/StringUtil.java @@ -77,8 +77,6 @@ private StringUtil() { * * @param s the string to convert to lower case * @return the lower case version of the string - * - * @since 2.0.0 */ public static @NonNull String toLowerCase(@NonNull String s) { int pos = indexOfFirstUpperCaseChar(s); @@ -101,8 +99,6 @@ private StringUtil() { * * @param source the string to decode * @return the percent decoded string - * - * @since 2.0.0 */ public static @NonNull String percentDecode(@NonNull final String source) { if (source.indexOf(PERCENT_CHAR) == -1) { @@ -132,8 +128,6 @@ private StringUtil() { * * @param source the string to encode * @return the percent encoded string - * - * @since 2.0.0 */ public static @NonNull String percentEncode(@NonNull final String source) { if (!shouldEncode(source)) { @@ -162,8 +156,6 @@ private StringUtil() { * * @param c the character to check * @return true if the character is a digit; otherwise, false - * - * @since 2.0.0 */ public static boolean isDigit(int c) { return (c >= '0' && c <= '9'); @@ -174,8 +166,6 @@ public static boolean isDigit(int c) { * * @param c the character to check * @return true if the character is valid for the package-url type; otherwise, false - * - * @since 2.0.0 */ public static boolean isValidCharForType(int c) { return (isAlphaNumeric(c) || c == '.' || c == '+' || c == '-'); @@ -186,8 +176,6 @@ public static boolean isValidCharForType(int c) { * * @param c the character to check * @return true if the character is valid for the package-url qualifier key; otherwise, false - * - * @since 2.0.0 */ public static boolean isValidCharForKey(int c) { return (isAlphaNumeric(c) || c == '.' || c == '_' || c == '-'); @@ -225,6 +213,12 @@ private static boolean shouldEncode(String s) { return false; } + /** + * Determines if the character is an ASCII alphabetic character, i.e., a lowercase or uppercase ASCII character. + * + * @param c the character to check + * @return whether the character is an ASCII alphabetic character + */ public static boolean isAlpha(int c) { return (isLowerCase(c) || isUpperCase(c)); } @@ -241,6 +235,13 @@ private static boolean isLowerCase(int c) { return (c >= 'a' && c <= 'z'); } + /** + * Determines if the character is an ASCII whitespace character, i.e., + * one of {@code ['\f', '\t', '\n', '\r', '\v', ' ']}. + * + * @param c the character to check + * @return whether the character is an ASCII whitespace character + */ public static boolean isWhitespace(int c) { if (c < 0 || c >= NBITS) { return false; diff --git a/src/main/java/com/github/packageurl/spi/PackageTypeProvider.java b/src/main/java/com/github/packageurl/spi/PackageTypeProvider.java index 1fc02da9..f9fc9f84 100644 --- a/src/main/java/com/github/packageurl/spi/PackageTypeProvider.java +++ b/src/main/java/com/github/packageurl/spi/PackageTypeProvider.java @@ -29,7 +29,32 @@ import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; +/** + * This interface defines a common interface for package type providers. Each package + * type provider must implement this interface to validate and normalize package URLs. + *

+ * Implementations of this interface are registered as OSGi services. + *

+ * The {@link PackageTypeFactory} class is responsible for loading and managing the available + * package type providers. + * These providers are used to validate and normalize package URLs based on their + * specific type. + * Classes must be added to {@code META-INF/services/com.github.packageurl.spi.PackageTypeProvider} in order for + * {@link java.util.ServiceLoader ServiceLoader} to find them. + * + */ public interface PackageTypeProvider { + /** + * Validates the components of a package URL. + * + * @param type the type of the package + * @param namespace the namespace of the package + * @param name the name of the package + * @param version the version of the package + * @param qualifiers the qualifiers of the package + * @param subpath the subpath of the package + * @throws MalformedPackageURLException if the components are not valid + */ default void validateComponents( @NonNull String type, @Nullable String namespace, @@ -39,6 +64,18 @@ default void validateComponents( @Nullable String subpath) throws MalformedPackageURLException {} + /** + * Normalizes the components of a package URL. + * + * @param type the type of the package + * @param namespace the namespace of the package + * @param name the name of the package + * @param version the version of the package + * @param qualifiers the qualifiers of the package + * @param subpath the subpath of the package + * @return a normalized PackageURL object + * @throws MalformedPackageURLException if the components are not valid + */ default @NonNull PackageURL normalizeComponents( @NonNull String type, @Nullable String namespace, @@ -50,6 +87,11 @@ default void validateComponents( return new PackageURL(type, namespace, name, version, qualifiers, subpath); } + /** + * Returns the package type of this provider. + * + * @return the package type of this provider + */ default @NonNull String getPackageType() { String type = StringUtil.toLowerCase(getClass().getSimpleName());