Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #3569 #3572

Merged
merged 11 commits into from
Jul 30, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URI;
import java.nio.file.Path;
import java.util.Optional;

Expand Down Expand Up @@ -48,10 +47,10 @@ public synchronized byte[] readAllBytes() {
}
}

private final URI uri;
protected final String uri;
private URIContentLoader[] fallbackContentLoaders;

protected CachedContentLoader(URI uri, URIContentLoader... fallbackContentLoaders) {
protected CachedContentLoader(String uri, URIContentLoader... fallbackContentLoaders) {
this.uri = uri;
this.fallbackContentLoaders = fallbackContentLoaders;
}
Expand Down Expand Up @@ -91,10 +90,13 @@ public InputStream getInputStream() {
}
}

protected abstract byte[] loadURI(URI uri);

@Override
public URI uri() {
return uri;
protected static String trimScheme(String uri, String scheme) {
fjtirado marked this conversation as resolved.
Show resolved Hide resolved
String str = uri;
if (str.toLowerCase().startsWith(scheme)) {
str = str.substring(scheme.length());
}
return str;
}

protected abstract byte[] loadURI();
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.Optional;

Expand All @@ -34,24 +31,12 @@ public class ClassPathContentLoader extends CachedContentLoader {
private final Optional<URL> resource;
private final String classpath;

ClassPathContentLoader(URI uri, Optional<ClassLoader> cl, URIContentLoader... fallbackContentLoaders) {
ClassPathContentLoader(String uri, Optional<ClassLoader> cl, URIContentLoader... fallbackContentLoaders) {
super(uri, fallbackContentLoaders);
this.classpath = getPath(uri);
this.classpath = uriToPath(uri);
this.resource = Optional.ofNullable(cl.orElse(Thread.currentThread().getContextClassLoader()).getResource(classpath));
}

static String getPath(URI uri) {
final String classPathPrefix = "classpath:";
String str = URLDecoder.decode(uri.toString(), Charset.defaultCharset());
if (str.toLowerCase().startsWith(classPathPrefix)) {
str = str.substring(classPathPrefix.length());
while (str.startsWith("/")) {
str = str.substring(1);
}
}
return str;
}

public Optional<URL> getResource() {
return resource;
}
Expand All @@ -74,7 +59,7 @@ private static Path fromURL(URL url) {
}

@Override
protected byte[] loadURI(URI uri) {
protected byte[] loadURI() {
return resource.map(this::loadBytes).orElseThrow(() -> new IllegalArgumentException("cannot find classpath resource " + classpath));
}

Expand All @@ -86,6 +71,17 @@ private byte[] loadBytes(URL r) {
}
}

static String uriToPath(String uri) {
fjtirado marked this conversation as resolved.
Show resolved Hide resolved
return removeSlash(trimScheme(uri, URIContentLoaderType.CLASSPATH.scheme()));
}

private static String removeSlash(String str) {
while (str.startsWith("/")) {
str = str.substring(1);
}
return str;
}

@Override
public URIContentLoaderType type() {
return URIContentLoaderType.CLASSPATH;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,51 @@
import java.nio.file.Path;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FileContentLoader extends CachedContentLoader {

private final Path path;

FileContentLoader(URI uri, URIContentLoader... fallbackContentLoaders) {
private static final Logger logger = LoggerFactory.getLogger(FileContentLoader.class);

FileContentLoader(String uri, URIContentLoader... fallbackContentLoaders) {
super(uri, fallbackContentLoaders);
this.path = Path.of(getPath(uri));
this.path = obtainPath(uri);
}

@Override
public URIContentLoaderType type() {
return URIContentLoaderType.FILE;
}

private static Path obtainPath(String uri) {
if (uri.startsWith(URIContentLoaderType.FILE.scheme())) {
try {
return Path.of(URI.create(uri));
} catch (Exception ex) {
logger.info("URI {} is not valid one according to Java, trying alternative approach", uri, ex);
}
}
return Path.of(uriToPath(uri));
}

@Override
protected Optional<Path> internalGetPath() {
return Files.exists(path) ? Optional.of(path) : Optional.empty();
}

@Override
protected byte[] loadURI(URI uri) {
protected byte[] loadURI() {
try {
return Files.readAllBytes(path);
} catch (IOException io) {
throw new UncheckedIOException(io);
}
}

static String getPath(URI uri) {
return uri.getPath();
static String uriToPath(String uri) {
return trimScheme(uri, URIContentLoaderType.FILE.scheme());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.Base64;
import java.util.Collection;
import java.util.HashMap;
Expand Down Expand Up @@ -50,17 +51,19 @@ class HttpContentLoader extends CachedContentLoader {

private Optional<Workflow> workflow;
private String authRef;
private final URIContentLoaderType type;

HttpContentLoader(URI uri, Optional<Workflow> workflow, String authRef) {
HttpContentLoader(String uri, Optional<Workflow> workflow, String authRef, URIContentLoaderType type) {
super(uri);
this.workflow = workflow;
this.authRef = authRef;
this.type = type;
}

@Override
protected byte[] loadURI(URI u) {
protected byte[] loadURI() {
try {
HttpURLConnection conn = (HttpURLConnection) u.toURL().openConnection();
HttpURLConnection conn = (HttpURLConnection) new URL(uri).openConnection();
// some http servers required specific accept header (*/* is specified for those we do not care about accept)
conn.setRequestProperty("Accept", "application/json,application/yaml,application/yml,application/text,text/*,*/*");
workflow.map(Workflow::getAuth).map(Auth::getAuthDefs).stream().flatMap(Collection::stream)
Expand All @@ -74,7 +77,7 @@ protected byte[] loadURI(URI u) {
} else {
try (InputStream is = conn.getErrorStream()) {
throw new IllegalArgumentException(String.format(
"Failed to fetch remote file: %s. Status code is %d and response: %n %s", u, code, is == null ? "" : new String(is.readAllBytes())));
"Failed to fetch remote file: %s. Status code is %d and response: %n %s", uri, code, is == null ? "" : new String(is.readAllBytes())));
}
}
} catch (IOException io) {
Expand Down Expand Up @@ -147,6 +150,11 @@ private String encode(String str) {

@Override
public URIContentLoaderType type() {
return URIContentLoaderType.HTTP;
return type;
}

static String uriToPath(String uri) {
return URI.create(uri).getPath();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@
*/
package org.kie.kogito.serverless.workflow.io;

import java.net.URI;
import java.util.function.Function;
import java.util.function.Supplier;

public interface ResourceCache {
byte[] get(URI uri, Function<URI, byte[]> retrieveCall);
byte[] get(String uri, Supplier<byte[]> retrieveCall);
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@
*/
package org.kie.kogito.serverless.workflow.io;

import java.net.URI;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.function.Supplier;

public class ResourceCacheFactory {
private static final AtomicReference<ResourceCache> cache = new AtomicReference<>(new LocalResourceCache());
Expand All @@ -33,11 +32,11 @@ public static ResourceCache getCache() {
}

private static class LocalResourceCache implements ResourceCache {
private final Map<URI, byte[]> map = Collections.synchronizedMap(new WeakHashMap<>());
private final Map<String, byte[]> map = Collections.synchronizedMap(new WeakHashMap<>());

@Override
public byte[] get(URI uri, Function<URI, byte[]> retrieveCall) {
return map.computeIfAbsent(uri, retrieveCall);
public byte[] get(String uri, Supplier<byte[]> retrieveCall) {
return map.computeIfAbsent(uri, u -> retrieveCall.get());
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,11 @@
package org.kie.kogito.serverless.workflow.io;

import java.io.InputStream;
import java.net.URI;
import java.nio.file.Path;
import java.util.Optional;

public interface URIContentLoader {

URI uri();

InputStream getInputStream();

URIContentLoaderType type();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Optional;

import org.kie.kogito.serverless.workflow.parser.ParserContext;
Expand All @@ -51,29 +48,11 @@ public static String readString(URIContentLoader loader) {
return new String(readAllBytes(loader));
}

public static String getFileName(URI uri) {
URIContentLoaderType type = URIContentLoaderType.from(uri);
String path = uriToPath(type, uri);
return type.lastPart(path);
}

private static String uriToPath(URIContentLoaderType type, URI uri) {
switch (type) {
case CLASSPATH:
return ClassPathContentLoader.getPath(uri);
case FILE:
return FileContentLoader.getPath(uri);
case HTTP:
default:
return uri.getPath();
}
}

public static String readString(Builder builder) {
return readString(builder.build());
}

public static URIContentLoader buildLoader(URI uri, Workflow workflow, Optional<ParserContext> context, String authRef) {
public static URIContentLoader buildLoader(String uri, Workflow workflow, Optional<ParserContext> context, String authRef) {
Builder builder = new Builder(uri).withWorkflow(workflow).withAuthRef(authRef);
context.map(c -> c.getContext().getClassLoader()).ifPresent(builder::withClassloader);
getBaseURI(workflow).ifPresent(builder::withBaseURI);
Expand All @@ -85,25 +64,29 @@ public static byte[] readBytes(String uriStr, Workflow workflow, ParserContext p
}

public static byte[] readBytes(String uriStr, Workflow workflow, Optional<ParserContext> parserContext) {
return readAllBytes(buildLoader(URI.create(uriStr), workflow, parserContext, null));
return readAllBytes(buildLoader(uriStr, workflow, parserContext, null));
}

public static Builder builder(URI uri) {
fjtirado marked this conversation as resolved.
Show resolved Hide resolved
return new Builder(uri);
return new Builder(uri.toString());
}

public static Builder builder(String uri) {
return new Builder(URI.create(URLEncoder.encode(uri, Charset.defaultCharset())));
return new Builder(uri);
}

public static class Builder {
private URI uri;
private String uri;
private ClassLoader cl;
private Workflow workflow;
private String authRef;
private URI baseURI;
private String baseURI;

private Builder(URI uri) {
this.uri = uri.toString();
}

private Builder(String uri) {
this.uri = uri;
}

Expand All @@ -122,44 +105,30 @@ public Builder withAuthRef(String authRef) {
return this;
}

public Builder withBaseURI(URI baseURI) {
public Builder withBaseURI(String baseURI) {
this.baseURI = baseURI;
return this;
}

public URIContentLoader build() {
final URI finalURI = baseURI != null ? compoundURI(baseURI, uri) : uri;
final String finalURI = baseURI != null ? compoundURI(baseURI, uri) : uri;
switch (URIContentLoaderType.from(finalURI)) {
default:
case FILE:
return new FileContentLoader(finalURI, new ClassPathContentLoader(uri, Optional.ofNullable(cl)));
case HTTP:
return new HttpContentLoader(finalURI, Optional.ofNullable(workflow), authRef);
return new HttpContentLoader(finalURI, Optional.ofNullable(workflow), authRef, URIContentLoaderType.HTTP);
case HTTPS:
return new HttpContentLoader(finalURI, Optional.ofNullable(workflow), authRef, URIContentLoaderType.HTTPS);
case CLASSPATH:
Optional<ClassLoader> optionalCl = Optional.ofNullable(cl);
return finalURI == uri ? new ClassPathContentLoader(finalURI, optionalCl) : new ClassPathContentLoader(finalURI, optionalCl, new ClassPathContentLoader(uri, optionalCl));
}
}
}

public static URI compoundURI(URI baseURI, URI uri) {
if (uri.getScheme() != null) {
return uri;
}
URIContentLoaderType type = URIContentLoaderType.from(baseURI);
String basePath = type.trimLast(uriToPath(type, baseURI));
String additionalPath = uriToPath(type, uri);
String path;
if (type.isAbsolutePath(additionalPath)) {
path = additionalPath;
} else {
path = type.concat(basePath, additionalPath);
}
try {
return new URI(type.toString().toLowerCase(), baseURI.getAuthority(), path, uri.getQuery(), uri.getFragment());
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
public static String compoundURI(String baseURI, String uri) {
return URIContentLoaderType.scheme(uri).isPresent() ? uri : URIContentLoaderType.from(baseURI).concat(baseURI, uri);
}

private URIContentLoaderFactory() {
Expand Down
Loading
Loading