* listThemeFiles implementation for StaticThemeProvider
* profind method for Themes WebDAV service


git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5435 8810af33-2d31-482b-a856-94f89814c4df
ccm-docs
jensp 2018-05-17 13:19:46 +00:00
parent c615a2124c
commit 6e1b5e3fd6
8 changed files with 194 additions and 28 deletions

View File

@ -28,7 +28,6 @@ import org.reflections.scanners.ResourcesScanner;
import org.reflections.util.ClasspathHelper; import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder; import org.reflections.util.ConfigurationBuilder;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -36,15 +35,13 @@ import java.net.URI;
import java.net.URL; import java.net.URL;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.logging.Level;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -54,6 +51,8 @@ import javax.json.Json;
import javax.json.JsonArray; import javax.json.JsonArray;
import javax.json.JsonObject; import javax.json.JsonObject;
import javax.json.JsonReader; import javax.json.JsonReader;
import javax.json.JsonStructure;
import javax.json.JsonValue;
/** /**
* *
@ -271,7 +270,7 @@ public class StaticThemeProvider implements ThemeProvider {
"The name of the theme can't be empty."); "The name of the theme can't be empty.");
} }
final String[] pathTokens = path.split("/"); final List<String> pathTokens = Arrays.asList(path.split("/"));
final String indexFilePath = String.format("/" final String indexFilePath = String.format("/"
+ THEMES_PACKAGE + THEMES_PACKAGE
@ -281,11 +280,30 @@ public class StaticThemeProvider implements ThemeProvider {
.getResourceAsStream(indexFilePath); .getResourceAsStream(indexFilePath);
final JsonReader reader = Json.createReader(stream); final JsonReader reader = Json.createReader(stream);
final JsonObject indexObj = reader.readObject(); final JsonObject indexObj = reader.readObject();
final JsonArray filesArray = indexObj.getJsonArray("files"); final JsonArray currentDir = indexObj.getJsonArray("files");
filesArray currentDir.forEach(value -> LOGGER.warn(value.toString()));
.forEach(value -> LOGGER.warn(value.toString()));
final Optional<JsonObject> targetFile = findFile(pathTokens,
throw new UnsupportedOperationException(); currentDir);
final List<ThemeFileInfo> result;
if (targetFile.isPresent()) {
if (targetFile.get().getBoolean("isDirectory")) {
final JsonArray files = targetFile.get().getJsonArray("files");
result = files
.stream()
.map(value -> generateFileInfo((JsonObject) value))
.collect(Collectors.toList());
} else {
final ThemeFileInfo fileInfo = generateFileInfo(
targetFile.get());
result = new ArrayList<>();
result.add(fileInfo);
}
} else {
result = Collections.emptyList();
}
return result;
} }
@Override @Override
@ -379,4 +397,59 @@ public class StaticThemeProvider implements ThemeProvider {
return Files.exists(manifestPathJson) || Files.exists(manifestPathXml); return Files.exists(manifestPathJson) || Files.exists(manifestPathXml);
} }
private Optional<JsonObject> findFile(final List<String> path,
final JsonArray currentDirectory) {
Objects.requireNonNull(path);
Objects.requireNonNull(currentDirectory);
if (path.isEmpty()) {
return Optional.empty();
}
final String fileName = path.get(0);
final Optional<JsonObject> fileData = currentDirectory
.stream()
.map(value -> (JsonObject) value)
.filter(value -> filterFileData(value, fileName))
.findAny();
if (path.size() == 1) {
return fileData;
} else {
if (fileData.get().getBoolean("isDirectory")) {
return findFile(path.subList(1, path.size()),
fileData.get().getJsonArray("files"));
} else {
return Optional.empty();
}
}
}
private boolean filterFileData(final JsonObject fileData,
final String fileName) {
return fileData.getString("name").equals(fileName);
}
private ThemeFileInfo generateFileInfo(final JsonObject fileData) {
Objects.requireNonNull(fileData);
final ThemeFileInfo fileInfo = new ThemeFileInfo();
fileInfo.setName(fileData.getString("name"));
if (fileData.getBoolean("isDirectory")) {
fileInfo.setDirectory(true);
} else {
fileInfo.setDirectory(false);
fileInfo.setMimeType(fileData.getString("mimeType"));
}
fileInfo.setWritable(false);
if (fileData.getJsonNumber("size") != null) {
fileInfo.setSize(fileData.getJsonNumber("size").longValue());
}
return fileInfo;
}
} }

View File

@ -41,6 +41,7 @@ import org.libreccm.theming.ThemeInfo;
import org.libreccm.theming.ThemeVersion; import org.libreccm.theming.ThemeVersion;
import org.libreccm.theming.Themes; import org.libreccm.theming.Themes;
import org.libreccm.webdav.ResponseStatus; import org.libreccm.webdav.ResponseStatus;
import org.libreccm.webdav.xml.elements.Collection;
import org.libreccm.webdav.xml.elements.HRef; import org.libreccm.webdav.xml.elements.HRef;
import org.libreccm.webdav.xml.elements.MultiStatus; import org.libreccm.webdav.xml.elements.MultiStatus;
import org.libreccm.webdav.xml.elements.Prop; import org.libreccm.webdav.xml.elements.Prop;
@ -51,11 +52,12 @@ import org.libreccm.webdav.xml.properties.DisplayName;
import org.libreccm.webdav.xml.properties.GetContentLength; import org.libreccm.webdav.xml.properties.GetContentLength;
import org.libreccm.webdav.xml.properties.GetContentType; import org.libreccm.webdav.xml.properties.GetContentType;
import java.util.Collection;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.OPTIONS; import javax.ws.rs.OPTIONS;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
@ -72,6 +74,12 @@ public class ThemeFiles {
@Inject @Inject
private Themes themes; private Themes themes;
@Inject
private ServletContext servletContext;
@Inject
private HttpServletRequest request;
@GET @GET
@Path("/{path}") @Path("/{path}")
public Response getFile(@PathParam("theme") final String theme, public Response getFile(@PathParam("theme") final String theme,
@ -137,10 +145,15 @@ public class ThemeFiles {
final List<ThemeFileInfo> fileInfos = themes.listThemesFiles(themeInfo, final List<ThemeFileInfo> fileInfos = themes.listThemesFiles(themeInfo,
path); path);
final MultiStatus result; final MultiStatus result;
if (fileInfos.size() == 1) { if (fileInfos.isEmpty()) {
throw new NotFoundException(String.format(
"No file \"%s\" in theme \"%s\".",
path,
theme));
} else if (fileInfos.size() == 1) {
final ThemeFileInfo fileInfo = fileInfos.get(0);
final ThemeFileInfo fileInfo = fileInfos.get(1);
result = new MultiStatus(buildWebDavResponse(fileInfo, uriInfo)); result = new MultiStatus(buildWebDavResponse(fileInfo, uriInfo));
} else { } else {
@ -150,7 +163,7 @@ public class ThemeFiles {
null, null,
null, null,
new PropStat(new Prop(new DisplayName(path), new PropStat(new Prop(new DisplayName(path),
org.libreccm.webdav.xml.elements.Collection.COLLECTION), Collection.COLLECTION),
new Status(javax.ws.rs.core.Response.Status.OK))); new Status(javax.ws.rs.core.Response.Status.OK)));
final List<WebDavResponse> responses = new LinkedList<>(); final List<WebDavResponse> responses = new LinkedList<>();
@ -158,13 +171,13 @@ public class ThemeFiles {
final List<WebDavResponse> fileResponses = fileInfos final List<WebDavResponse> fileResponses = fileInfos
.stream() .stream()
.map(fileInfo -> buildWebDavResponse(fileInfo, uriInfo)) .map(fileInfo -> buildWebDavResponse(path, fileInfo))
.collect(Collectors.toList()); .collect(Collectors.toList());
responses.addAll(fileResponses); responses.addAll(fileResponses);
result = new MultiStatus(responses.toArray(new WebDavResponse[]{})); result = new MultiStatus(responses.toArray(new WebDavResponse[]{}));
} }
return Response return Response
.status(ResponseStatus.MULTI_STATUS) .status(ResponseStatus.MULTI_STATUS)
.entity(result) .entity(result)
@ -174,11 +187,18 @@ public class ThemeFiles {
private WebDavResponse buildWebDavResponse(final ThemeFileInfo fileInfo, private WebDavResponse buildWebDavResponse(final ThemeFileInfo fileInfo,
final UriInfo uriInfo) { final UriInfo uriInfo) {
final PropStat propStat = new PropStat( final PropStat propStat;
new Prop(new DisplayName(fileInfo.getName()), if (fileInfo.isDirectory()) {
new GetContentLength(fileInfo.getSize()), propStat = new PropStat(
new GetContentType(fileInfo.getMimeType())), new Prop(new DisplayName(fileInfo.getName())),
new Status(javax.ws.rs.core.Response.Status.OK)); new Status(javax.ws.rs.core.Response.Status.OK));
} else {
propStat = new PropStat(
new Prop(new DisplayName(fileInfo.getName()),
new GetContentLength(fileInfo.getSize()),
new GetContentType(fileInfo.getMimeType())),
new Status(javax.ws.rs.core.Response.Status.OK));
}
final WebDavResponse response = new WebDavResponse( final WebDavResponse response = new WebDavResponse(
new HRef(uriInfo.getRequestUri()), new HRef(uriInfo.getRequestUri()),
@ -189,6 +209,38 @@ public class ThemeFiles {
return response; return response;
} }
private WebDavResponse buildWebDavResponse(final String basePath,
final ThemeFileInfo fileInfo) {
final PropStat propStat;
if (fileInfo.isDirectory()) {
propStat = new PropStat(
new Prop(new DisplayName(fileInfo.getName())),
new Status(javax.ws.rs.core.Response.Status.OK));
} else {
propStat = new PropStat(
new Prop(new DisplayName(fileInfo.getName()),
new GetContentLength(fileInfo.getSize()),
new GetContentType(fileInfo.getMimeType())),
new Status(javax.ws.rs.core.Response.Status.OK));
}
final WebDavResponse response = new WebDavResponse(
new HRef(String.format("%s://%s:%d%s/DAV/themes/%s/%s",
request.getScheme(),
request.getServerName(),
request.getServerPort(),
servletContext.getContextPath(),
basePath,
fileInfo.getName())),
null,
null,
null,
propStat);
return response;
}
private MediaType getMediaTypeFromPath(final String path) { private MediaType getMediaTypeFromPath(final String path) {

View File

@ -18,11 +18,17 @@
*/ */
package org.libreccm.theming.webdav; package org.libreccm.theming.webdav;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.libreccm.core.UnexpectedErrorException;
import org.libreccm.webdav.xml.WebDavContextResolver;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import javax.ws.rs.ApplicationPath; import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application; import javax.ws.rs.core.Application;
import javax.xml.bind.JAXBException;
/** /**
* *
@ -31,6 +37,8 @@ import javax.ws.rs.core.Application;
@ApplicationPath("/DAV/themes") @ApplicationPath("/DAV/themes")
public class WebDAV extends Application { public class WebDAV extends Application {
private static final Logger LOGGER = LogManager.getLogger(WebDAV.class);
@Override @Override
public Set<Class<?>> getClasses() { public Set<Class<?>> getClasses() {
@ -40,4 +48,20 @@ public class WebDAV extends Application {
return classes; return classes;
} }
@Override
public Set<Object> getSingletons() {
LOGGER.warn("Adding singletons...");
final HashSet<Object> singletons = new HashSet<>();
try {
singletons.add(new WebDavContextResolver());
} catch (JAXBException ex) {
throw new UnexpectedErrorException(ex);
}
LOGGER.warn("Added singletons");
return singletons;
}
} }

View File

@ -61,7 +61,7 @@ public final class PropFindFiniteDepth {
// For unmarshalling only. // For unmarshalling only.
} }
private static PropFindFiniteDepth createInstance() { private static PropFindFiniteDepth createSingleton() {
return PROPFIND_FINITE_DEPTH; return PROPFIND_FINITE_DEPTH;
} }

View File

@ -60,6 +60,12 @@ public class WebDavContextResolver implements ContextResolver<JAXBContext> {
private final JAXBIntrospector introspector; private final JAXBIntrospector introspector;
public WebDavContextResolver() throws JAXBException {
this.context = WebDavJAXBContextBuilder.build();
this.introspector = this.context.createJAXBIntrospector();
}
/** /**
* Creates an instance of this resolver, registering the provided custom XML * Creates an instance of this resolver, registering the provided custom XML
* Elements and Properties. * Elements and Properties.

View File

@ -48,6 +48,7 @@ import org.libreccm.webdav.xml.elements.PropStat;
import org.libreccm.webdav.xml.elements.PropertyUpdate; import org.libreccm.webdav.xml.elements.PropertyUpdate;
import org.libreccm.webdav.xml.elements.Remove; import org.libreccm.webdav.xml.elements.Remove;
import org.libreccm.webdav.xml.elements.ResponseDescription; import org.libreccm.webdav.xml.elements.ResponseDescription;
import org.libreccm.webdav.xml.elements.Set;
import org.libreccm.webdav.xml.elements.Shared; import org.libreccm.webdav.xml.elements.Shared;
import org.libreccm.webdav.xml.elements.Status; import org.libreccm.webdav.xml.elements.Status;
import org.libreccm.webdav.xml.elements.TimeOut; import org.libreccm.webdav.xml.elements.TimeOut;
@ -66,9 +67,7 @@ import org.libreccm.webdav.xml.properties.SupportedLock;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Set;
import javax.swing.text.Utilities;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException; import javax.xml.bind.JAXBException;
@ -148,7 +147,8 @@ final class WebDavJAXBContextBuilder {
ResourceType.class, ResourceType.class,
Response.class, Response.class,
ResponseDescription.class, ResponseDescription.class,
Set.class, Shared.class, Set.class,
Shared.class,
Status.class, Status.class,
SupportedLock.class, SupportedLock.class,
TimeOut.class, TimeOut.class,

View File

@ -18,6 +18,9 @@
*/ */
package org.libreccm.webdav.xml.elements; package org.libreccm.webdav.xml.elements;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/** /**
* WebDAV collection XML Element. * WebDAV collection XML Element.
* *
@ -38,6 +41,9 @@ package org.libreccm.webdav.xml.elements;
* Distributed Authoring and Versioning (WebDAV)"</a> * Distributed Authoring and Versioning (WebDAV)"</a>
* *
*/ */
@XmlRootElement
@XmlType(factoryMethod = "createSingleton")
public final class Collection { public final class Collection {
private Collection() { private Collection() {

View File

@ -57,6 +57,11 @@
"mimeType": "text/x-java-properties" "mimeType": "text/x-java-properties"
} }
] ]
},
{
"name": "theme.json",
"isDirectory": false,
"mimeType": "application/json"
} }
] ]
} }