/** * 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.df.external; import static org.openbel.framework.core.df.cache.ResourceType.ANNOTATIONS; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.openbel.framework.common.AnnotationDefinitionResolutionException; import org.openbel.framework.common.model.AnnotationDefinition; import org.openbel.framework.common.model.CommonModelFactory; import org.openbel.framework.core.df.beldata.annotation.AnnotationHeader; import org.openbel.framework.core.df.beldata.annotation.AnnotationHeaderProcessor; import org.openbel.framework.core.df.cache.CacheLookupService; import org.openbel.framework.core.df.cache.CacheableResourceService; import org.openbel.framework.core.df.cache.CachedResource; import org.openbel.framework.core.df.cache.DefaultCacheLookupService; import org.openbel.framework.core.df.cache.DefaultCacheableResourceService; import org.openbel.framework.core.df.cache.ResolvedResource; import org.openbel.framework.core.indexer.IndexingFailure; import org.openbel.framework.core.protocol.ResourceDownloadError; /** * CacheableAnnotationDefinitionServiceImpl implements a service to resolve BEL * annotation files and cache the data for subsequent calls. * * @author Anthony Bargnesi {@code <abargnesi@selventa.com>} */ public class CacheableAnnotationDefinitionServiceImpl implements CacheableAnnotationDefinitionService { /** * Defines the resource cache service dependency. */ private final CacheableResourceService resourceCache; /** * Defines the cache lookup service dependency. */ private final CacheLookupService cacheLookupService; public CacheableAnnotationDefinitionServiceImpl( CacheableResourceService resourceCache, CacheLookupService cacheLookupService) { this.resourceCache = resourceCache; this.cacheLookupService = cacheLookupService; } public CacheableAnnotationDefinitionServiceImpl() { this.resourceCache = new DefaultCacheableResourceService(); this.cacheLookupService = new DefaultCacheLookupService(); } /** * {@inheritDoc} */ @Override public AnnotationDefinition resolveAnnotationDefinition( String resourceLocation) throws AnnotationDefinitionResolutionException { ResolvedResource resolveResource; try { resolveResource = resourceCache.resolveResource( ANNOTATIONS, resourceLocation); } catch (ResourceDownloadError e) { throw new AnnotationDefinitionResolutionException(resourceLocation, e.getMessage()); } File annotationCacheCopy = resolveResource.getCacheResourceCopy(); CachedResource cacheResource = cacheLookupService.findInCache( ANNOTATIONS, resourceLocation); AnnotationHeaderProcessor annotationHeaderProcessor = new AnnotationHeaderProcessor(); AnnotationHeader annotationHeader; try { annotationHeader = annotationHeaderProcessor .processAnnotationHeader(resourceLocation, annotationCacheCopy, cacheResource .getLocalFile()); } catch (IndexingFailure e) { throw new AnnotationDefinitionResolutionException(resourceLocation, e.getMessage()); } AnnotationDefinition annotationDefinition = CommonModelFactory .getInstance().createAnnotationDefinition(annotationHeader. getAnnotationBlock().getKeyword()); annotationDefinition.setDescription(annotationHeader .getAnnotationBlock().getDescriptionString()); annotationDefinition.setUsage(annotationHeader.getAnnotationBlock() .getUsageString()); annotationDefinition.setType(annotationHeader.getAnnotationBlock() .getAnnotationType()); annotationDefinition.setURL(resourceLocation); long characterOffset = annotationHeaderProcessor .getCharacterStopOffset(); try { switch (annotationDefinition.getType()) { case ENUMERATION: annotationDefinition.setEnums(parseEnumData( annotationCacheCopy, annotationHeader.getProcessingBlock() .getDelimiterString(), characterOffset)); break; case REGULAR_EXPRESSION: annotationDefinition.setValue(parseRegularExpression( annotationCacheCopy, characterOffset)); } } catch (IOException e) { throw new AnnotationDefinitionResolutionException(resourceLocation, e.getMessage()); } return annotationDefinition; } /** * Reads each line after the [Values] block as enumeration values for the * annotation definition. * * @param annotationCacheCopy {@link File}, the annotation file to read * from * @param valueDelimiter {@link String}, the delimiter that separates * annotation value lines * @param characterOffset <tt>long</tt>, the character offset of the * [Values] block in <tt>annotationCacheCopy</tt> * @return {@link List} of {@link String} that represents the enumeration * data * @throws IOException Thrown if an IO error occurred reading the BEL * annotation file */ private List<String> parseEnumData(File annotationCacheCopy, String valueDelimiter, long characterOffset) throws IOException { List<String> enumData = new ArrayList<String>(); BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(annotationCacheCopy)); reader.skip(characterOffset); String line = ""; while ((line = reader.readLine()) != null) { String[] lineTokens = StringUtils.splitByWholeSeparator(line, valueDelimiter); if (lineTokens != null && lineTokens.length >= 1) { enumData.add(lineTokens[0]); } } } finally { if (reader != null) { try { reader.close(); } catch (Exception e) {} } } return enumData; } /** * Reads the first line after the annotation header as a regular expression * for the annotation definition. * * @param annotationCacheCopy * {@link File}, the annotation cache copy to parse * @param characterOffset * <tt>long</tt>, the character offset to start reading from * @return {@link String} the parsed regular expression * @throws IOException * Thrown if an IO error occurred reading the annotation file */ private String parseRegularExpression(File annotationCacheCopy, long characterOffset) throws IOException { BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(annotationCacheCopy)); reader.skip(characterOffset); return reader.readLine(); } finally { if (reader != null) { try { reader.close(); } catch (Exception e) {} } } } }