001 /* 002 * Copyright (C) 2006-2007 the original author or authors. 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.codehaus.gmaven.runtime.loader; 018 019 import org.codehaus.gmaven.feature.Provider; 020 import org.codehaus.gmaven.feature.ProviderLoader; 021 import org.codehaus.gmaven.feature.ProviderRegistry; 022 import org.codehaus.gmaven.feature.ProviderSelector; 023 import org.codehaus.plexus.PlexusConstants; 024 import org.codehaus.plexus.PlexusContainer; 025 import org.codehaus.plexus.context.Context; 026 import org.codehaus.plexus.context.ContextException; 027 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable; 028 import org.slf4j.Logger; 029 import org.slf4j.LoggerFactory; 030 031 import java.util.HashMap; 032 import java.util.Iterator; 033 import java.util.LinkedHashMap; 034 import java.util.Map; 035 import java.util.Set; 036 037 /** 038 * Default {@link ProviderSelector}. 039 * 040 * @plexus.component role="org.codehaus.gmaven.feature.ProviderSelector" 041 * 042 * @version $Id: DefaultProviderSelector.java 52 2009-11-22 10:32:14Z user57 $ 043 * @author <a href="mailto:jason@planet57.com">Jason Dillon</a> 044 */ 045 public class DefaultProviderSelector 046 implements ProviderSelector, Contextualizable 047 { 048 private final Logger log = LoggerFactory.getLogger(getClass()); 049 050 private PlexusContainer container; 051 052 public void contextualize(final Context context) throws ContextException { 053 assert context != null; 054 055 container = (PlexusContainer) context.get(PlexusConstants.PLEXUS_KEY); 056 } 057 058 protected PlexusContainer getContainer() { 059 if (container == null) { 060 throw new IllegalStateException("Container not bound"); 061 } 062 063 return container; 064 } 065 066 public Provider select(final ProviderRegistry registry, final String selection) throws Exception { 067 assert registry != null; 068 assert selection != null; 069 070 log.trace("Select: {}", selection); 071 072 register(registry, selection); 073 074 Provider provider = null; 075 076 if (SELECT_ANY.equals(selection)) { 077 provider = selectAny(registry); 078 } 079 else { 080 String[] keys = selection.split(","); 081 082 for (int i=0; i<keys.length; i++) { 083 Provider tmp = registry.lookup(keys[i]); 084 085 if (tmp != null) { 086 provider = tmp; 087 break; 088 } 089 } 090 } 091 092 if (log.isTraceEnabled()) { 093 if (provider == null) { 094 log.trace("No matching providers found for selection: {}", selection); 095 } 096 else if (!provider.supported()) { 097 log.trace("Found unsupported provider matching selection: {}, found: {}", selection, provider); 098 } 099 } 100 101 return provider; 102 } 103 104 private Provider selectAny(final ProviderRegistry registry) { 105 assert registry != null; 106 107 Map supported = registry.providers(true); 108 Provider provider = null; 109 110 if (supported != null && !supported.isEmpty()) { 111 provider = (Provider) supported.values().iterator().next(); 112 } 113 114 return provider; 115 } 116 117 private void register(final ProviderRegistry registry, final String selection) throws Exception { 118 assert registry != null; 119 assert selection != null; 120 121 // First run discovery 122 Map discovered = discover(registry, selection); 123 124 // If we didn't find anything then puke 125 if (discovered == null || discovered.isEmpty()) { 126 log.debug("No providers discovered for selection: {}", selection); 127 } 128 else { 129 log.debug("Registering {} providers:", String.valueOf(discovered.size())); 130 131 for (Iterator iter = discovered.keySet().iterator(); iter.hasNext();) { 132 String key = (String) iter.next(); 133 Provider provider = (Provider) discovered.get(key); 134 135 log.debug(" {} -> {}", key, provider); 136 137 // Complain if we found a mismatch of keys 138 if (!key.equals(provider.key())) { 139 log.warn("Found mismatch of provider key; discovered key: {}, provider's key: {}", key, provider.key()); 140 } 141 142 Provider replaced = registry.register(provider); 143 144 // Complain if we replaced a provider 145 if (replaced != null) { 146 log.warn("Replaced provider; key: {}, current: {}, replaced: {}", new Object[] { key, provider, replaced }); 147 } 148 } 149 } 150 } 151 152 private Map discover(final ProviderRegistry registry, final String selection) throws Exception { 153 assert registry != null; 154 assert selection != null; 155 156 log.debug("Discovering providers for selection: {}", selection); 157 158 Map discovered = null; 159 String[] keys = selection.split(","); 160 161 // Attempt to discover providers for each key 162 for (int i=0; i<keys.length; i++) { 163 // Don't attempt to discover psuedo providers 164 if (keys[i].equals(SELECT_ANY)) { 165 continue; 166 } 167 168 try { 169 // First see if the registry already has a provider for this key 170 if (registry.lookup(keys[i]) != null) { 171 log.debug("Provider already registered for: {}", keys[i]); 172 173 // Skip loading and re-use the registered provider 174 continue; 175 } 176 177 Map found = load(keys[i]); 178 179 if (found != null && !found.isEmpty()) { 180 // Late init the discovered providers map 181 if (discovered == null) { 182 discovered = new HashMap(); 183 } 184 185 discovered.putAll(found); 186 } 187 } 188 catch (Exception e) { 189 log.debug("Failed to load providers for key: {}", keys[i], e); 190 } 191 } 192 193 return discovered; 194 } 195 196 protected Map load(final String key) throws Exception { 197 assert key != null; 198 199 Map found = null; 200 Map loaders = findLoaders(); 201 202 if (loaders == null || loaders.isEmpty()) { 203 log.debug("No provider loaders were found"); 204 } 205 else { 206 log.debug("Looking for provider {} in {}", key, loaders); 207 208 for (Iterator iter = loaders.values().iterator(); iter.hasNext();) { 209 ProviderLoader loader = (ProviderLoader) iter.next(); 210 211 log.debug("Trying to load {} from {}", key, loader); 212 213 try { 214 Map loaded = loader.load(key); 215 216 if (loaded != null && !loaded.isEmpty()) { 217 found = loaded; 218 break; 219 } 220 } 221 catch (Exception e) { 222 log.warn("Failed to load provider from: {}", loader, e); 223 } 224 } 225 } 226 227 return found; 228 } 229 230 /** 231 * Find any provider loaders which are available in the container. 232 */ 233 private Map findLoaders() { 234 Map loaders = getContainer().getComponentDescriptorMap(ProviderLoader.class.getName()); 235 if (loaders == null) { 236 throw new Error("No provider loaders found"); 237 } 238 239 Set keys = loaders.keySet(); 240 Map found = null; 241 ProviderLoader defaultLoader = null; 242 243 for (Iterator iter = keys.iterator(); iter.hasNext();) { 244 String key = (String)iter.next(); 245 246 ProviderLoader loader; 247 248 try { 249 loader = (ProviderLoader) getContainer().lookup(ProviderLoader.class.getName(), key); 250 } 251 catch (Exception e) { 252 log.warn("Failed to lookup provider loader for key: {}", key, e); 253 continue; 254 } 255 256 if (loader != null) { 257 if (found == null) { 258 // we need an ordered map 259 found = new LinkedHashMap(); 260 } 261 if (key.equals(SELECT_DEFAULT)) { 262 defaultLoader = loader; 263 } 264 else { 265 found.put(key, loader); 266 } 267 } 268 } 269 270 // the default should be added at the end (as fallback) 271 assert defaultLoader != null; 272 found.put(SELECT_DEFAULT, defaultLoader); 273 274 return found; 275 } 276 }