| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.apache.sling.bundleresource.impl; |
| |
| import static org.apache.jackrabbit.JcrConstants.NT_FILE; |
| import static org.apache.jackrabbit.JcrConstants.NT_FOLDER; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.Iterator; |
| |
| import org.apache.sling.api.resource.AbstractResource; |
| import org.apache.sling.api.resource.Resource; |
| import org.apache.sling.api.resource.ResourceMetadata; |
| import org.apache.sling.api.resource.ResourceResolver; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** A Resource that wraps a Bundle entry */ |
| public class BundleResource extends AbstractResource implements Resource { |
| |
| /** default log */ |
| private final Logger log = LoggerFactory.getLogger(getClass()); |
| |
| private final ResourceResolver resourceResolver; |
| |
| private final BundleResourceCache bundle; |
| |
| private final MappedPath mappedPath; |
| |
| private final String path; |
| |
| private URL url; |
| |
| private final String resourceType; |
| |
| private final ResourceMetadata metadata; |
| |
| public static BundleResource getResource(ResourceResolver resourceResolver, |
| BundleResourceCache bundle, MappedPath mappedPath, |
| String resourcePath) { |
| |
| String entryPath = mappedPath.getEntryPath(resourcePath); |
| |
| // first try, whether the bundle has an entry with a trailing slash |
| // which would be a folder. In this case we check whether the |
| // repository contains an item with the same path. If so, we |
| // don't create a BundleResource but instead return null to be |
| // able to return an item-based resource |
| URL entry = bundle.getEntry(entryPath.concat("/")); |
| if (entry != null) { |
| |
| // append the slash to path for next steps |
| resourcePath = resourcePath.concat("/"); |
| } |
| |
| // if there is no entry with a trailing slash, try plain name |
| // which would then of course be a file |
| if (entry == null) { |
| entry = bundle.getEntry(entryPath); |
| } |
| |
| // here we either have a folder for which no same-named item exists |
| // or a bundle file |
| if (entry != null) { |
| return new BundleResource(resourceResolver, bundle, mappedPath, |
| resourcePath); |
| } |
| |
| // the bundle does not contain the path |
| return null; |
| } |
| |
| public BundleResource(ResourceResolver resourceResolver, |
| BundleResourceCache bundle, MappedPath mappedPath, |
| String resourcePath) { |
| |
| this.resourceResolver = resourceResolver; |
| this.bundle = bundle; |
| this.mappedPath = mappedPath; |
| |
| metadata = new ResourceMetadata(); |
| metadata.setResolutionPath(resourcePath); |
| metadata.setCreationTime(bundle.getBundle().getLastModified()); |
| metadata.setModificationTime(bundle.getBundle().getLastModified()); |
| |
| if (resourcePath.endsWith("/")) { |
| |
| this.path = resourcePath.substring(0, resourcePath.length() - 1); |
| this.resourceType = NT_FOLDER; |
| metadata.put(ResourceMetadata.INTERNAL_CONTINUE_RESOLVING, Boolean.TRUE); |
| |
| } else { |
| |
| this.path = resourcePath; |
| this.resourceType = NT_FILE; |
| |
| try { |
| URL url = bundle.getEntry(mappedPath.getEntryPath(resourcePath)); |
| metadata.setContentLength(url.openConnection().getContentLength()); |
| } catch (Exception e) { |
| // don't care, we just have no content length |
| } |
| } |
| } |
| |
| public String getPath() { |
| return path; |
| } |
| |
| public String getResourceType() { |
| return resourceType; |
| } |
| |
| /** Returns <code>null</code>, bundle resources have no super type */ |
| public String getResourceSuperType() { |
| return null; |
| } |
| |
| public ResourceMetadata getResourceMetadata() { |
| return metadata; |
| } |
| |
| public ResourceResolver getResourceResolver() { |
| return resourceResolver; |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| public <Type> Type adaptTo(Class<Type> type) { |
| if (type == InputStream.class) { |
| return (Type) getInputStream(); // unchecked cast |
| } else if (type == URL.class) { |
| return (Type) getURL(); // unchecked cast |
| } |
| |
| // fall back to nothing |
| return super.adaptTo(type); |
| } |
| |
| @Override |
| public String toString() { |
| return getClass().getSimpleName() + ", type=" + getResourceType() |
| + ", path=" + getPath(); |
| } |
| |
| // ---------- internal ----------------------------------------------------- |
| |
| /** |
| * Returns a stream to the bundle entry if it is a file. Otherwise returns |
| * <code>null</code>. |
| */ |
| private InputStream getInputStream() { |
| // implement this for files only |
| if (isFile()) { |
| try { |
| URL url = getURL(); |
| if (url != null) { |
| return url.openStream(); |
| } |
| } catch (IOException ioe) { |
| log.error( |
| "getInputStream: Cannot get input stream for " + this, ioe); |
| } |
| } |
| |
| // otherwise there is no stream |
| return null; |
| } |
| |
| private URL getURL() { |
| if (url == null) { |
| try { |
| url = new URL(BundleResourceURLStreamHandler.PROTOCOL, null, |
| -1, path, new BundleResourceURLStreamHandler( |
| bundle.getBundle(), mappedPath.getEntryPath(path))); |
| } catch (MalformedURLException mue) { |
| log.error("getURL: Cannot get URL for " + this, mue); |
| } |
| } |
| |
| return url; |
| } |
| |
| @Override |
| public Iterator<Resource> listChildren() { |
| return new BundleResourceIterator(this); |
| } |
| |
| BundleResourceCache getBundle() { |
| return bundle; |
| } |
| |
| MappedPath getMappedPath() { |
| return mappedPath; |
| } |
| |
| boolean isFile() { |
| return NT_FILE.equals(getResourceType()); |
| } |
| } |