001// Generated by delombok at Mon Jan 02 16:27:27 UTC 2023
002package io.cui.tools.io;
003
004import static io.cui.tools.base.Preconditions.checkState;
005import static io.cui.tools.string.MoreStrings.isEmpty;
006import static io.cui.tools.string.MoreStrings.requireNotEmpty;
007import static java.util.Objects.requireNonNull;
008import java.io.IOException;
009import java.io.InputStream;
010import java.net.URL;
011import java.util.Optional;
012import io.cui.tools.lang.SecuritySupport;
013import io.cui.tools.logging.CuiLogger;
014
015/**
016 * Variant of {@link FileLoader} that loads files from the classpath.
017 *
018 * @author Oliver Wolff
019 */
020public class ClassPathLoader implements FileLoader {
021    private static final long serialVersionUID = 9140071059594577808L;
022    private static final CuiLogger log = new CuiLogger(ClassPathLoader.class);
023    private final String normalizedPathName;
024    private final String givenPathName;
025    private final StructuredFilename fileName;
026    private URL url;
027
028    /**
029     * @param pathName must not be null nor empty, may start with the prefix
030     *            {@link FileTypePrefix#CLASSPATH} but not with
031     *            {@link FileTypePrefix#FILE} and contain at least one character despite the prefix.
032     *            On all other cases a {@link IllegalArgumentException} will be
033     *            thrown.
034     */
035    public ClassPathLoader(final String pathName) {
036        requireNonNull(pathName);
037        givenPathName = pathName;
038        normalizedPathName = checkClasspathName(pathName);
039        fileName = new StructuredFilename(FilenameUtils.getName(normalizedPathName));
040    }
041
042    /**
043     * Checks and modifies a given pathName
044     *
045     * @param pathName must not be null nor empty, may start with the prefix
046     *            {@link FileTypePrefix#CLASSPATH} but not with
047     *            {@link FileTypePrefix#FILE} and contain at least one character despite
048     *            the prefix. On all other cases a {@link IllegalArgumentException} will be
049     *            thrown.
050     * @return the normalized pathname without prefix but with a leading '/'
051     */
052    static String checkClasspathName(final String pathName) {
053        requireNotEmpty(pathName);
054        if (FileTypePrefix.FILE.is(pathName)) {
055            throw new IllegalArgumentException("Invalid path name, must start not start with " + FileTypePrefix.FILE + " but was: " + pathName);
056        }
057        String newPathName = pathName;
058        if (FileTypePrefix.CLASSPATH.is(pathName)) {
059            newPathName = FileTypePrefix.CLASSPATH.removePrefix(pathName);
060        }
061        if (isEmpty(newPathName)) {
062            throw new IllegalArgumentException("Filename " + pathName + " is invalid");
063        }
064        if (newPathName.indexOf('/') != 0) {
065            newPathName = '/' + newPathName;
066        }
067        return newPathName;
068    }
069
070    @Override
071    public boolean isReadable() {
072        return null != getURL();
073    }
074
075    @Override
076    public InputStream inputStream() {
077        checkState(isReadable(), "Resource \'{}\' is not readable", givenPathName);
078        try {
079            return getURL().openStream();
080        } catch (IOException e) {
081            throw new IllegalStateException("Unable to load classpath file for " + givenPathName, e);
082        }
083    }
084
085    @Override
086    public boolean isFilesystemLoader() {
087        return false;
088    }
089
090    @Override
091    public URL getURL() {
092        if (null == url) {
093            url = resolveUrl(normalizedPathName);
094        }
095        return url;
096    }
097
098    private static URL resolveUrl(String path) {
099        log.debug("Resolving URL for \'{}\'", path);
100        URL url = ClassPathLoader.class.getResource(path);
101        if (null != url) {
102            log.debug("Resolved \'{}\' from ClassPathLoader.class", path);
103            return url;
104        }
105        Optional<ClassLoader> loader = SecuritySupport.getContextClassLoader();
106        if (loader.isPresent()) {
107            url = loader.get().getResource(path);
108            if (null != url) {
109                log.debug("Resolved \'{}\' from ContextClassLoader", path);
110                return url;
111            }
112        }
113        log.warn("Unable to resolve \'{}\' from classpath", path);
114        return null;
115    }
116
117    @java.lang.Override
118    @java.lang.SuppressWarnings("all")
119    @lombok.Generated
120    public boolean equals(final java.lang.Object o) {
121        if (o == this) return true;
122        if (!(o instanceof ClassPathLoader)) return false;
123        final ClassPathLoader other = (ClassPathLoader) o;
124        if (!other.canEqual((java.lang.Object) this)) return false;
125        final java.lang.Object this$normalizedPathName = this.normalizedPathName;
126        final java.lang.Object other$normalizedPathName = other.normalizedPathName;
127        if (this$normalizedPathName == null ? other$normalizedPathName != null : !this$normalizedPathName.equals(other$normalizedPathName)) return false;
128        return true;
129    }
130
131    @java.lang.SuppressWarnings("all")
132    @lombok.Generated
133    protected boolean canEqual(final java.lang.Object other) {
134        return other instanceof ClassPathLoader;
135    }
136
137    @java.lang.Override
138    @java.lang.SuppressWarnings("all")
139    @lombok.Generated
140    public int hashCode() {
141        final int PRIME = 59;
142        int result = 1;
143        final java.lang.Object $normalizedPathName = this.normalizedPathName;
144        result = result * PRIME + ($normalizedPathName == null ? 43 : $normalizedPathName.hashCode());
145        return result;
146    }
147
148    @java.lang.Override
149    @java.lang.SuppressWarnings("all")
150    @lombok.Generated
151    public java.lang.String toString() {
152        return "ClassPathLoader(normalizedPathName=" + this.normalizedPathName + ", givenPathName=" + this.givenPathName + ", fileName=" + this.getFileName() + ", url=" + this.getURL() + ")";
153    }
154
155    @java.lang.SuppressWarnings("all")
156    @lombok.Generated
157    public StructuredFilename getFileName() {
158        return this.fileName;
159    }
160}