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