blob: ec441d627f91f38a4780035de504f71b51c366d7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2008 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.protocol;
import java.io.IOException;
import java.net.*;
import org.osgi.framework.*;
import org.osgi.service.url.URLConstants;
import org.osgi.service.url.URLStreamHandlerService;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
/**
* The URLStreamHandlerProxy is a URLStreamHandler that acts as a proxy for registered
* URLStreamHandlerServices. When a URLStreamHandler is requested from the URLStreamHandlerFactory
* and it exists in the service registry, a URLStreamHandlerProxy is created which will pass all the
* requests from the requestor to the real URLStreamHandlerService. We can't return the real
* URLStreamHandlerService from the URLStreamHandlerFactory because the JVM caches URLStreamHandlers
* and therefore would not support a dynamic environment of URLStreamHandlerServices being registered
* and unregistered.
*/
public class URLStreamHandlerProxy extends URLStreamHandler implements ServiceTrackerCustomizer {
// TODO lots of type-based names
protected URLStreamHandlerService realHandlerService;
protected URLStreamHandlerSetter urlSetter;
protected ServiceTracker urlStreamHandlerServiceTracker;
protected BundleContext context;
protected ServiceReference urlStreamServiceReference;
protected String protocol;
protected int ranking = Integer.MIN_VALUE;
public URLStreamHandlerProxy(String protocol, ServiceReference reference, BundleContext context) {
this.context = context;
this.protocol = protocol;
urlSetter = new URLStreamHandlerSetter(this);
//set the handler and ranking
setNewHandler(reference, getRank(reference));
urlStreamHandlerServiceTracker = new ServiceTracker(context, StreamHandlerFactory.URLSTREAMHANDLERCLASS, this);
StreamHandlerFactory.secureAction.open(urlStreamHandlerServiceTracker);
}
private void setNewHandler(ServiceReference reference, int rank) {
if (urlStreamServiceReference != null)
context.ungetService(urlStreamServiceReference);
urlStreamServiceReference = reference;
ranking = rank;
if (reference == null)
realHandlerService = new NullURLStreamHandlerService();
else
realHandlerService = (URLStreamHandlerService) StreamHandlerFactory.secureAction.getService(reference, context);
}
/**
* @see java.net.URLStreamHandler#equals(URL, URL)
*/
protected boolean equals(URL url1, URL url2) {
return realHandlerService.equals(url1, url2);
}
/**
* @see java.net.URLStreamHandler#getDefaultPort()
*/
protected int getDefaultPort() {
return realHandlerService.getDefaultPort();
}
/**
* @see java.net.URLStreamHandler#getHostAddress(URL)
*/
protected InetAddress getHostAddress(URL url) {
return realHandlerService.getHostAddress(url);
}
/**
* @see java.net.URLStreamHandler#hashCode(URL)
*/
protected int hashCode(URL url) {
return realHandlerService.hashCode(url);
}
/**
* @see java.net.URLStreamHandler#hostsEqual(URL, URL)
*/
protected boolean hostsEqual(URL url1, URL url2) {
return realHandlerService.hostsEqual(url1, url2);
}
/**
* @see java.net.URLStreamHandler#openConnection(URL)
*/
protected URLConnection openConnection(URL url) throws IOException {
return realHandlerService.openConnection(url);
}
/**
* @see java.net.URLStreamHandler#parseURL(URL, String, int, int)
*/
protected void parseURL(URL url, String str, int start, int end) {
realHandlerService.parseURL(urlSetter, url, str, start, end);
}
/**
* @see java.net.URLStreamHandler#sameFile(URL, URL)
*/
protected boolean sameFile(URL url1, URL url2) {
return realHandlerService.sameFile(url1, url2);
}
/**
* @see java.net.URLStreamHandler#toExternalForm(URL)
*/
protected String toExternalForm(URL url) {
return realHandlerService.toExternalForm(url);
}
/**
* @see java.net.URLStreamHandler#setURL(URL, String, String, int, String, String, String, String, String)
*/
public void setURL(URL u, String protocol, String host, int port, String authority, String userInfo, String file, String query, String ref) {
super.setURL(u, protocol, host, port, authority, userInfo, file, query, ref);
}
public void setURL(URL url, String protocol, String host, int port, String file, String ref) {
//using non-deprecated URLStreamHandler.setURL method.
//setURL(URL u, String protocol, String host, int port, String authority, String userInfo, String file, String query, String ref)
super.setURL(url, protocol, host, port, null, null, file, null, ref);
}
/**
* @see org.osgi.util.tracker.ServiceTrackerCustomizer#addingService(ServiceReference)
*/
public Object addingService(ServiceReference reference) {
//check to see if our protocol is being registered by another service
Object prop = reference.getProperty(URLConstants.URL_HANDLER_PROTOCOL);
if (!(prop instanceof String[]))
return null;
String[] protocols = (String[]) prop;
for (int i = 0; i < protocols.length; i++) {
if (protocols[i].equals(protocol)) {
//If our protocol is registered by another service, check the service ranking and switch URLStreamHandlers if nessecary.
int newServiceRanking = getRank(reference);
if (newServiceRanking > ranking || urlStreamServiceReference == null)
setNewHandler(reference, newServiceRanking);
return (reference);
}
}
//we don't want to continue hearing events about a URLStreamHandlerService not registered under our protocol
return (null);
}
/**
* @see org.osgi.util.tracker.ServiceTrackerCustomizer#modifiedService(ServiceReference, Object)
*/
// check to see if the ranking has changed. If so, re-select a new URLHandler
public void modifiedService(ServiceReference reference, Object service) {
int newRank = getRank(reference);
if (reference == urlStreamServiceReference) {
if (newRank < ranking) {
// The URLHandler we are currently using has dropped it's ranking below a URLHandler registered
// for the same protocol. We need to swap out URLHandlers.
// this should get us the highest ranked service, if available
ServiceReference newReference = urlStreamHandlerServiceTracker.getServiceReference();
if (newReference != urlStreamServiceReference && newReference != null) {
setNewHandler(newReference, ((Integer) newReference.getProperty(Constants.SERVICE_RANKING)).intValue());
}
}
} else if (newRank > ranking) {
// the service changed is another URLHandler that we are not currently using
// If it's ranking is higher, we must swap it in.
setNewHandler(reference, newRank);
}
}
/**
* @see org.osgi.util.tracker.ServiceTrackerCustomizer#removedService(ServiceReference, Object)
*/
public void removedService(ServiceReference reference, Object service) {
// check to see if our URLStreamHandler was unregistered.
if (reference != urlStreamServiceReference)
return;
// If so, look for a lower ranking URLHandler
// this should get us the highest ranking service left, if available
ServiceReference newReference = urlStreamHandlerServiceTracker.getServiceReference();
// if newReference == null then we will use the NullURLStreamHandlerService here
setNewHandler(newReference, getRank(newReference));
}
private int getRank(ServiceReference reference) {
if (reference == null)
return Integer.MIN_VALUE;
Object property = reference.getProperty(Constants.SERVICE_RANKING);
return (property instanceof Integer) ? ((Integer) property).intValue() : 0;
}
}