/************************************************************************* * Copyright 2009-2013 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need * additional information or have any questions. ************************************************************************/ package com.eucalyptus.objectstorage.providers; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Modifier; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import org.apache.log4j.Logger; import com.eucalyptus.bootstrap.ServiceJarDiscovery; import com.eucalyptus.objectstorage.entities.ObjectStorageGlobalConfiguration; import com.eucalyptus.system.Ats; import com.eucalyptus.util.Classes; import com.eucalyptus.util.EucalyptusCloudException; import com.google.common.base.Joiner; import com.google.common.base.Strings; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.ComputationException; import com.google.common.collect.Maps; /** * Manages the set of installed provider clients, returning the currently selected item * * @author zhill * */ // Moved provider client configuration to ObjectStorageGlobalConfiguration - EUCA-9421 public class ObjectStorageProviders extends ServiceJarDiscovery { private static Logger LOG = Logger.getLogger(ObjectStorageProviders.class); private static final String UNSET = "unset"; // Moved provider client configuration to ObjectStorageGlobalConfiguration - EUCA-9421 /** * The annotation for indicating that a given class is an ObjectStorageProviderClient and to specify the name to use for configuring it. * * @author zhill * */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface ObjectStorageProviderClientProperty { String value(); } /* * The map of available client provider classes. */ private static final Map<String, Class> clients = Maps.newHashMap(); @Override public boolean processClass(Class candidate) throws Exception { if (Ats.from(candidate).has(ObjectStorageProviderClientProperty.class) && !Modifier.isAbstract(candidate.getModifiers()) && !Modifier.isInterface(candidate.getModifiers())) { ObjectStorageProviderClientProperty candidateType = Ats.from(candidate).get(ObjectStorageProviderClientProperty.class); String propName = candidateType.value(); if (ObjectStorageProviderClient.class.isAssignableFrom(candidate)) { clients.put(propName, candidate); } return true; } else { return false; } } @Override public Double getPriority() { return 0.0d; } private static final LoadingCache<String, ObjectStorageProviderClient> clientInstances = CacheBuilder.newBuilder().build( new CacheLoader<String, ObjectStorageProviderClient>() { @Override public ObjectStorageProviderClient load(String arg0) { ObjectStorageProviderClient osp = Classes.newInstance(lookupClient(arg0)); try { osp.checkPreconditions(); return osp; } catch (EucalyptusCloudException ex) { throw new ComputationException(ex); } } }); private static AtomicReference<String> lastClient = new AtomicReference<String>(); /** * Request the currently configured client * * @return */ public static ObjectStorageProviderClient getInstance() throws NoSuchElementException { if (lastClient.get() == null || UNSET.equals(lastClient.get())) { String providerClient = lookupProviderClient(); if (!Strings.isNullOrEmpty(providerClient)) { if (clients.containsKey(providerClient)) { lastClient.set(providerClient); } } else { throw new NoSuchElementException( "OSG object storage provider client not configured. Found property 'objectstorage.providerclient' empty or unset manager(" + lastClient + "). Legal values are: " + Joiner.on(",").join(clients.keySet())); } } return clientInstances.getUnchecked(lastClient.get()); } private static String lookupProviderClient() { // swathi - could prime cache and fetch config using ConfigurationCache.getConfiguration(ObjectStorageGlobalConfiguration.class) // swathi - going with direct access for now to avoid cache eviction delays during provider client initialization return ObjectStorageGlobalConfiguration.getConfiguration().getProviderClient(); } /** * Request a specific instance based on name * * @param propertyBackend * @return * @throws InstantiationException * @throws IllegalAccessException * @throws EucalyptusCloudException */ public static ObjectStorageProviderClient getInstance(String propertyBackend) throws InstantiationException, IllegalAccessException, EucalyptusCloudException { if (clients.containsKey(propertyBackend)) { lastClient.set(propertyBackend); } return getInstance(); } public static Set<String> list() { return clients.keySet(); } public static boolean contains(Object key) { return clients.containsKey(key); } public static synchronized void flushClientInstances() throws EucalyptusCloudException { LOG.debug("Flushing all object storage manager instances"); clientInstances.invalidateAll(); lastClient.set(UNSET); } public static synchronized void flushClientInstance(String key) throws EucalyptusCloudException { LOG.debug("Flusing block object manager instance: " + key); lastClient.set(UNSET); clientInstances.invalidate(key); } public static Class<? extends ObjectStorageProviderClient> lookupClient(String arg0) { if (!clients.containsKey(arg0)) { throw new NoSuchElementException("Not a valid value: " + arg0 + ". Legal values are: " + Joiner.on(",").join(clients.keySet())); } else { return clients.get(arg0); } } }