package org.eclipse.osgi.storage.url;
import java.io.IOException;
import java.net.*;
import org.eclipse.osgi.container.Module;
import org.eclipse.osgi.container.ModuleContainer;
import org.eclipse.osgi.internal.messages.Msg;
import org.eclipse.osgi.storage.bundlefile.BundleEntry;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.AdminPermission;
import org.osgi.framework.Bundle;
public abstract class BundleResourceHandler extends URLStreamHandler {
public static final String OSGI_RESOURCE_URL_PROTOCOL = "bundleresource";
public static final String OSGI_ENTRY_URL_PROTOCOL = "bundleentry";
public static final String SECURITY_CHECKED = "SECURITY_CHECKED";
public static final String SECURITY_UNCHECKED = "SECURITY_UNCHECKED";
public static final String BID_FWKID_SEPARATOR = ".fwk";
protected final ModuleContainer container;
protected BundleEntry bundleEntry;
public BundleResourceHandler(ModuleContainer container, BundleEntry bundleEntry) {
this.container = container;
this.bundleEntry = bundleEntry;
}
@Override
protected void parseURL(URL url, String str, int start, int end) {
if (end < start)
return;
if (url.getPath() != null)
bundleEntry = null;
String spec = "";
if (start < end)
spec = str.substring(start, end);
end -= start;
String path = url.getPath();
String host = url.getHost();
int resIndex = url.getPort();
if (resIndex < 0)
resIndex = 0;
int pathIdx = 0;
if (spec.startsWith("//")) {
int bundleIdIdx = 2;
pathIdx = spec.indexOf('/', bundleIdIdx);
if (pathIdx == -1) {
pathIdx = end;
path = "";
}
int bundleIdEnd = spec.indexOf(':', bundleIdIdx);
if (bundleIdEnd > pathIdx || bundleIdEnd == -1)
bundleIdEnd = pathIdx;
if (bundleIdEnd < pathIdx - 1)
try {
resIndex = Integer.parseInt(spec.substring(bundleIdEnd + 1, pathIdx));
} catch (NumberFormatException e) {
}
host = spec.substring(bundleIdIdx, bundleIdEnd);
}
if (pathIdx < end && spec.charAt(pathIdx) == '/')
path = spec.substring(pathIdx, end);
else if (end > pathIdx) {
if (path == null || path.equals(""))
path = "/";
int last = path.lastIndexOf('/') + 1;
if (last == 0)
path = spec.substring(pathIdx, end);
else
path = path.substring(0, last) + spec.substring(pathIdx, end);
}
if (path == null)
path = "";
if (path.endsWith("/.") || path.endsWith("/.."))
path = path + '/';
int dotIndex;
while ((dotIndex = path.indexOf("/./")) >= 0)
path = path.substring(0, dotIndex + 1) + path.substring(dotIndex + 3);
while ((dotIndex = path.indexOf("/../")) >= 0) {
if (dotIndex != 0)
path = path.substring(0, path.lastIndexOf('/', dotIndex - 1)) + path.substring(dotIndex + 3);
else
path = path.substring(dotIndex + 3);
}
while ((dotIndex = path.indexOf("//")) >= 0)
path = path.substring(0, dotIndex + 1) + path.substring(dotIndex + 2);
String authorized = SECURITY_UNCHECKED;
long bundleId = getBundleID(host);
Module module = getModule(bundleId);
if (checkAuthorization(module))
authorized = SECURITY_CHECKED;
host = Long.toString(bundleId) + BID_FWKID_SEPARATOR + Integer.toString(container.hashCode());
setURL(url, url.getProtocol(), host, resIndex, authorized, null, path, null, url.getRef());
}
private Module getModule(long id) {
return container.getModule(id);
}
@Override
protected URLConnection openConnection(URL url) throws IOException {
if (bundleEntry != null)
return (new BundleURLConnection(url, bundleEntry));
String host = url.getHost();
if (host == null) {
throw new IOException(NLS.bind(Msg.URL_NO_BUNDLE_ID, url.toExternalForm()));
}
long bundleID;
try {
bundleID = getBundleID(host);
} catch (NumberFormatException nfe) {
throw (MalformedURLException) new MalformedURLException(NLS.bind(Msg.URL_INVALID_BUNDLE_ID, host)).initCause(nfe);
}
Module module = getModule(bundleID);
if (module == null)
throw new IOException(NLS.bind(Msg.URL_NO_BUNDLE_FOUND, url.toExternalForm()));
if (!url.getAuthority().equals(SECURITY_CHECKED)) {
checkAuthorization(module);
}
return (new BundleURLConnection(url, findBundleEntry(url, module)));
}
abstract protected BundleEntry findBundleEntry(URL url, Module module) throws IOException;
@Override
protected String toExternalForm(URL url) {
StringBuilder result = new StringBuilder(url.getProtocol());
result.append("://");
String host = url.getHost();
if ((host != null) && (host.length() > 0))
result.append(host);
int index = url.getPort();
if (index > 0)
result.append(':').append(index);
String path = url.getPath();
if (path != null) {
if ((path.length() > 0) && (path.charAt(0) != '/'))
{
result.append("/");
}
result.append(path);
}
String ref = url.getRef();
if (ref != null && ref.length() > 0)
result.append('#').append(ref);
return (result.toString());
}
@Override
protected int hashCode(URL url) {
int hash = 0;
String protocol = url.getProtocol();
if (protocol != null)
hash += protocol.hashCode();
String host = url.getHost();
if (host != null)
hash += host.hashCode();
hash += url.getPort();
String path = url.getPath();
if (path != null)
hash += path.hashCode();
hash += container.hashCode();
return hash;
}
@Override
protected boolean equals(URL url1, URL url2) {
return sameFile(url1, url2);
}
@Override
protected synchronized InetAddress getHostAddress(URL url) {
return null;
}
@Override
protected boolean hostsEqual(URL url1, URL url2) {
String host1 = url1.getHost();
String host2 = url2.getHost();
if (host1 != null && host2 != null)
return host1.equalsIgnoreCase(host2);
return (host1 == null && host2 == null);
}
@Override
protected boolean sameFile(URL url1, URL url2) {
if (url1.hashCode() != url2.hashCode())
return false;
String p1 = url1.getProtocol();
String p2 = url2.getProtocol();
if (!((p1 == p2) || (p1 != null && p1.equalsIgnoreCase(p2))))
return false;
if (!hostsEqual(url1, url2))
return false;
if (url1.getPort() != url2.getPort())
return false;
String path1 = url1.getPath();
String path2 = url2.getPath();
if (!((path1 == path2) || (path1 != null && path1.equals(path2))))
return false;
return true;
}
protected boolean checkAuthorization(Module module) {
SecurityManager sm = System.getSecurityManager();
if (sm == null)
return true;
Bundle bundle = module == null ? null : module.getBundle();
if (bundle == null)
return false;
sm.checkPermission(new AdminPermission(bundle, AdminPermission.RESOURCE));
return true;
}
private long getBundleID(String host) {
int dotIndex = host.indexOf('.');
return (dotIndex >= 0 && dotIndex < host.length() - 1) ? Long.parseLong(host.substring(0, dotIndex)) : Long.parseLong(host);
}
}