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     */
017    package org.apache.commons.jnet;
018    
019    import java.lang.reflect.Field;
020    import java.lang.reflect.Modifier;
021    import java.net.URL;
022    import 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     */
030    public 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 ( factory instanceof ParentAwareURLStreamHandlerFactory ) {
062                        ((ParentAwareURLStreamHandlerFactory)factory).setParentFactory(oldFactory);
063                    }
064                    factoryField.set(null, factory);
065                } catch (IllegalArgumentException e) {
066                    throw new Exception("Unable to set url stream handler factory " + factory);
067                } catch (IllegalAccessException e) {
068                    throw new Exception("Unable to set url stream handler factory " + factory);
069                }
070            }
071        }
072    
073        protected static Field getStaticURLStreamHandlerFactoryField() {
074            Field[] fields = URL.class.getDeclaredFields();
075            for ( int i = 0; i < fields.length; i++ ) {
076                if ( Modifier.isStatic( fields[i].getModifiers() ) && fields[i].getType().equals( URLStreamHandlerFactory.class ) ) {
077                    fields[i].setAccessible( true );
078                    return fields[i];
079                }
080            }
081            return null;
082        }
083    }