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    
025    import java.io.BufferedReader;
026    import java.io.IOException;
027    import java.io.InputStream;
028    import java.io.InputStreamReader;
029    import java.net.URL;
030    import java.util.*;
031    
032    import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory;
033    
034    /**
035     * A helper class to discover a META-INF/services file on the classpath and load the files referenced inside it
036     */
037    public final class MetaInfServices {
038        private MetaInfServices() {
039        }
040    
041        public static List<JetFile> loadServicesFiles(@NotNull String metaInfServicesFile, @NotNull Project project) {
042            List<JetFile> libFiles = new ArrayList<JetFile>();
043            Set<URL> urlsLoaded = new HashSet<URL>();
044            try {
045                Enumeration<URL> resources = MetaInfServices.class.getClassLoader().getResources(metaInfServicesFile);
046                loadLibFiles(resources, urlsLoaded, libFiles, project);
047                resources = Thread.currentThread().getContextClassLoader().getResources(metaInfServicesFile);
048                loadLibFiles(resources, urlsLoaded, libFiles, project);
049            }
050            catch (IOException e) {
051                throw new IllegalStateException(e);
052            }
053            return libFiles;
054        }
055    
056        private static void loadLibFiles(@NotNull Enumeration<URL> resources,
057                @NotNull Set<URL> urlsLoaded,
058                @NotNull List<JetFile> libFiles,
059                @NotNull Project project)
060                throws IOException {
061            while (resources.hasMoreElements()) {
062                URL url = resources.nextElement();
063                if (url != null) {
064                    if (urlsLoaded.add(url)) {
065                        BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
066                        try {
067                            while (true) {
068                                String line = reader.readLine();
069                                if (line == null) {
070                                    break;
071                                }
072                                else {
073                                    line = line.trim();
074                                    if (line.length() == 0 || line.startsWith("#")) continue;
075                                    // lets try to discover the file
076                                    InputStream stream = loadClasspathResource(line);
077                                    if (stream != null) {
078                                        String text = StringUtil.convertLineSeparators(FileUtil.loadTextAndClose(stream));
079                                        libFiles.add(JetPsiFactory(project).createFile(line, text));
080                                    }
081                                }
082                            }
083                        }
084                        finally {
085                            reader.close();
086                        }
087                    }
088                }
089            }
090        }
091    
092        /**
093         * Tries to load the given resource name on the classpath
094         */
095        public static InputStream loadClasspathResource(String resourceName) {
096            InputStream answer = ClassPathLibraryDefintionsConfig.class.getClassLoader().getResourceAsStream(resourceName);
097            if (answer == null) {
098                answer = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName);
099            }
100            return answer;
101        }
102    }