Java tutorial
/******************************************************************************* * Copyright (c) 2008, 2011 Gunnar Wagenknecht and others. * All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html. * * Contributors: * Gunnar Wagenknecht - initial API and implementation * Mike Tschierschke - customization for rap based admin ui, * added implementation for method getRepositoryDefinition *******************************************************************************/ package org.eclipse.gyrex.persistence.internal.storage; import java.text.MessageFormat; import java.util.Collection; import java.util.Collections; import java.util.Hashtable; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.eclipse.gyrex.cloud.services.state.INodeState; import org.eclipse.gyrex.common.identifiers.IdHelper; import org.eclipse.gyrex.persistence.internal.PersistenceActivator; import org.eclipse.gyrex.persistence.storage.Repository; import org.eclipse.gyrex.persistence.storage.provider.RepositoryProvider; import org.eclipse.gyrex.persistence.storage.registry.IRepositoryDefinition; import org.eclipse.gyrex.persistence.storage.registry.IRepositoryRegistry; import org.eclipse.gyrex.persistence.storage.settings.IRepositoryPreferences; import org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener; import org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceRegistration; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.exception.ExceptionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The platform repository manager stores repository information. */ public class RepositoryRegistry implements IRepositoryRegistry { /** ACTIVE */ private static final String STATE_ACTIVE = "active"; public static final String STATE_REPOSITORY_PREFIX = "repository:"; public static final String REPOSITORY_STATE_SERVICE_PID = "org.eclipse.gyrex.persistence.storage.registry.state"; private static final Logger LOG = LoggerFactory.getLogger(RepositoryRegistry.class); private static void errorCreatingRepository(final RepositoryDefinition repositoryDef, final String detail) { throw new IllegalStateException(MessageFormat.format("Invalid repository definition ''{0}'': {1}", repositoryDef.getRepositoryId(), detail)); } private final INodeChangeListener repositoryModifcationListener = new INodeChangeListener() { @Override public void added(final NodeChangeEvent event) { // not handled } @Override public void removed(final NodeChangeEvent event) { // repository has been removed final String repositoryId = event.getChild().name(); // close removed repo close(repositoryId); } }; private final AtomicReference<RepositoryDefinitionsStore> repositoryDefinitionsStoreRef = new AtomicReference<RepositoryDefinitionsStore>(); private final ConcurrentMap<String, Lock> locksByRepositoryId = new ConcurrentHashMap<String, Lock>(4); private final ConcurrentMap<String, Repository> repositoryCache = new ConcurrentHashMap<String, Repository>(4); private final AtomicBoolean closed = new AtomicBoolean(false); private volatile ServiceRegistration<INodeState> registryStateRegistration; private final Hashtable<String, String> registryState; /** * Creates a new instance. * * @param context */ public RepositoryRegistry(final BundleContext context) { // initialize repository state registryState = new Hashtable<String, String>(4); registryState.put(Constants.SERVICE_VENDOR, "Eclipse Gyrex"); registryState.put(Constants.SERVICE_DESCRIPTION, "Repository Registry State"); registryState.put(Constants.SERVICE_PID, REPOSITORY_STATE_SERVICE_PID); // publish initial state registryStateRegistration = context.registerService(INodeState.class, INodeState.INSTANCE, registryState); } public void close(final String repositoryId) { if (!repositoryCache.containsKey(repositoryId)) { return; } // lock final Lock lock = locksByRepositoryId.get(repositoryId); if (lock != null) { lock.lock(); } final Repository repository; try { // remove cached instance repository = repositoryCache.remove(repositoryId); // remove from state map registryState.remove(STATE_REPOSITORY_PREFIX.concat(repositoryId)); // remove lock locksByRepositoryId.remove(repositoryId); } finally { if (lock != null) { lock.unlock(); } } // close repository outside lock if (null != repository) { try { repository.close(); } catch (final Exception e) { LOG.error("Error closing repository {}. {}", new Object[] { repositoryId, ExceptionUtils.getRootCauseMessage(e), e }); } } // publish new state updateRepositoryState(); } /** * Creates a repository from a definition * * @param repositoryDef * @return * @throws IllegalStateException * if the repository could not be created */ private Repository createRepository(final RepositoryDefinition repositoryDef) throws IllegalStateException { final String repositoryProviderId = repositoryDef.getProviderId(); if (null == repositoryProviderId) { errorCreatingRepository(repositoryDef, "invalid type"); } // get repository type final RepositoryProvider repositoryType = PersistenceActivator.getInstance().getRepositoryProviderRegistry() .getRepositoryProvider(repositoryProviderId); // get repository settings final IRepositoryPreferences repositoryPreferences = repositoryDef.getRepositoryPreferences(); // create repository instance final Repository repository = repositoryType.createRepositoryInstance(repositoryDef.getRepositoryId(), repositoryPreferences); if (null == repository) { errorCreatingRepository(repositoryDef, MessageFormat .format("repository type ''{0}'' returned no repository instance", repositoryProviderId)); } return repository; } @Override public IRepositoryDefinition createRepository(final String repositoryId, final String repositoryProviderId) throws IllegalArgumentException { if (!IdHelper.isValidId(repositoryId)) { throw new IllegalArgumentException("repository id is not valid"); } if (StringUtils.isBlank(repositoryProviderId)) { throw new IllegalArgumentException("repository id must not be null"); } // create return getStore().create(repositoryId, repositoryProviderId); } private Lock getOrCreateRepositoryLock(final String repositoryId) { Lock lock = locksByRepositoryId.get(repositoryId); if (lock == null) { final Lock newLock = new ReentrantLock(); lock = locksByRepositoryId.putIfAbsent(repositoryId, newLock); if (lock == null) { // put succeeded, use new value lock = newLock; } } return lock; } /** * Returns the repository with the specified id. * * @param repositoryId * the repository id. * @return the repository * @throws IllegalStateException * if a repository with the specified id is not available */ public Repository getRepository(final String repositoryId) throws IllegalStateException { if (null == repositoryId) { throw new IllegalArgumentException("repository id must not be null"); } if (closed.get()) { throw new IllegalStateException("closed"); } // lookup a cached instance Repository repository = repositoryCache.get(repositoryId); if (null != repository) { return repository; } // get repository definition final RepositoryDefinition repositoryDef = getStore().findById(repositoryId); if (null == repositoryDef) { throw new IllegalStateException( MessageFormat.format("The repository with id \"{0}\" could not be found!", repositoryId)); } // create a new instance final Lock repositoryCreationLock = getOrCreateRepositoryLock(repositoryId); repositoryCreationLock.lock(); try { // make sure the cache is empty repository = repositoryCache.get(repositoryId); if (null != repository) { // use cached repository return repository; } // create the repository repository = createRepository(repositoryDef); // put the repository instance in the cache repositoryCache.put(repositoryId, repository); } finally { repositoryCreationLock.unlock(); } // register repository in state map registryState.put(STATE_REPOSITORY_PREFIX.concat(repositoryId), STATE_ACTIVE); // update the repository state (outside lock) updateRepositoryState(); // return the repository return repository; } @Override public RepositoryDefinition getRepositoryDefinition(final String repositoryId) { if (null == repositoryId) { throw new IllegalArgumentException("repository id must not be null"); } // get repository definition return getStore().findById(repositoryId); } @Override public Collection<String> getRepositoryIds() { return Collections.unmodifiableCollection(getStore().findRepositoryIds()); } RepositoryDefinitionsStore getStore() { final RepositoryDefinitionsStore store = repositoryDefinitionsStoreRef.get(); if (store != null) { return store; } if (repositoryDefinitionsStoreRef.compareAndSet(null, new RepositoryDefinitionsStore())) { RepositoryDefinitionsStore.getRepositoriesNode().addNodeChangeListener(repositoryModifcationListener); } return repositoryDefinitionsStoreRef.get(); } @Override public void removeRepository(final String repositoryId) throws IllegalArgumentException { getStore().remove(repositoryId); } /** * Stops the registry */ public void stop() { if (!closed.compareAndSet(false, true)) { return; } // un-publish state final ServiceRegistration<INodeState> registration = registryStateRegistration; if (null != registration) { try { registration.unregister(); } catch (final IllegalStateException e) { // ignore } } registryStateRegistration = null; registryState.clear(); // remove listener RepositoryDefinitionsStore.getRepositoriesNode().removeNodeChangeListener(repositoryModifcationListener); // close any open repository while (!repositoryCache.isEmpty()) { final Set<String> repoIds = repositoryCache.keySet(); for (final String repoId : repoIds) { close(repoId); } } } private void updateRepositoryState() { final ServiceRegistration<INodeState> stateRegistration = registryStateRegistration; if (null != stateRegistration) { try { stateRegistration.setProperties(registryState); } catch (final IllegalStateException e) { // ignore } catch (final Exception e) { LOG.error("Error updating repository state. {}", ExceptionUtils.getRootCauseMessage(e), e); } } } }