/* * * * Copyright 2011-2014 the original author or authors. * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * */ package org.springframework.xd.module.support; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.List; import org.springframework.boot.loader.archive.Archive; import org.springframework.boot.loader.util.AsciiBytes; import org.springframework.core.io.ContextResource; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** * Represents a resource as resolved inside a boot {@link org.springframework.boot.loader.archive.Archive}. * * @author Eric Bottard */ public class NestedArchiveResource implements ContextResource{ private final Archive rootArchive; private final Archive nestedArchive; private final String path; public NestedArchiveResource(Archive rootArchive, String path) { Assert.isTrue(path.startsWith("/"), "path '" + path + "' should start with a '/'"); this.rootArchive = rootArchive; this.path = path; this.nestedArchive = maybeLocateNestedArchive(); } private Archive maybeLocateNestedArchive() { final AsciiBytes strippedPath = new AsciiBytes(path.substring(1)); try { List<Archive> nestedArchives = rootArchive.getNestedArchives(new Archive.EntryFilter() { @Override public boolean matches(Archive.Entry entry) { return entry.getName().equals(strippedPath); } }); Assert.isTrue(nestedArchives.size() <= 1, "More than 1 entry matched " + path + " : " + nestedArchives); return nestedArchives.size() == 1 ? nestedArchives.get(0) : null; } catch (IOException e) { throw new RuntimeException(e); } } @Override public String getPathWithinContext() { return path; } @Override public boolean exists() { return nestedArchive != null; } @Override public boolean isReadable() { return exists(); } @Override public boolean isOpen() { return false; } @Override public URL getURL() throws IOException { assertExists(); return nestedArchive.getUrl(); } @Override public URI getURI() throws IOException { assertExists(); try { return nestedArchive.getUrl().toURI(); } catch (URISyntaxException e) { throw new IOException(e); } } @Override public File getFile() throws IOException { assertExists(); return new FileSystemResource(nestedArchive.getUrl().toExternalForm()).getFile(); } @Override public long contentLength() throws IOException { throw new UnsupportedOperationException(); } @Override public long lastModified() throws IOException { throw new UnsupportedOperationException(); } @Override public Resource createRelative(String relativePath) throws IOException { String pathToUse = StringUtils.applyRelativePath(this.path, relativePath); return new NestedArchiveResource(rootArchive, pathToUse); } @Override public String getFilename() { int slash = path.lastIndexOf('/'); return path.substring(slash + 1); } @Override public String getDescription() { return toString(); } @Override public InputStream getInputStream() throws IOException { assertExists(); return nestedArchive.getUrl().openStream(); } private void assertExists() throws IOException { if (nestedArchive == null) { throw new IOException("Nested archive at path " + path + " does not exist"); } } @Override public String toString() { return String.format("%s for archive at %s inside %s", getClass().getSimpleName(), path, rootArchive); } }