/*
* Copyright 2013 eXo Platform SAS
*
* 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 juzu.impl.fs.spi.war;
import juzu.impl.common.Resource;
import juzu.impl.common.Spliterator;
import juzu.impl.common.Timestamped;
import juzu.impl.fs.spi.PathType;
import juzu.impl.fs.spi.ReadFileSystem;
import juzu.impl.common.Tools;
import javax.portlet.PortletContext;
import javax.servlet.ServletContext;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
/** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */
public abstract class WarFileSystem extends ReadFileSystem<String> {
/** . */
private final String mountPoint;
public WarFileSystem(String mountPoint) throws NullPointerException {
if (mountPoint == null) {
throw new NullPointerException("No null mount point accepted");
}
if (!mountPoint.startsWith("/") || !mountPoint.endsWith("/")) {
throw new IllegalArgumentException("Invalid mount point " + mountPoint);
}
//
this.mountPoint = mountPoint.substring(0, mountPoint.length() - 1);
}
@Override
public Class<String> getType() {
return String.class;
}
@Override
public boolean equals(String left, String right) {
return left.equals(right);
}
@Override
public String getRoot() {
return "/";
}
@Override
public String getName(String path) {
// It's a directory, remove the trailing '/'
if (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
// Get index of last '/'
int index = path.lastIndexOf('/');
// Return name
return path.substring(index + 1);
}
@Override
public Iterable<String> getNames(String path) {
int to = path.length();
if (path.endsWith("/")) {
to--;
}
return Spliterator.split(path, 0, to, '/');
}
@Override
public Iterator<String> getChildren(String dir) throws IOException {
return getResourcePaths(dir).iterator();
}
@Override
public String getChild(String dir, String name) throws IOException {
for (Iterator<String> i = getChildren(dir);i.hasNext();) {
String child = i.next();
String childName = getName(child);
if (childName.equals(name)) {
return child;
}
}
return null;
}
@Override
public PathType typeOf(String path) throws IOException {
if (path.endsWith("/")) {
return PathType.DIR;
} else {
URL url = getResourceURL(path);
if (url != null) {
return PathType.FILE;
} else {
return null;
}
}
}
@Override
public Timestamped<Resource> getResource(String file) throws IOException {
URL url = getResourceURL(file);
if (url != null) {
URLConnection conn = url.openConnection();
long lastModified = conn.getLastModified();
InputStream in = conn.getInputStream();
try {
ByteArrayOutputStream resource = new ByteArrayOutputStream();
byte[] buffer = new byte[256];
for (int l = in.read(buffer);l != -1;l = in.read(buffer)) {
resource.write(buffer, 0, l);
}
return new Timestamped<Resource>(lastModified, new Resource(resource.toByteArray(), Charset.defaultCharset()));
}
finally {
Tools.safeClose(in);
}
}
else {
throw new UnsupportedOperationException("handle me gracefully");
}
}
@Override
public long getLastModified(String path) throws IOException {
URL url = getResourceURL(path);
URLConnection conn = url.openConnection();
return conn.getLastModified();
}
@Override
public URL getURL(String path) throws IOException {
return getResourceURL(path);
}
protected abstract Set<String> doGetResourcePaths(String path) throws IOException;
protected abstract URL doGetResource(String path) throws IOException;
protected abstract String doGetRealPath(String path);
private Collection<String> getResourcePaths(String path) throws IOException {
Set<String> resourcePaths = doGetResourcePaths(mountPoint + path);
if (resourcePaths != null) {
ArrayList<String> tmp = new ArrayList<String>(resourcePaths.size());
for (String resourcePath : resourcePaths) {
tmp.add(resourcePath.substring(mountPoint.length()));
}
return tmp;
}
else {
return Collections.emptyList();
}
}
@Override
public File getFile(String path) {
String realPath = doGetRealPath(mountPoint + path);
return realPath == null ? null : new File(realPath);
}
private URL getResourceURL(String path) throws IOException {
return doGetResource(mountPoint + path);
}
public static WarFileSystem create(ServletContext context) {
return create(context, "/");
}
public static WarFileSystem create(final ServletContext servletContext, String mountPoint) {
return new WarFileSystem(mountPoint) {
@Override
public String getDescription() {
return "servlet[" + servletContext.getRealPath("/") + "]";
}
@Override
protected Set<String> doGetResourcePaths(String path) throws IOException {
return servletContext.getResourcePaths(path);
}
@Override
protected URL doGetResource(String path) throws IOException {
String realPath = servletContext.getRealPath(path);
if (realPath != null) {
return new File(realPath).toURI().toURL();
}
else {
return servletContext.getResource(path);
}
}
@Override
protected String doGetRealPath(String path) {
return servletContext.getRealPath(path);
}
};
}
public static WarFileSystem create(PortletContext portletContext) {
return create(portletContext, "/");
}
public static WarFileSystem create(final PortletContext portletContext, String mountPoint) {
return new WarFileSystem(mountPoint) {
@Override
public String getDescription() {
return "servlet[" + portletContext.getRealPath("/") + "]";
}
@Override
protected Set<String> doGetResourcePaths(String path) throws IOException {
return portletContext.getResourcePaths(path);
}
@Override
protected URL doGetResource(String path) throws IOException {
String realPath = portletContext.getRealPath(path);
if (realPath != null) {
return new File(realPath).toURI().toURL();
}
else {
return portletContext.getResource(path);
}
}
@Override
protected String doGetRealPath(String path) {
return portletContext.getRealPath(path);
}
};
}
}