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.xbean.rmi;
018    
019    import java.io.File;
020    import java.net.MalformedURLException;
021    import java.net.URL;
022    import java.rmi.server.RMIClassLoader;
023    import java.rmi.server.RMIClassLoaderSpi;
024    import java.util.StringTokenizer;
025    
026    
027    /**
028     * An implementation of {@link java.rmi.server.RMIClassLoaderSpi} which provides normilzation
029     * of codebase URLs and delegates to the default {@link RMIClassLoaderSpi}.
030     *
031     * @version $Rev: 209990 $ $Date: 2005-07-09 21:24:52 -0700 (Sat, 09 Jul 2005) $
032     */
033    public class RMIClassLoaderSpiImpl extends RMIClassLoaderSpi {
034    
035        private static final RMIClassLoaderSpi delegate = RMIClassLoader.getDefaultProviderInstance();
036    
037        public Class loadClass(String codebase, String name, ClassLoader defaultLoader)
038                throws MalformedURLException, ClassNotFoundException
039        {
040            if (codebase != null) {
041                codebase = normalizeCodebase(codebase);
042            }
043    
044            return delegate.loadClass(codebase, name, defaultLoader);
045        }
046    
047        public Class loadProxyClass(String codebase, String[] interfaces, ClassLoader defaultLoader)
048                throws MalformedURLException, ClassNotFoundException
049        {
050            if (codebase != null) {
051                codebase = normalizeCodebase(codebase);
052            }
053    
054            return delegate.loadProxyClass(codebase, interfaces, defaultLoader);
055        }
056    
057        public ClassLoader getClassLoader(String codebase) throws MalformedURLException {
058    
059            if (codebase != null) {
060                codebase = normalizeCodebase(codebase);
061            }
062    
063            return delegate.getClassLoader(codebase);
064        }
065    
066        public String getClassAnnotation(Class type) {
067    
068            Object obj = type.getClassLoader();
069            if (obj instanceof ClassLoaderServerAware) {
070                ClassLoaderServerAware classLoader = (ClassLoaderServerAware) obj;
071                URL urls[] = classLoader.getClassLoaderServerURLs();
072                if (null == urls) {
073                    return delegate.getClassAnnotation(type);
074                }
075                StringBuffer codebase = new StringBuffer();
076                for (int i = 0; i < urls.length; i++) {
077                    URL url = normalizeURL(urls[i]);
078                    if (codebase.length() != 0) {
079                        codebase.append(' ');
080                    }
081                    codebase.append(url);
082                }
083                return codebase.toString();
084            }
085    
086            return delegate.getClassAnnotation(type);
087        }
088    
089        static String normalizeCodebase(String input) throws MalformedURLException {
090    
091            StringBuffer codebase = new StringBuffer();
092            StringBuffer working = new StringBuffer();
093            StringTokenizer stok = new StringTokenizer(input, " \t\n\r\f", true);
094    
095            while (stok.hasMoreTokens()) {
096                String item = stok.nextToken();
097                try {
098                    // If we got this far then item is a valid url, so commit the current
099                    // buffer and start collecting any trailing bits from where we are now
100    
101                    updateCodebase(working, codebase);
102                }
103                catch (MalformedURLException ignore) {
104                    // just keep going & append to the working buffer
105                }
106    
107                working.append(item);
108            }
109    
110            // Handle trailing elements
111            updateCodebase(working, codebase);
112    
113            return codebase.toString();
114        }
115    
116        private static void updateCodebase(final StringBuffer working, final StringBuffer codebase) throws MalformedURLException {
117    
118            if (working.length() != 0) {
119                // Normalize the URL
120                URL url = normalizeURL(new URL(working.toString()));
121    
122                // Put spaces back in for URL delims
123                if (codebase.length() != 0) {
124                    codebase.append(" ");
125                }
126                codebase.append(url);
127    
128                // Reset the working buffer
129                working.setLength(0);
130            }
131        }
132    
133        static URL normalizeURL(URL url) {
134    
135            if (url.getProtocol().equals("file")) {
136                String filename = url.getFile().replace('/', File.separatorChar);
137                File file = new File(filename);
138                try {
139                    url = file.toURI().toURL();
140                }
141                catch (MalformedURLException ignore) {
142                }
143            }
144    
145            return url;
146        }
147    
148        public interface ClassLoaderServerAware {
149            public URL[] getClassLoaderServerURLs();
150        }
151    }
152