ServiceLoaderUtils.java
01 /*
02  * Copyright 2008-2015 the original author or authors.
03  *
04  * Licensed under the Apache License, Version 2.0 (the "License");
05  * you may not use this file except in compliance with the License.
06  * You may obtain a copy of the License at
07  *
08  *     http://www.apache.org/licenses/LICENSE-2.0
09  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package griffon.util;
17 
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20 
21 import javax.annotation.Nonnull;
22 import java.io.IOException;
23 import java.net.URL;
24 import java.util.Enumeration;
25 import java.util.Scanner;
26 
27 import static griffon.core.GriffonExceptionHandler.sanitize;
28 import static griffon.util.GriffonNameUtils.isBlank;
29 import static griffon.util.GriffonNameUtils.requireNonBlank;
30 import static java.util.Objects.requireNonNull;
31 
32 /**
33  @author Andres Almiray
34  @since 2.0.0
35  */
36 public class ServiceLoaderUtils {
37     private static final Logger LOG = LoggerFactory.getLogger(ServiceLoaderUtils.class);
38 
39     private ServiceLoaderUtils() {
40 
41     }
42 
43     public static interface LineProcessor {
44         void process(@Nonnull ClassLoader classLoader, @Nonnull Class<?> type, @Nonnull String line);
45     }
46 
47     public static boolean load(@Nonnull ClassLoader classLoader, @Nonnull String path, @Nonnull Class<?> type, @Nonnull LineProcessor processor) {
48         requireNonNull(classLoader, "Argument 'classLoader' must not be null");
49         requireNonBlank(path, "Argument 'path' must not be blank");
50         requireNonNull(type, "Argument 'type' must not be null");
51         requireNonNull(processor, "Argument 'processor' must not be null");
52         // "The name of a resource is a /-separated path name that identifies the resource."
53         String normalizedPath = path.endsWith("/"? path : path + "/";
54 
55         Enumeration<URL> urls;
56 
57         try {
58             urls = classLoader.getResources(normalizedPath + type.getName());
59         catch (IOException ioe) {
60             LOG.error(ioe.getClass().getName() " error loading resources of type \"" + type.getName() "\" from \"" + normalizedPath + "\".");
61             return false;
62         }
63 
64         if (urls == nullreturn false;
65 
66         while (urls.hasMoreElements()) {
67             URL url = urls.nextElement();
68             LOG.debug("Reading {} definitions from {}", type.getName(), url);
69 
70             try (Scanner scanner = new Scanner(url.openStream())) {
71                 while (scanner.hasNextLine()) {
72                     String line = scanner.nextLine();
73                     if (line.startsWith("#"|| isBlank(line)) continue;
74                     processor.process(classLoader, type, line);
75                 }
76             catch (IOException e) {
77                 LOG.warn("Could not load " + type.getName() " definitions from " + url, sanitize(e));
78             }
79         }
80 
81         return true;
82     }
83 }