WebappResourceExtractor.java
/*******************************************************************************
* Copyright (c) 2025 Eclipse RDF4J contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
// Some portions generated by Codex
package org.eclipse.rdf4j.tools.serverboot;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
class WebappResourceExtractor implements AutoCloseable {
private static final String SERVER_WEBAPP_BASE = "rdf4j/server-webapp";
private static final String WORKBENCH_WEBAPP_BASE = "rdf4j/workbench-webapp";
private final Path serverDocBase;
WebappResourceExtractor() {
try {
this.serverDocBase = Files.createTempDirectory("rdf4j-server-webapp");
this.serverDocBase.toFile().deleteOnExit();
copyTree(SERVER_WEBAPP_BASE, serverDocBase);
Path workbenchTarget = serverDocBase.resolve("rdf4j-workbench");
Files.createDirectories(workbenchTarget);
copyTree(WORKBENCH_WEBAPP_BASE, workbenchTarget);
} catch (IOException e) {
throw new IllegalStateException("Failed to prepare web application resources", e);
}
}
Path getServerDocBase() {
return serverDocBase;
}
@Override
public void close() throws Exception {
if (serverDocBase == null) {
return;
}
try (Stream<Path> walk = Files.walk(serverDocBase)) {
walk.sorted((left, right) -> right.compareTo(left)).forEach(path -> {
try {
Files.deleteIfExists(path);
} catch (IOException ignored) {
// best-effort cleanup
}
});
}
}
private static void copyTree(String resourceBase, Path destinationRoot) throws IOException {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(
Rdf4jServerWorkbenchApplication.class.getClassLoader());
Resource[] resources = resolver.getResources("classpath*:" + resourceBase + "/**");
Set<String> copied = new HashSet<>();
for (Resource resource : resources) {
if (!resource.exists() || !resource.isReadable()) {
continue;
}
String url = resource.getURL().toExternalForm();
if (url.endsWith("/")) {
continue;
}
int baseIndex = url.indexOf(resourceBase);
if (baseIndex == -1) {
continue;
}
String relative = url.substring(baseIndex + resourceBase.length());
if (relative.isEmpty() || "/".equals(relative)) {
continue;
}
if (relative.startsWith("/")) {
relative = relative.substring(1);
}
if (!copied.add(relative)) {
continue;
}
Path target = destinationRoot.resolve(relative);
Files.createDirectories(target.getParent());
try (InputStream inputStream = resource.getInputStream()) {
Files.copy(inputStream, target, StandardCopyOption.REPLACE_EXISTING);
}
}
}
}