/**
* Copyright (C) 2012-2013 Selventa, Inc.
*
* This file is part of the OpenBEL Framework.
*
* This program 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 OpenBEL Framework 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 OpenBEL Framework. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms under LGPL v3:
*
* This license does not authorize you and you are prohibited from using the
* name, trademarks, service marks, logos or similar indicia of Selventa, Inc.,
* or, in the discretion of other licensors or authors of the program, the
* name, trademarks, service marks, logos or similar indicia of such authors or
* licensors, in any marketing or advertising materials relating to your
* distribution of the program or any covered product. This restriction does
* not waive or limit your obligation to keep intact all copyright notices set
* forth in the program as delivered to you.
*
* If you distribute the program in whole or in part, or any modified version
* of the program, and you assume contractual liability to the recipient with
* respect to the program or modified version, then you will indemnify the
* authors and licensors of the program for any liabilities that these
* contractual assumptions directly impose on those licensors and authors.
*/
package org.openbel.framework.core.equivalence;
import static org.openbel.framework.common.BELUtilities.hasItems;
import static org.openbel.framework.common.cfg.SystemConfiguration.getSystemConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.stream.XMLStreamException;
import org.openbel.framework.common.InvalidArgument;
import org.openbel.framework.common.cfg.SystemConfiguration;
import org.openbel.framework.common.index.Equivalence;
import org.openbel.framework.common.index.Index;
import org.openbel.framework.common.index.ResourceIndex;
import org.openbel.framework.common.model.DataFileIndex;
import org.openbel.framework.common.model.EquivalenceDataIndex;
import org.openbel.framework.common.model.Namespace;
import org.openbel.framework.common.model.Parameter;
import org.openbel.framework.common.protonetwork.model.SkinnyUUID;
import org.openbel.framework.core.df.cache.CacheableResourceService;
import org.openbel.framework.core.df.cache.DefaultCacheableResourceService;
import org.openbel.framework.core.df.cache.ResolvedResource;
import org.openbel.framework.core.df.cache.ResourceType;
import org.openbel.framework.core.indexer.IndexingFailure;
import org.openbel.framework.core.indexer.JDBMEquivalenceLookup;
import org.openbel.framework.core.protocol.ResourceDownloadError;
public final class DefaultParameterEquivalencer implements
ParameterEquivalencer {
private static DefaultParameterEquivalencer instance;
private final Map<String, JDBMEquivalenceLookup> openEquivalences;
private Index resourceIndex;
private final CacheableResourceService cacheService;
private final EquivalenceIndexerService eqIndexer;
private DefaultParameterEquivalencer() throws IOException,
ResourceDownloadError, XMLStreamException {
openEquivalences =
new ConcurrentHashMap<String, JDBMEquivalenceLookup>();
cacheService = new DefaultCacheableResourceService();
eqIndexer = new EquivalenceIndexerServiceImpl();
if (!ResourceIndex.INSTANCE.isLoaded()) {
// Load resource index defined by the BELFramework instance
final SystemConfiguration sysConfig = getSystemConfiguration();
final String resourceIndexURL = sysConfig.getResourceIndexURL();
File indexFile = new File(resourceIndexURL);
if (!indexFile.exists() || !indexFile.canRead()) {
// try the index as an online resource.
ResolvedResource resolvedResource = cacheService
.resolveResource(ResourceType.RESOURCE_INDEX,
resourceIndexURL);
indexFile = resolvedResource.getCacheResourceCopy();
}
ResourceIndex.INSTANCE.loadIndex(indexFile);
}
resourceIndex = ResourceIndex.INSTANCE.getIndex();
}
public static synchronized DefaultParameterEquivalencer getInstance()
throws ResourceDownloadError, IOException, XMLStreamException {
if (instance == null) {
instance = new DefaultParameterEquivalencer();
}
return instance;
}
/**
* {@inheritDoc}
*/
@Override
public List<Parameter> findEquivalences(Parameter sourceParameter)
throws ResourceDownloadError, IndexingFailure, IOException {
openAllEquivalences();
final List<Parameter> equivalentParameters = new ArrayList<Parameter>();
Set<Entry<String, JDBMEquivalenceLookup>> equivalenceEntries =
openEquivalences.entrySet();
for (Entry<String, JDBMEquivalenceLookup> equivalenceEntry : equivalenceEntries) {
final String equivalentValue = doFindEquivalence(sourceParameter
.getNamespace().getResourceLocation(),
equivalenceEntry.getKey(),
sourceParameter.getValue());
if (equivalentValue != null) {
equivalentParameters.add(new Parameter(new Namespace("",
equivalenceEntry.getKey()), equivalentValue));
}
}
return equivalentParameters;
}
/**
* {@inheritDoc}
*/
@Override
public Parameter findEquivalence(Parameter sourceParameter,
Namespace destinationNamespace) throws ResourceDownloadError,
IndexingFailure, IOException {
// open equivalences for source and destination namespaces.
final String srl = sourceParameter.getNamespace().getResourceLocation();
openEquivalence(srl);
openEquivalence(destinationNamespace.getResourceLocation());
final String equivalentValue = doFindEquivalence(sourceParameter
.getNamespace().getResourceLocation(),
destinationNamespace.getResourceLocation(),
sourceParameter.getValue());
if (equivalentValue == null) {
return null;
}
return new Parameter(destinationNamespace, equivalentValue);
}
/**
* {@inheritDoc}
*/
@Override
public List<Parameter> findEquivalences(SkinnyUUID sourceUUID)
throws ResourceDownloadError, IndexingFailure, IOException {
openAllEquivalences();
final List<Parameter> equivalentParameters = new ArrayList<Parameter>();
Set<Entry<String, JDBMEquivalenceLookup>> equivalenceEntries =
openEquivalences.entrySet();
for (Entry<String, JDBMEquivalenceLookup> equivalenceEntry : equivalenceEntries) {
final String equivalentValue = doFindEquivalence(
equivalenceEntry.getKey(),
sourceUUID);
if (equivalentValue != null) {
equivalentParameters.add(new Parameter(new Namespace("",
equivalenceEntry.getKey()), equivalentValue));
}
}
return equivalentParameters;
}
/**
* {@inheritDoc}
*/
@Override
public Parameter findEquivalence(SkinnyUUID sourceUUID,
Namespace destinationNamespace) throws ResourceDownloadError,
IndexingFailure, IOException {
// open equivalences for destination namespace.
openEquivalence(destinationNamespace.getResourceLocation());
final String equivalentValue = doFindEquivalence(
destinationNamespace.getResourceLocation(),
sourceUUID);
if (equivalentValue == null) {
return null;
}
return new Parameter(destinationNamespace, equivalentValue);
}
/**
* {@inheritDoc}
*/
@Override
public void openAllEquivalences() throws ResourceDownloadError,
IndexingFailure, IOException {
if (hasItems(resourceIndex.getEquivalenceResources())) {
// open all equivalences that are not already open
for (Equivalence eqResource : resourceIndex
.getEquivalenceResources()) {
if (!openEquivalences.containsKey(eqResource
.getNamespaceResourceLocation().getResourceLocation())) {
openEquivalence(eqResource);
}
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void closeAllEquivalences() throws ResourceDownloadError,
IndexingFailure, IOException {
final Iterator<JDBMEquivalenceLookup> equivalenceIndexIt =
openEquivalences.values().iterator();
while (equivalenceIndexIt.hasNext()) {
final JDBMEquivalenceLookup jdbmLookup = equivalenceIndexIt.next();
// close the JDBM lookup
jdbmLookup.close();
// remove from open equivalences map
equivalenceIndexIt.remove();
}
}
/**
* {@inheritDoc}
*/
@Override
public SkinnyUUID getUUID(Parameter param) throws ResourceDownloadError,
IndexingFailure, IOException {
String srl = param.getNamespace().getResourceLocation();
openEquivalence(srl);
JDBMEquivalenceLookup lookup = openEquivalences.get(srl);
return lookup.lookup(param.getValue());
}
/**
* Obtain the destinationNamespace equivalent value of sourceValue in sourceNamespace
* @param sourceNamespace resourceLocation of source namespace
* @param destinationNamespace resourceLocation of destination namespace
* @param sourceValue
* @return equivalent value, may be null.
*/
private String doFindEquivalence(final String sourceNamespace,
final String destinationNamespace, final String sourceValue) {
JDBMEquivalenceLookup sourceLookup =
openEquivalences.get(sourceNamespace);
if (sourceLookup == null) {
return null;
}
final SkinnyUUID sourceUUID = sourceLookup.lookup(sourceValue);
if (sourceUUID == null) {
return null;
}
return doFindEquivalence(destinationNamespace, sourceUUID);
}
/**
* Obtain the destinationNamespace equivalent value of the sourceUUID.
* @param destinationNamespace resourceLocation of destination namespace
* @param sourceUUID
* @return equivalent value, may be null
*/
private String doFindEquivalence(final String destinationNamespace,
final SkinnyUUID sourceUUID) {
JDBMEquivalenceLookup destinationLookup = openEquivalences
.get(destinationNamespace);
return destinationLookup.reverseLookup(sourceUUID);
}
private void openEquivalence(final String namespaceResourceLocation)
throws ResourceDownloadError, IndexingFailure, IOException {
// if we've opened an equivalence for this namespace, do nothing.
if (openEquivalences.containsKey(namespaceResourceLocation)) {
return;
}
if (hasItems(resourceIndex.getEquivalenceResources())) {
Equivalence equivalence = null;
// find equivalence for namespace resource location
for (Equivalence eqResource : resourceIndex
.getEquivalenceResources()) {
if (namespaceResourceLocation.equals(eqResource
.getNamespaceResourceLocation().getResourceLocation())) {
equivalence = eqResource;
break;
}
}
if (equivalence == null) {
// TODO Better exception
throw new InvalidArgument(
"Namespace '"
+ namespaceResourceLocation
+ "' is not defined or is not backed by an equivalence.");
}
openEquivalence(equivalence);
}
}
private void openEquivalence(final Equivalence equivalence)
throws ResourceDownloadError, IndexingFailure, IOException {
synchronized (equivalence.getResourceLocation()) {
ResolvedResource resolved =
cacheService.resolveResource(ResourceType.EQUIVALENCES,
equivalence.getResourceLocation());
final DataFileIndex equivalenceIndex =
eqIndexer.indexEquivalence(
equivalence.getResourceLocation(),
resolved.getCacheResourceCopy());
final EquivalenceDataIndex dataIndex = new EquivalenceDataIndex(
equivalence.getNamespaceResourceLocation()
.getResourceLocation(), equivalenceIndex);
JDBMEquivalenceLookup jdbmLookup =
new JDBMEquivalenceLookup(dataIndex.getEquivalenceIndex()
.getIndexPath());
jdbmLookup.open();
openEquivalences.put(equivalence.getNamespaceResourceLocation()
.getResourceLocation(),
jdbmLookup);
}
}
}