001    /*
002     * Copyright 2010-2013 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.k2js.config;
018    
019    import com.intellij.openapi.project.Project;
020    import com.intellij.openapi.util.io.FileUtil;
021    import com.intellij.openapi.util.text.StringUtil;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.jet.lang.psi.JetFile;
024    import org.jetbrains.jet.lang.psi.JetPsiFactory;
025    
026    import java.io.BufferedReader;
027    import java.io.IOException;
028    import java.io.InputStream;
029    import java.io.InputStreamReader;
030    import java.net.URL;
031    import java.util.*;
032    
033    /**
034     * A helper class to discover a META-INF/services file on the classpath and load the files referenced inside it
035     */
036    public final class MetaInfServices {
037        private MetaInfServices() {
038        }
039    
040        public static List<JetFile> loadServicesFiles(@NotNull String metaInfServicesFile, @NotNull Project project) {
041            List<JetFile> libFiles = new ArrayList<JetFile>();
042            Set<URL> urlsLoaded = new HashSet<URL>();
043            try {
044                Enumeration<URL> resources = MetaInfServices.class.getClassLoader().getResources(metaInfServicesFile);
045                loadLibFiles(resources, urlsLoaded, libFiles, project);
046                resources = Thread.currentThread().getContextClassLoader().getResources(metaInfServicesFile);
047                loadLibFiles(resources, urlsLoaded, libFiles, project);
048            }
049            catch (IOException e) {
050                throw new IllegalStateException(e);
051            }
052            return libFiles;
053        }
054    
055        private static void loadLibFiles(@NotNull Enumeration<URL> resources,
056                @NotNull Set<URL> urlsLoaded,
057                @NotNull List<JetFile> libFiles,
058                @NotNull Project project)
059                throws IOException {
060            while (resources.hasMoreElements()) {
061                URL url = resources.nextElement();
062                if (url != null) {
063                    if (urlsLoaded.add(url)) {
064                        BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
065                        try {
066                            while (true) {
067                                String line = reader.readLine();
068                                if (line == null) {
069                                    break;
070                                }
071                                else {
072                                    line = line.trim();
073                                    if (line.length() == 0 || line.startsWith("#")) continue;
074                                    // lets try to discover the file
075                                    InputStream stream = loadClasspathResource(line);
076                                    if (stream != null) {
077                                        String text = StringUtil.convertLineSeparators(FileUtil.loadTextAndClose(stream));
078                                        libFiles.add(JetPsiFactory.createFile(project, line, text));
079                                    }
080                                }
081                            }
082                        }
083                        finally {
084                            reader.close();
085                        }
086                    }
087                }
088            }
089        }
090    
091        /**
092         * Tries to load the given resource name on the classpath
093         */
094        public static InputStream loadClasspathResource(String resourceName) {
095            InputStream answer = ClassPathLibraryDefintionsConfig.class.getClassLoader().getResourceAsStream(resourceName);
096            if (answer == null) {
097                answer = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName);
098            }
099            return answer;
100        }
101    }