blob: 794af2833bca4ed14fd62bad5d617eab8b450a4b [file] [log] [blame]
/*
* 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.felix.framework;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.security.Permission;
import org.apache.felix.framework.util.Util;
import org.osgi.framework.Bundle;
import org.osgi.framework.wiring.BundleRevision;
import org.osgi.framework.wiring.BundleRevisions;
import org.osgi.framework.wiring.BundleWiring;
class URLHandlersBundleURLConnection extends URLConnection
{
private Felix m_framework;
private BundleRevision m_targetRevision;
private int m_classPathIdx = -1;
private int m_contentLength;
private long m_contentTime;
private String m_contentType;
private InputStream m_is;
private final String m_path;
public URLHandlersBundleURLConnection(URL url, Felix framework)
throws IOException
{
super(url);
String urlString = url.toExternalForm();
m_path = urlString.substring(urlString.indexOf(url.getPath()));
// If this is an attempt to create a connection to the root of
// the bundle, then throw an exception since this isn't possible.
// We only allow "/" as a valid URL so it can be used as context
// for creating other URLs.
if ((m_path == null) || (m_path.length() == 0) || m_path.equals("/"))
{
throw new IOException("Resource does not exist: " + url);
}
m_framework = framework;
// If we don't have a framework instance, try to find
// one from the call context.
if (m_framework == null)
{
Object tmp = URLHandlers.getFrameworkFromContext(Util.getFrameworkUUIDFromURL(url.getHost()));
if (tmp instanceof Felix)
{
m_framework = (Felix) tmp;
}
}
// If there is still no framework, then error.
if (m_framework == null)
{
throw new IOException("Unable to find framework for URL: " + url);
}
// Verify that the resource pointed to by the URL exists.
// The URL is constructed like this:
// bundle://<revision-id>:<bundle-classpath-index>/<resource-path>
// Where <revision-id> = <bundle-id>.<revision>
long bundleId = Util.getBundleIdFromRevisionId(Util.getRevisionIdFromURL(url.getHost()));
Bundle bundle = m_framework.getBundle(bundleId);
if (bundle == null)
{
throw new IOException("No bundle associated with resource: " + url);
}
m_contentTime = bundle.getLastModified();
// Get the bundle's revisions to find the target revision.
BundleRevisions revisions = bundle.adapt(BundleRevisions.class);
if ((revisions == null) || revisions.getRevisions().isEmpty())
{
throw new IOException("Resource does not exist: " + url);
}
// Search for matching revision name.
for (BundleRevision br : revisions.getRevisions())
{
if (((BundleRevisionImpl) br).getId().equals(url.getHost()))
{
m_targetRevision = br;
break;
}
}
// If not found, assume the current revision.
if (m_targetRevision == null)
{
m_targetRevision = revisions.getRevisions().get(0);
}
// If the resource cannot be found at the current class path index,
// then search them all in order to see if it can be found. This is
// necessary since the user might create a resource URL from another
// resource URL and not realize they have the wrong class path entry.
// Of course, this approach won't work in cases where there are multiple
// resources with the same path, since it will always find the first
// one on the class path.
m_classPathIdx = url.getPort();
if (m_classPathIdx < 0)
{
m_classPathIdx = 0;
}
if (!((BundleRevisionImpl) m_targetRevision)
.hasInputStream(m_classPathIdx, m_path))
{
BundleWiring wiring = m_targetRevision.getWiring();
ClassLoader cl = (wiring != null) ? wiring.getClassLoader() : null;
URL newurl = (cl != null) ? cl.getResource(m_path) : null;
if (newurl == null)
{
throw new IOException("Resource does not exist: " + url);
}
m_classPathIdx = newurl.getPort();
}
}
public synchronized void connect() throws IOException
{
if (!connected)
{
if ((m_targetRevision == null) || (m_classPathIdx < 0))
{
throw new IOException("Resource does not exist: " + url);
}
m_is = ((BundleRevisionImpl)
m_targetRevision).getInputStream(m_classPathIdx, m_path);
m_contentLength = (m_is == null) ? 0 : m_is.available();
m_contentType = URLConnection.guessContentTypeFromName(m_path);
connected = true;
}
}
public InputStream getInputStream()
throws IOException
{
connect();
return m_is;
}
public int getContentLength()
{
try
{
connect();
}
catch(IOException ex)
{
return -1;
}
return m_contentLength;
}
public long getContentLengthLong()
{
return getContentLength();
}
public long getLastModified()
{
try
{
connect();
}
catch(IOException ex)
{
return 0;
}
if (m_contentTime != -1L)
{
return m_contentTime;
}
else
{
return 0L;
}
}
public String getContentType()
{
try
{
connect();
}
catch (IOException ex)
{
return null;
}
return m_contentType;
}
public Permission getPermission()
{
// TODO: SECURITY - This should probably return a FilePermission
// to access the bundle JAR file, but we don't have the
// necessary information here to construct the absolute
// path of the JAR file...so it would take some
// re-arranging to get this to work.
return null;
}
/**
* Retrieve the entry as a URL using standard protocols such as file: and jar:
*
* @return the local URL
*/
URL getLocalURL()
{
if ((m_targetRevision == null) || (m_classPathIdx < 0))
{
return url;
}
return ((BundleRevisionImpl)
m_targetRevision).getLocalURL(m_classPathIdx, m_path);
}
}