View Javadoc
1   /*
2    * Licensed under the Apache License, Version 2.0 (the "License");
3    * you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at
5    *
6    * http://www.apache.org/licenses/LICENSE-2.0
7    *
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS,
10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11   * See the License for the specific language governing permissions and
12   * limitations under the License.
13   */
14  package com.addthis.codec.plugins;
15  
16  import javax.annotation.Nonnull;
17  
18  import java.util.Collections;
19  import java.util.HashMap;
20  import java.util.Map;
21  import java.util.Set;
22  
23  import com.google.common.annotations.Beta;
24  import com.google.common.base.Objects;
25  import com.google.common.collect.BiMap;
26  import com.google.common.collect.HashBiMap;
27  import com.google.common.collect.Maps;
28  
29  import com.typesafe.config.Config;
30  
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  @Beta
35  public class PluginRegistry {
36  
37      private static final Logger log = LoggerFactory.getLogger(PluginRegistry.class);
38  
39      public static final String PLUGIN_DEFAULTS_PATH = "addthis.codec.plugins.defaults";
40      public static final String PLUGINS_PATH_PATH    = "addthis.codec.plugins.path";
41  
42      public static PluginRegistry defaultRegistry() {
43          return DefaultRegistry.DEFAULT;
44      }
45  
46      @Nonnull private final Map<String, PluginMap> pluginMapsByCategory;
47      @Nonnull private final BiMap<Class<?>, PluginMap> pluginMapsByClass;
48      @Nonnull private final Config config;
49  
50      public PluginRegistry(@Nonnull Config config) {
51          this.config = config;
52          Config defaultPluginMapSettings = config.getConfig(PLUGIN_DEFAULTS_PATH);
53          String pluginPath = config.getString(PLUGINS_PATH_PATH);
54          Config pluginConfigs = config.getConfig(pluginPath);
55  
56          Set<String> categories = pluginConfigs.root().keySet();
57          Map<String, PluginMap> mapsFromConfig = new HashMap<>(categories.size());
58          BiMap<Class<?>, PluginMap> mapsFromConfigByClass = HashBiMap.create(categories.size());
59          for (String category : categories) {
60              Config pluginConfig = pluginConfigs.getConfig(category)
61                                                 .withFallback(defaultPluginMapSettings);
62              PluginMap pluginMap = new PluginMap(category, pluginConfig);
63              mapsFromConfig.put(category, pluginMap);
64              if (pluginMap.baseClass() != null) {
65                  mapsFromConfigByClass.put(pluginMap.baseClass(), pluginMap);
66              }
67          }
68          pluginMapsByCategory = Collections.unmodifiableMap(mapsFromConfig);
69          pluginMapsByClass = Maps.unmodifiableBiMap(mapsFromConfigByClass);
70      }
71  
72      /** For immutable 'with' methods. */
73      private PluginRegistry(@Nonnull Config config,
74                             @Nonnull Map<String, PluginMap> pluginMapsByCategory,
75                             @Nonnull BiMap<Class<?>, PluginMap> pluginMapsByClass) {
76          this.config = config;
77          this.pluginMapsByCategory = pluginMapsByCategory;
78          this.pluginMapsByClass = pluginMapsByClass;
79      }
80  
81      /**
82       * Similar to calling {@code new PluginRegistry(overrides.withFallback(previousRegistry.config()))},
83       * but may be more efficient. Currently only really benefits when only global defaults have been
84       * changed, but may be expanded upon in the future.
85       */
86      public PluginRegistry withOverrides(Config overrides) {
87          Config newConfig = overrides.withFallback(config);
88          String pluginPath = config.getString(PLUGINS_PATH_PATH);
89          if (overrides.hasPath(PLUGIN_DEFAULTS_PATH)
90              || overrides.hasPath(PLUGINS_PATH_PATH)
91              || overrides.hasPath(pluginPath)) {
92              return new PluginRegistry(newConfig);
93          } else {
94              return new PluginRegistry(newConfig, pluginMapsByCategory, pluginMapsByClass);
95          }
96      }
97  
98      public Config config() {
99          return config;
100     }
101 
102     public Map<String, PluginMap> asMap() {
103         return pluginMapsByCategory;
104     }
105 
106     public Map<String, PluginMap> byCategory() {
107         return pluginMapsByCategory;
108     }
109 
110     public Map<Class<?>, PluginMap> byClass() {
111         return pluginMapsByClass;
112     }
113 
114     @Override public String toString() {
115         return Objects.toStringHelper(this)
116                       .add("config.origin", config.origin())
117                       .add("pluginMapsByCategory", pluginMapsByCategory)
118                       .add("pluginMapsByClass", pluginMapsByClass)
119                       .toString();
120     }
121 }