/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.resources;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.whole.lang.codebase.IPersistenceProvider;
import org.whole.lang.model.IEntity;
/**
* @author Riccardo Solmi
*/
public class ResourceRegistry<T extends IResource> implements IResourceRegistry<T> {
protected List<IResourceRegistryListener<T>> resourceRegistryListeners = new ArrayList<IResourceRegistryListener<T>>();
protected IResourceFactoryRegistry resourceFactoryRegistry;
protected IURIResolverRegistry uriResolverRegistry;
private Set<T> publicResources = new HashSet<T>();
private Map<String, T> uriResourceMap = new HashMap<String, T>();
private Map<String, Set<T>> qnameResourcesMap = new HashMap<String, Set<T>>();
private Map<String, Integer> nameOccurrencesMap = new HashMap<String, Integer>();
protected ResourceRegistry() {
this(new URLURIResolver(), new ClasspathURIResolver(), new WholeURIResolver(), new FileURIResolver());
}
protected ResourceRegistry(IURIResolver... uriResolvers) {
resourceFactoryRegistry = new ResourceFactoryRegistry(this);
uriResolverRegistry = new URIResolverRegistry(this);
for (IURIResolver uriResolver : uriResolvers)
uriResolverRegistry.addURIResolver(uriResolver);
}
public void addResourceRegistryListener(IResourceRegistryListener<T> listener) {
resourceRegistryListeners.add(listener);
}
public void removeResourceRegistryListener(IResourceRegistryListener<T> listener) {
resourceRegistryListeners.remove(listener);
}
public IResourceFactoryRegistry getResourceFactoryRegistry() {
return resourceFactoryRegistry;
}
public IURIResolverRegistry getURIResolverRegistry() {
return uriResolverRegistry;
}
private static Map<String, IResourceRegistry<?>> registryMap = new HashMap<String, IResourceRegistry<?>>();
public static boolean hasRegistry(String id) {
return registryMap.containsKey(id);
}
@SuppressWarnings("unchecked")
public static <T extends IResource> IResourceRegistry<T> getRegistry(String id) {
IResourceRegistry<T> registry = (IResourceRegistry<T>) registryMap.get(id);
if (registry == null)
putRegistry(id, registry = new ResourceRegistry<T>());
return registry;
}
public static void putRegistry(String id, IResourceRegistry<?> registry) {
registryMap.put(id, registry);
}
public int getResourceNameOccurrences(T resource) {
Integer occurrences = nameOccurrencesMap.get(resource.getName());
return occurrences != null ? occurrences : 0;
}
public int getResourceQualifiedNameOccurrences(T resource) {
Set<T> resourceSet = qnameResourcesMap.get(resource.getQualifiedName());
return resourceSet != null ? resourceSet.size() : 0;
}
public boolean isResourceVersionAmbiguous(T resource) {
Set<T> resourceSet = qnameResourcesMap.get(resource.getQualifiedName());
if (resourceSet != null && resourceSet.size() >= 2) {
String version = resource.getVersion();
for (T other : resourceSet)
if (version.equals(other.getVersion()) && !resource.equals(other))
return true;
}
return false;
}
public boolean containsResource(String uri, boolean loadOnDemand, String contextUri) {
return getResource(uri, loadOnDemand, contextUri) != null;
}
protected Set<String> uriFailureSet = new HashSet<String>();
@SuppressWarnings("unchecked")
public T getResource(String uri, boolean loadOnDemand, String contextUri) {
T resource = uriResourceMap.get(uri);
if (resource == null && loadOnDemand && !uriFailureSet.contains(uri))
try {
IPersistenceProvider pp = getURIResolverRegistry().resolve(contextUri, uri);
if (pp.exists()) {
resource = (T) getResourceFactoryRegistry().createResource(uri);
resource.setResourcePersistenceProvider(pp);
uriResourceMap.put(uri, resource);
final boolean isValidResource = resource.getEntity() != null && resource.getName() != null;
uriResourceMap.remove(uri);
if (isValidResource)
addResource(resource, false);
else {
resource = null;
uriFailureSet.add(uri);
}
}
} catch (IllegalArgumentException e) {
}
return resource;
}
public <E extends IEntity> E getResourceModel(String uri, boolean loadOnDemand, String contextUri) {
IResource resource = getResource(uri, loadOnDemand, contextUri);
return resource == null ? null : resource.<E>getEntity();
}
@SuppressWarnings("unchecked")
public T createResource(String uri, boolean hidden) {
T resource = (T) getResourceFactoryRegistry().createResource(uri);
try {
IPersistenceProvider pp = getURIResolverRegistry().resolve(null, uri);
resource.setResourcePersistenceProvider(pp);
} catch (IllegalArgumentException e) {
}
addResource(resource, hidden);
return resource;
}
@SuppressWarnings("unchecked")
public boolean addResource(IEntity entity, String uri, boolean hidden) {
T resource = (T) getResourceFactoryRegistry().createResource(uri, entity.wGetEntityDescriptor());
resource.setEntity(entity);
return addResource(resource, hidden);
}
public boolean addResource(T resource, boolean hidden) {
T oldResource = getResource(resource.getURI(), false, null);
boolean removed = removeResource(resource.getURI());
uriResourceMap.put(resource.getURI(), resource);
((Resource) resource).setResourceRegistry(this);//TODO InternalIResource
if (!hidden)
publicResources.add(resource);
String resourceQName = resource.getQualifiedName();
if (resourceQName != null) {
Set<T> resourceSet = qnameResourcesMap.get(resourceQName);
if (resourceSet == null)
qnameResourcesMap.put(resourceQName, resourceSet = new HashSet<T>());
resourceSet.add(resource);
}
String resourceName = resource.getName();
if (resourceName != null) {
Integer occurrences = nameOccurrencesMap.get(resourceName);
if (occurrences == null)
nameOccurrencesMap.put(resourceName, new Integer(1));
else
nameOccurrencesMap.put(resourceName, new Integer(occurrences.intValue() + 1));
}
if (removed)
for (IResourceRegistryListener<T> resourceChangeHandler : resourceRegistryListeners)
resourceChangeHandler.notifyChanged(oldResource, resource);
else
for (IResourceRegistryListener<T> resourceChangeHandler : resourceRegistryListeners)
resourceChangeHandler.notifyAdded(resource);
return !removed;
}
public boolean removeResource(String uri) {
T resource = uriResourceMap.remove(uri);
if (resource == null)
return false;
publicResources.remove(resource);
((Resource) resource).setResourceRegistry(null);//TODO InternalIResource
String resourceQName = resource.getQualifiedName();
if (resourceQName != null) {
Set<T> resourceSet = qnameResourcesMap.get(resourceQName);
if (resourceSet != null) {
resourceSet.remove(resource);
if (resourceSet.isEmpty())
qnameResourcesMap.remove(resourceQName);
}
}
String resourceName = resource.getName();
if (resourceName != null && nameOccurrencesMap.containsKey(resourceName)) {
int occurrences = nameOccurrencesMap.get(resourceName);
if (occurrences == 1)
nameOccurrencesMap.remove(resourceName);
else
nameOccurrencesMap.put(resourceName, new Integer(occurrences - 1));
}
for (IResourceRegistryListener<T> resourceChangeHandler : resourceRegistryListeners)
resourceChangeHandler.notifyRemoved(resource);
return true;
}
public Set<T> getResourceVersions(String qualifiedName) {
Set<T> resourceVersions = qnameResourcesMap.get(qualifiedName);
return resourceVersions != null ?
resourceVersions : Collections.<T>emptySet();
}
public Collection<T> getResources(boolean includeHidden) {
return Collections.unmodifiableCollection(
includeHidden ? uriResourceMap.values() : publicResources);
}
public SortedSet<T> getResources(boolean includeHidden, Comparator<? super T> comparator) {
SortedSet<T> sortedSet = new TreeSet<T>(comparator);
sortedSet.addAll(
includeHidden ? uriResourceMap.values() : publicResources);
return sortedSet;
}
}