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.finder;
018    
019    import org.apache.xbean.finder.filter.Filter;
020    
021    import java.net.URL;
022    import java.net.MalformedURLException;
023    import java.util.Collection;
024    import java.util.Iterator;
025    import java.util.List;
026    import java.util.ArrayList;
027    import java.util.Collections;
028    import java.util.Map;
029    import java.util.HashMap;
030    import java.util.Arrays;
031    import java.io.IOException;
032    import java.io.File;
033    
034    import static org.apache.xbean.finder.filter.Filters.invert;
035    import static org.apache.xbean.finder.filter.Filters.patterns;
036    
037    /**
038     * @version $Rev$ $Date$
039     */
040    public class UrlSet implements Iterable<URL> {
041    
042        private final Map<String,URL> urls;
043    
044        public UrlSet(ClassLoader classLoader) throws IOException {
045            this(getUrls(classLoader));
046        }
047    
048        public UrlSet(URL... urls){
049            this(Arrays.asList(urls));
050        }
051        /**
052         * Ignores all URLs that are not "jar" or "file"
053         * @param urls
054         */
055        public UrlSet(Collection<URL> urls){
056            this.urls = new HashMap<String,URL>();
057            for (URL location : urls) {
058                try {
059    //                if (location.getProtocol().equals("file")) {
060    //                    try {
061    //                        // See if it's actually a jar
062    //                        URL jarUrl = new URL("jar", "", location.toExternalForm() + "!/");
063    //                        JarURLConnection juc = (JarURLConnection) jarUrl.openConnection();
064    //                        juc.getJarFile();
065    //                        location = jarUrl;
066    //                    } catch (IOException e) {
067    //                    }
068    //                    this.urls.put(location.toExternalForm(), location);
069    //                }
070                    this.urls.put(location.toExternalForm(), location);
071                } catch (Exception e) {
072                    e.printStackTrace();
073                }
074            }
075        }
076    
077        private UrlSet(Map<String, URL> urls) {
078            this.urls = urls;
079        }
080    
081        public UrlSet include(UrlSet urlSet){
082            Map<String, URL> urls = new HashMap<String, URL>(this.urls);
083            urls.putAll(urlSet.urls);
084            return new UrlSet(urls);
085        }
086    
087    
088        public UrlSet include(URL url){
089            Map<String, URL> urls = new HashMap<String, URL>(this.urls);
090            urls.put(url.toExternalForm(), url);
091            return new UrlSet(urls);
092        }
093    
094        public UrlSet exclude(UrlSet urlSet) {
095            Map<String, URL> urls = new HashMap<String, URL>(this.urls);
096            Map<String, URL> parentUrls = urlSet.urls;
097            for (String url : parentUrls.keySet()) {
098                urls.remove(url);
099            }
100            return new UrlSet(urls);
101        }
102    
103        public UrlSet exclude(URL url) {
104            Map<String, URL> urls = new HashMap<String, URL>(this.urls);
105            urls.remove(url.toExternalForm());
106            return new UrlSet(urls);
107        }
108    
109        public UrlSet exclude(ClassLoader parent) throws IOException {
110            return exclude(new UrlSet(parent));
111        }
112    
113        public UrlSet exclude(File file) throws MalformedURLException {
114            return exclude(relative(file));
115        }
116    
117        public UrlSet exclude(String pattern) throws MalformedURLException {
118            return filter(invert(patterns(pattern)));
119        }
120    
121        /**
122         * Calls excludePaths(System.getProperty("java.ext.dirs"))
123         * @return
124         * @throws MalformedURLException
125         */
126        public UrlSet excludeJavaExtDirs() throws MalformedURLException {
127            String extDirs = System.getProperty("java.ext.dirs");
128            return extDirs == null ? this : excludePaths(extDirs);
129        }
130    
131        /**
132         * Calls excludePaths(System.getProperty("java.endorsed.dirs"))
133         *
134         * @return
135         * @throws MalformedURLException
136         */
137        public UrlSet excludeJavaEndorsedDirs() throws MalformedURLException {
138            String endorsedDirs = System.getProperty("java.endorsed.dirs");
139            return endorsedDirs == null ? this : excludePaths(endorsedDirs);
140        }
141    
142        public UrlSet excludeJavaHome() throws MalformedURLException {
143            String path = System.getProperty("java.home");
144    
145            File java = new File(path);
146    
147            if (path.matches("/System/Library/Frameworks/JavaVM.framework/Versions/[^/]+/Home")){
148                java = java.getParentFile();
149            }
150    
151            return exclude(java);
152        }
153    
154        public UrlSet excludePaths(String pathString) throws MalformedURLException {
155            String[] paths = pathString.split(File.pathSeparator);
156            UrlSet urlSet = this;
157            for (String path : paths) {
158                File file = new File(path);
159                urlSet = urlSet.exclude(file);
160            }
161            return urlSet;
162        }
163    
164        public UrlSet filter(Filter filter) {
165            Map<String, URL> urls = new HashMap<String, URL>();
166            for (Map.Entry<String, URL> entry : this.urls.entrySet()) {
167                String url = entry.getKey();
168                if (filter.accept(url)){
169                    urls.put(url, entry.getValue());
170                }
171            }
172            return new UrlSet(urls);
173        }
174    
175        public UrlSet matching(String pattern) {
176            return filter(patterns(pattern));
177        }
178    
179        public UrlSet relative(File file) throws MalformedURLException {
180            String urlPath = file.toURI().toURL().toExternalForm();
181            Map<String, URL> urls = new HashMap<String, URL>();
182            for (Map.Entry<String, URL> entry : this.urls.entrySet()) {
183                String url = entry.getKey();
184                if (url.startsWith(urlPath) || url.startsWith("jar:"+urlPath)){
185                    urls.put(url, entry.getValue());
186                }
187            }
188            return new UrlSet(urls);
189        }
190    
191        public List<URL> getUrls() {
192            return new ArrayList<URL>(urls.values());
193        }
194    
195        public int size() {
196            return urls.size();
197        }
198    
199        @Override
200        public Iterator<URL> iterator() {
201            return getUrls().iterator();
202        }
203    
204        private static List<URL> getUrls(ClassLoader classLoader) throws IOException {
205            List<URL> list = new ArrayList<URL>();
206            ArrayList<URL> urls = Collections.list(classLoader.getResources("META-INF"));
207            for (URL url : urls) {
208                String externalForm = url.toExternalForm();
209                int i = externalForm.lastIndexOf("META-INF");
210                externalForm = externalForm.substring(0, i);
211                url = new URL(externalForm);
212                list.add(url);
213            }
214            list.addAll(Collections.list(classLoader.getResources("")));
215            return list;
216        }
217    
218        @Override
219        public String toString() {
220            return super.toString() + "[" + urls.size() + "]";
221        }
222    }