001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package ref.org.apache.commons.jnet;
018
019import java.lang.reflect.Field;
020import java.lang.reflect.Modifier;
021import java.net.URL;
022import java.net.URLStreamHandlerFactory;
023
024/**
025 * The installer is a general purpose class to install an own
026 * {@link URLStreamHandlerFactory} in any environment.
027 *
028 * TODO Uninstall
029 */
030public class Installer {
031
032    /**
033     * Set the url stream handler factory.
034     * @param factory
035     * @throws Exception
036     */
037    public static void setURLStreamHandlerFactory(URLStreamHandlerFactory factory)
038    throws Exception {
039        try {
040            // if we can set the factory, its the first!
041            URL.setURLStreamHandlerFactory(factory);
042        } catch (Error err) {
043            // let's use reflection to get the field holding the factory
044            final Field[] fields = URL.class.getDeclaredFields();
045            int index = 0;
046            Field factoryField = null;
047            while ( factoryField == null && index < fields.length ) {
048                final Field current = fields[index];
049                if ( Modifier.isStatic( current.getModifiers() ) && current.getType().equals( URLStreamHandlerFactory.class ) ) {
050                    factoryField = current;
051                    factoryField.setAccessible(true);
052                } else {
053                    index++;
054                }
055            }
056            if ( factoryField == null ) {
057                throw new Exception("Unable to detect static field in the URL class for the URLStreamHandlerFactory. Please report this error together with your exact environment to the Apache Excalibur project.");
058            }
059            try {
060                URLStreamHandlerFactory oldFactory = (URLStreamHandlerFactory)factoryField.get(null);
061                if(oldFactory instanceof ParentAwareURLStreamHandlerFactory){
062                        ((ParentAwareURLStreamHandlerFactory)oldFactory).setParentFactory(factory);
063                        return;
064                }
065                if (! (factory instanceof ParentAwareURLStreamHandlerFactory) ) {
066                        factory = new URLStreamHandlerFactoryWrapper(factory);
067                }
068                ((ParentAwareURLStreamHandlerFactory)factory).setParentFactory(oldFactory);
069                factoryField.set(null, factory);
070            } catch (IllegalArgumentException e) {
071                throw new Exception("Unable to set url stream handler factory " + factory);
072            } catch (IllegalAccessException e) {
073                throw new Exception("Unable to set url stream handler factory " + factory);
074            }
075        }
076    }
077
078    protected static Field getStaticURLStreamHandlerFactoryField() {
079        Field[] fields = URL.class.getDeclaredFields();
080        for ( int i = 0; i < fields.length; i++ ) {
081            if ( Modifier.isStatic( fields[i].getModifiers() ) && fields[i].getType().equals( URLStreamHandlerFactory.class ) ) {
082                fields[i].setAccessible( true );
083                return fields[i];
084            }
085        }
086        return null;
087    }
088}