Package org.eclipse.osgi.framework.internal.core

Source Code of org.eclipse.osgi.framework.internal.core.BundleResourceHandler

/*******************************************************************************
* Copyright (c) 2004, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/

package org.eclipse.osgi.framework.internal.core;

import java.io.IOException;
import java.net.*;
import org.eclipse.osgi.baseadaptor.BaseAdaptor;
import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry;
import org.eclipse.osgi.baseadaptor.loader.BaseClassLoader;
import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor;
import org.eclipse.osgi.framework.internal.protocol.ProtocolActivator;
import org.eclipse.osgi.internal.baseadaptor.AdaptorMsg;
import org.eclipse.osgi.internal.loader.BundleLoader;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.*;

/**
* URLStreamHandler the bundleentry and bundleresource protocols.
*/

public abstract class BundleResourceHandler extends URLStreamHandler implements ProtocolActivator {
  public static final String SECURITY_CHECKED = "SECURITY_CHECKED"; //$NON-NLS-1$
  public static final String SECURITY_UNCHECKED = "SECURITY_UNCHECKED"; //$NON-NLS-1$
  public static final String BID_FWKID_SEPARATOR = ".fwk"; //$NON-NLS-1$
  private BaseAdaptor adaptor;
  protected BundleEntry bundleEntry;

  /**
   * Constructor for a bundle protocol resource URLStreamHandler.
   */
  public BundleResourceHandler() {
    this(null, null);
  }

  public BundleResourceHandler(BundleEntry bundleEntry, BaseAdaptor adaptor) {
    this.bundleEntry = bundleEntry;
    this.adaptor = adaptor;
  }

  public void start(BundleContext context, FrameworkAdaptor baseAdaptor) {
    this.adaptor = (BaseAdaptor) baseAdaptor;
  }

  /**
   * Parse reference URL.
   */
  protected void parseURL(URL url, String str, int start, int end) {
    if (end < start)
      return;
    if (url.getPath() != null)
      // A call to a URL constructor has been made that uses an authorized URL as its context.
      // Null out bundleEntry because it will not be valid for the new path
      bundleEntry = null;
    String spec = ""; //$NON-NLS-1$
    if (start < end)
      spec = str.substring(start, end);
    end -= start;
    //Default is to use path and bundleId from context
    String path = url.getPath();
    String host = url.getHost();
    int resIndex = url.getPort();
    if (resIndex < 0) // -1 indicates port was not set; must default to 0
      resIndex = 0;
    int pathIdx = 0;
    if (spec.startsWith("//")) { //$NON-NLS-1$
      int bundleIdIdx = 2;
      pathIdx = spec.indexOf('/', bundleIdIdx);
      if (pathIdx == -1) {
        pathIdx = end;
        // Use default
        path = ""; //$NON-NLS-1$
      }
      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) {
          // do nothing; results in resIndex == 0
        }
      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("")) //$NON-NLS-1$
        path = "/"; //$NON-NLS-1$
      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 = ""; //$NON-NLS-1$
    //modify path if there's any relative references
    // see RFC2396 Section 5.2
    // Note: For ".." references above the root the approach taken is removing them from the resolved path
    if (path.endsWith("/.") || path.endsWith("/..")) //$NON-NLS-1$ //$NON-NLS-2$
      path = path + '/';
    int dotIndex;
    while ((dotIndex = path.indexOf("/./")) >= 0) //$NON-NLS-1$
      path = path.substring(0, dotIndex + 1) + path.substring(dotIndex + 3);
    while ((dotIndex = path.indexOf("/../")) >= 0) { //$NON-NLS-1$
      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) //$NON-NLS-1$
      path = path.substring(0, dotIndex + 1) + path.substring(dotIndex + 2);

    // Check the permission of the caller to see if they
    // are allowed access to the resource.
    String authorized = SECURITY_UNCHECKED;
    long bundleId = getBundleID(host);
    Bundle bundle = adaptor == null ? null : adaptor.getBundle(bundleId);
    if (checkAuthorization(bundle))
      authorized = SECURITY_CHECKED;
    // Always force the use of the hash from the adaptor
    if (adaptor != null)
      host = Long.toString(bundleId) + BID_FWKID_SEPARATOR + Integer.toString(adaptor.hashCode());
    // Setting the authority portion of the URL to SECURITY_ATHORIZED
    // ensures that this URL was created by using this parseURL
    // method.  The openConnection method will only open URLs
    // that have the authority set to this.
    setURL(url, url.getProtocol(), host, resIndex, authorized, null, path, null, url.getRef());
  }

  /**
   * Establishes a connection to the resource specified by <code>URL</code>.
   * Since different protocols may have unique ways of connecting, it must be
   * overridden by the subclass.
   *
   * @return java.net.URLConnection
   * @param url java.net.URL
   *
   * @exception  IOException   thrown if an IO error occurs during connection establishment
   */
  protected URLConnection openConnection(URL url) throws IOException {
    if (bundleEntry != null) // if the bundleEntry is not null then return quick
      return (new BundleURLConnection(url, bundleEntry));

    String host = url.getHost();
    if (host == null) {
      throw new IOException(NLS.bind(AdaptorMsg.URL_NO_BUNDLE_ID, url.toExternalForm()));
    }
    AbstractBundle bundle = null;
    long bundleID;
    try {
      bundleID = getBundleID(host);
    } catch (NumberFormatException nfe) {
      throw (MalformedURLException) new MalformedURLException(NLS.bind(AdaptorMsg.URL_INVALID_BUNDLE_ID, host)).initCause(nfe);
    }
    bundle = adaptor == null ? null : (AbstractBundle) adaptor.getBundle(bundleID);
    if (bundle == null)
      throw new IOException(NLS.bind(AdaptorMsg.URL_NO_BUNDLE_FOUND, url.toExternalForm()));
    // check to make sure that this URL was created using the
    // parseURL method.  This ensures the security check was done
    // at URL construction.
    if (!url.getAuthority().equals(SECURITY_CHECKED)) {
      // No admin security check was made better check now.
      checkAuthorization(bundle);
    }
    return (new BundleURLConnection(url, findBundleEntry(url, bundle)));
  }

  /**
   * Finds the bundle entry for this protocal.  This is handled
   * differently for Bundle.gerResource() and Bundle.getEntry()
   * because getResource uses the bundle classloader and getEntry
   * only used the base bundle file.
   * @param url The URL to find the BundleEntry for.
   * @return the bundle entry
   */
  abstract protected BundleEntry findBundleEntry(URL url, AbstractBundle bundle) throws IOException;

  /**
   * Converts a bundle URL to a String.
   *
   * @param   url   the URL.
   * @return  a string representation of the URL.
   */
  protected String toExternalForm(URL url) {
    StringBuffer result = new StringBuffer(url.getProtocol());
    result.append("://"); //$NON-NLS-1$

    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) != '/')) /* if name doesn't have a leading slash */
      {
        result.append("/"); //$NON-NLS-1$
      }

      result.append(path);
    }
    String ref = url.getRef();
    if (ref != null && ref.length() > 0)
      result.append('#').append(ref);

    return (result.toString());
  }

  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();

    if (adaptor != null)
      hash += adaptor.hashCode();
    return hash;
  }

  protected boolean equals(URL url1, URL url2) {
    return sameFile(url1, url2);
  }

  protected synchronized InetAddress getHostAddress(URL url) {
    return null;
  }

  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);
  }

  protected boolean sameFile(URL url1, URL url2) {
    // do a hashcode test to allow each handler to check the adaptor first
    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;
    // note that the authority is not checked here because it can be different for two
    // URLs depending on how they were constructed.
  }

  protected boolean checkAuthorization(Bundle bundle) {
    SecurityManager sm = System.getSecurityManager();
    if (sm == null)
      return true;
    if (bundle == null)
      return false;
    sm.checkPermission(new AdminPermission(bundle, AdminPermission.RESOURCE));
    return true;
  }

  protected static BaseClassLoader getBundleClassLoader(AbstractBundle bundle) {
    BundleLoader loader = bundle.getBundleLoader();
    if (loader == null)
      return null;
    return (BaseClassLoader) loader.createClassLoader();
  }

  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);
  }
}
TOP

Related Classes of org.eclipse.osgi.framework.internal.core.BundleResourceHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.