eclipse / Xpect

This repository has been rewritten to move to the Eclipse Foundation. Find the old history here: https://github.com/TypeFox/Xpect
http://www.xpect-tests.org/
Eclipse Public License 2.0
32 stars 28 forks source link

consider a URLStreamHandlerFactory for platform:/ #116

Open meysholdt opened 10 years ago

meysholdt commented 10 years ago
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor;
import org.eclipse.osgi.framework.internal.core.Constants;
import org.eclipse.osgi.framework.internal.core.Msg;
import org.eclipse.osgi.framework.internal.protocol.MultiplexingURLStreamHandler;
import org.eclipse.osgi.framework.internal.protocol.ProtocolActivator;
import org.eclipse.osgi.framework.internal.protocol.StreamHandlerFactory;
import org.eclipse.osgi.framework.internal.protocol.URLStreamHandlerFactoryProxyFor15;
import org.eclipse.osgi.framework.internal.protocol.URLStreamHandlerProxy;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.framework.util.SecureAction;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.url.URLConstants;
import org.osgi.service.url.URLStreamHandlerService;
import org.osgi.util.tracker.ServiceTracker;
import org.xpect.util.IBundleInfo;

public class PlatformURLStreamHandlerFactory implements URLStreamHandlerFactory {
//    private static Field getField(Class<?> clazz, Class<?> type, boolean instance) {
//        Field[] fields = clazz.getDeclaredFields();
//        for (int i = 0; i < fields.length; i++) {
//            boolean isStatic = Modifier.isStatic(fields[i].getModifiers());
//            if (instance != isStatic && fields[i].getType().equals(type)) {
//                fields[i].setAccessible(true);
//                return fields[i];
//            }
//        }
//        return null;
//    }
//
//    private static Object getURLStreamHandlerFactoryLock() throws IllegalAccessException {
//        Object lock;
//        try {
//            Field streamHandlerLockField = URL.class.getDeclaredField("streamHandlerLock"); //$NON-NLS-1$
//            streamHandlerLockField.setAccessible(true);
//            lock = streamHandlerLockField.get(null);
//        } catch (NoSuchFieldException noField) {
//            // could not find the lock, lets sync on the class object
//            lock = URL.class;
//        }
//        return lock;
//    }
//
//    // see org.eclipse.osgi.framework.internal.core.Framework.forceURLStreamHandlerFactory(StreamHandlerFactory)
//    public static void forceURLStreamHandlerFactory() {
//        try {
//            URL u = new URL("file:/test");
//            URLConnection openConnection = u.openConnection();
//            IBundleInfo.Registry.INSTANCE.getAllBundleNames();
//            Field factoryField = getField(URL.class, URLStreamHandlerFactory.class, false);
//            if (factoryField == null)
//                throw new Exception("Could not find URLStreamHandlerFactory field"); //$NON-NLS-1$
//            // look for a lock to synchronize on
//            Object lock = getURLStreamHandlerFactoryLock();
//            synchronized (lock) {
//                URLStreamHandlerFactory factory = (URLStreamHandlerFactory)factoryField.get(null);
//                URLStreamHandlerFactory shf = new PlatformURLStreamHandlerFactory(factory);
//                // doing a null check here just in case, but it would be really strange if it was null, 
//                // because we failed to set the factory normally!!
//                if (factory != null) {
//                    try {
//                        factory.getClass().getMethod("isMultiplexing", (Class[])null); //$NON-NLS-1$
//                        Method register = factory.getClass().getMethod("register", new Class[] { Object.class }); //$NON-NLS-1$
//                        register.invoke(factory, new Object[] { shf });
//                    } catch (NoSuchMethodException e) {
//                        // current factory does not support multiplexing, ok we'll wrap it
//                        // shf.setParentFactory(factory);
//                        factory = shf;
//                    }
//                }
//                factoryField.set(null, null);
//                // always attempt to clear the handlers cache
//                // This allows an optomization for the single framework use-case
//                resetURLStreamHandlers();
//                //                URL.setURLStreamHandlerFactory(factory);
//                URL.setURLStreamHandlerFactory(shf);
//            }
//        } catch (Throwable e) {
//            throw new RuntimeException(e);
//        }
//    }

//    private static void resetURLStreamHandlers() throws IllegalAccessException {
//        Field handlersField = getField(URL.class, Hashtable.class, false);
//        if (handlersField != null) {
//            @SuppressWarnings("rawtypes")
//            Hashtable<?, ?> handlers = (Hashtable)handlersField.get(null);
//            if (handlers != null)
//                handlers.clear();
//        }
//    }

    public static class PlatformURLConnection extends URLConnection {
        protected PlatformURLConnection (URL url) {
            super(url);
        }

        @Override
        public InputStream getInputStream() throws IOException {
            URI uri = URI.createURI(getURL().toString());
            List<String> segments = uri.segmentsList();
            String project = segments.get(1);
            IBundleInfo bundle = IBundleInfo.Registry.INSTANCE.getBundle(project);
            if (bundle == null)
                throw new IllegalStateException("Bundle " + project + " not found.");
            URI resolved = bundle.getLocationURI().appendSegments(segments.subList(2, segments.size()).toArray(new String[segments.size() - 2]));
            return new FileInputStream(resolved.toFileString());
        }

        @Override
        public void connect() throws IOException {
            System.out.println("connecting " + getURL());
        }
    }

    public static class PlatformURLStreamHandler extends URLStreamHandler {
        @Override
        protected URLConnection openConnection(URL u) throws IOException {
            return new PlatformURLConnection(u);
        }
    }

//    private final URLStreamHandlerFactory parent;

//    private PlatformURLStreamHandlerFactory (URLStreamHandlerFactory parent) {
//        super();
//        this.parent = parent;
//    }

//    @Override
//    public URLStreamHandler createURLStreamHandler(String arg0) {
//        if ("platform".equals(arg0))
//            return new PlatformURLStreamHandler();
//        return parent.createURLStreamHandler(arg0);
//    }

    static final SecureAction secureAction = AccessController.doPrivileged(SecureAction.createSecureAction());

//    private ServiceTracker<URLStreamHandlerService, URLStreamHandlerService> handlerTracker;

    protected static final String URLSTREAMHANDLERCLASS = "org.osgi.service.url.URLStreamHandlerService"; //$NON-NLS-1$
    protected static final String PROTOCOL_HANDLER_PKGS = "java.protocol.handler.pkgs"; //$NON-NLS-1$
    protected static final String INTERNAL_PROTOCOL_HANDLER_PKG = "org.eclipse.osgi.framework.internal.protocol"; //$NON-NLS-1$

    private static final List<Class<?>> ignoredClasses = Arrays.asList(new Class<?>[] {MultiplexingURLStreamHandler.class, StreamHandlerFactory.class, URL.class});
    private static final boolean useNetProxy;
    static {
        Class<?> clazz = null;
        try {
            clazz = Class.forName("java.net.Proxy"); //$NON-NLS-1$
        } catch (ClassNotFoundException e) {
            // expected on JRE < 1.5
        }
        useNetProxy = clazz != null;
    }
//    private Map<String, URLStreamHandler> proxies;
//    private URLStreamHandlerFactory parentFactory;
    private ThreadLocal<List<String>> creatingProtocols = new ThreadLocal<List<String>>();

    /**
     * Create the factory.
     *
     * @param context BundleContext for the system bundle
     */
    public PlatformURLStreamHandlerFactory() {

//        proxies = new Hashtable<String, URLStreamHandler>(15);
//        handlerTracker = new ServiceTracker<URLStreamHandlerService, URLStreamHandlerService>(context, URLSTREAMHANDLERCLASS, null);
//        handlerTracker.open();
    }

    private Class<?> getBuiltIn(String protocol, String builtInHandlers, boolean fromFramework) {
        if (builtInHandlers == null)
            return null;
        Class<?> clazz;
        StringTokenizer tok = new StringTokenizer(builtInHandlers, "|"); //$NON-NLS-1$
        while (tok.hasMoreElements()) {
            StringBuffer name = new StringBuffer();
            name.append(tok.nextToken());
            name.append("."); //$NON-NLS-1$
            name.append(protocol);
            name.append(".Handler"); //$NON-NLS-1$
            try {
                if (fromFramework)
                    clazz = secureAction.forName(name.toString());
                else
                    clazz = secureAction.loadSystemClass(name.toString());
                if (clazz != null)
                    return clazz; //this class exists, it is a built in handler 
            } catch (ClassNotFoundException ex) {
                // keep looking
            }
        }
        return null;
    }

    /**
     * Creates a new URLStreamHandler instance for the specified
     * protocol.
     *
     * @param protocol The desired protocol
     * @return a URLStreamHandler for the specific protocol.
     */
    public URLStreamHandler createURLStreamHandler(String protocol) {
        // Check if we are recursing
        if (isRecursive(protocol))
            return null;
        try {
            //first check for built in handlers
            String builtInHandlers = secureAction.getProperty(PROTOCOL_HANDLER_PKGS);
            Class<?> clazz = getBuiltIn(protocol, builtInHandlers, false);
            if (clazz != null)
                return null; // let the VM handle it
            URLStreamHandler result = null;
//            if (isMultiplexing()) {
//                URLStreamHandler authorized = findAuthorizedURLStreamHandler(protocol);
//                if (authorized != null)
//                    result = new MultiplexingURLStreamHandler(protocol, this, authorized);
//            } else {
                result = createInternalURLStreamHandler(protocol);
//            }
            // if parent is present do parent lookup
//            if (result == null && parentFactory != null)
//                result = parentFactory.createURLStreamHandler(protocol);
            return result; //result may be null; let the VM handle it (consider sun.net.protocol.www.*)
        } catch (Throwable t) {
            t.printStackTrace();
            return null;
        } finally {
            releaseRecursive(protocol);
        }
    }

    private boolean isRecursive(String protocol) {
        List<String> protocols = creatingProtocols.get();
        if (protocols == null) {
            protocols = new ArrayList<String>(1);
            creatingProtocols.set(protocols);
        }
        if (protocols.contains(protocol))
            return true;
        protocols.add(protocol);
        return false;
    }

    private void releaseRecursive(String protocol) {
        List<String> protocols = creatingProtocols.get();
        protocols.remove(protocol);
    }

    public URLStreamHandler createInternalURLStreamHandler(String protocol) {

        //internal protocol handlers
        String internalHandlerPkgs = secureAction.getProperty(Constants.INTERNAL_HANDLER_PKGS);
        internalHandlerPkgs = internalHandlerPkgs == null ? INTERNAL_PROTOCOL_HANDLER_PKG : internalHandlerPkgs + '|' + INTERNAL_PROTOCOL_HANDLER_PKG;
        Class<?> clazz = getBuiltIn(protocol, internalHandlerPkgs, true);

        if (clazz == null) {
            if("platform".equals(protocol))
                return new PlatformURLStreamHandler();
            //Now we check the service registry
            //first check to see if the handler is in the cache
//            URLStreamHandlerProxy handler = (URLStreamHandlerProxy) proxies.get(protocol);
//            if (handler != null)
//                return (handler);
//            //look through the service registry for a URLStramHandler registered for this protocol
//            ServiceReference<URLStreamHandlerService>[] serviceReferences = handlerTracker.getServiceReferences();
//            if (serviceReferences == null)
//                return null;
//            for (int i = 0; i < serviceReferences.length; i++) {
//                Object prop = serviceReferences[i].getProperty(URLConstants.URL_HANDLER_PROTOCOL);
//                if (prop instanceof String)
//                    prop = new String[] {(String) prop}; // TODO should this be a warning?
//                if (!(prop instanceof String[])) {
//                    String message = NLS.bind(Msg.URL_HANDLER_INCORRECT_TYPE, new Object[] {URLConstants.URL_HANDLER_PROTOCOL, URLSTREAMHANDLERCLASS, serviceReferences[i].getBundle()});
//                    adaptor.getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, message, 0, null, null));
//                    continue;
//                }
//                String[] protocols = (String[]) prop;
//                for (int j = 0; j < protocols.length; j++)
//                    if (protocols[j].equals(protocol)) {
//                        handler = useNetProxy ? new URLStreamHandlerFactoryProxyFor15(protocol, serviceReferences[i], context) : new URLStreamHandlerProxy(protocol, serviceReferences[i], context);
//                        proxies.put(protocol, handler);
//                        return (handler);
//                    }
//            }
            return null;
        }

        // must be a built-in handler
        try {
            URLStreamHandler handler = (URLStreamHandler) clazz.newInstance();

//            if (handler instanceof ProtocolActivator) {
//                ((ProtocolActivator) handler).start(context, adaptor);
//            }

            return handler;
        } catch (Exception e) {
            return null;
        }
    }

//    protected URLStreamHandler findAuthorizedURLStreamHandler(String protocol) {
//        Object factory = findAuthorizedFactory(ignoredClasses);
//        if (factory == null)
//            return null;
//
//        if (factory == this)
//            return createInternalURLStreamHandler(protocol);
//
//        try {
//            Method createInternalURLStreamHandlerMethod = factory.getClass().getMethod("createInternalURLStreamHandler", new Class[] {String.class}); //$NON-NLS-1$
//            return (URLStreamHandler) createInternalURLStreamHandlerMethod.invoke(factory, new Object[] {protocol});
//        } catch (Exception e) {
//            adaptor.getFrameworkLog().log(new FrameworkLogEntry(StreamHandlerFactory.class.getName(), FrameworkLogEntry.ERROR, 0, "findAuthorizedURLStreamHandler-loop", 0, e, null)); //$NON-NLS-1$
//            throw new RuntimeException(e.getMessage(), e);
//        }
//    }

//    public Object getParentFactory() {
//        return parentFactory;
//    }
//
//    public void setParentFactory(Object parentFactory) {
//        if (this.parentFactory == null) // only allow it to be set once
//            this.parentFactory = (URLStreamHandlerFactory) parentFactory;
//    }

}