/** * Copyright 2014 IHTSDO * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ihtsdo.otf.snomed.service; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.apache.commons.configuration.Configuration; import org.ihtsdo.otf.refset.exception.EntityNotFoundException; import org.ihtsdo.otf.refset.graph.RefsetGraphFactory; import org.ihtsdo.otf.snomed.domain.Concept; import org.ihtsdo.otf.snomed.domain.Properties; import org.ihtsdo.otf.snomed.domain.Relationship; import org.ihtsdo.otf.snomed.exception.ConceptServiceException; import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; import org.springframework.util.StringUtils; import com.thinkaurelius.titan.core.TitanGraph; import com.thinkaurelius.titan.core.TitanIndexQuery.Result; import com.tinkerpop.blueprints.Direction; import com.tinkerpop.blueprints.Edge; import com.tinkerpop.blueprints.Vertex; /** * Service to look up Terminology data. * */ public class ConceptLookUpServiceImplv1_0 implements ConceptLookupService { private static final Logger LOGGER = LoggerFactory.getLogger(ConceptLookUpServiceImplv1_0.class); private Configuration config; private RefsetGraphFactory factory; /* (non-Javadoc) * @see org.ihtsdo.otf.snomed.service.ConceptLookupService#getConcepts(java.util.List) */ @Override @Cacheable(value = { "concepts" }) public Map<String, Concept> getConcepts(Set<String> conceptIds) throws ConceptServiceException { LOGGER.debug("getting concepts details for {}", conceptIds); Map<String, Concept> concepts = new HashMap<String, Concept>(); TitanGraph g = null; try { g = factory.getReadOnlyGraph(); /**/ List<String> idLst = new ArrayList<String>(); idLst.addAll(conceptIds); int length = idLst.size()/1024; int to = idLst.size() > 1024 ? 1024 : conceptIds.size(); int from = 0; for (int i = 0; i < length+1; i++) { LOGGER.debug("getting concept description from {} to {} ", from, to); List<String> subList = idLst.subList(from, to); String ids = org.apache.commons.lang.StringUtils.join(subList, " OR "); Iterable<Result<Vertex>> vs = g.indexQuery("concept","v.sctid:" + ids).vertices(); for (Result<Vertex> r : vs) { Vertex v = r.getElement(); Object sctid = v.getProperty(Properties.sctid.toString()); Object label = v.getProperty(Properties.title.toString()); if (sctid != null && label != null && idLst.contains(sctid.toString())) { Concept c = new Concept(); c.setId(sctid.toString()); Long effectiveTime = v.getProperty(Properties.effectiveTime.toString()); if (effectiveTime != null) { c.setEffectiveTime(new DateTime(effectiveTime)); } String status = v.getProperty(Properties.status.toString()); boolean active = "1".equals(status) ? true : false; c.setActive(active); c.setLabel(label.toString()); Iterable<Edge> es = v.getEdges(Direction.OUT, Relationship.hasModule.toString()); for (Edge edge : es) { Vertex vE = edge.getVertex(Direction.IN); if (vE != null) { String moduleId = vE.getProperty(Properties.sctid.toString()); c.setModule(moduleId); break; } } concepts.put(sctid.toString(), c); } } //to run next loop if required from = to > idLst.size() ? idLst.size() : to; to = (to + 1024) > idLst.size() ? idLst.size() : to+1024; } RefsetGraphFactory.commit(g); } catch (Exception e) { LOGGER.error("Error duing concept details for concept map fetch", e); RefsetGraphFactory.rollback(g); throw new ConceptServiceException(e); } finally { RefsetGraphFactory.shutdown(g); } LOGGER.debug("returning total {} concepts ", concepts.size()); return Collections.unmodifiableMap(concepts); } /* (non-Javadoc) * @see org.ihtsdo.otf.snomed.service.ConceptLookupService#getConcept(java.lang.String) */ @Override @Cacheable(value = { "concept" }) public Concept getConcept(String conceptId) throws ConceptServiceException, EntityNotFoundException { LOGGER.debug("getting concept details for {} ", conceptId); if (StringUtils.isEmpty(conceptId)) { throw new EntityNotFoundException(String.format("Invalid concept id", conceptId)); } TitanGraph g = null; try { g = factory.getReadOnlyGraph(); Iterable<Vertex> vs = g.getVertices(Properties.sctid.toString(), conceptId); for (Vertex r : vs) { Concept c = new Concept(); Vertex v = r; String sctId = v.getProperty(Properties.sctid.toString()); c.setId(sctId); Long effectiveTime = v.getProperty(Properties.effectiveTime.toString()); if (effectiveTime != null) { c.setEffectiveTime(new DateTime(effectiveTime)); } String status = v.getProperty(Properties.status.toString()); boolean active = "1".equals(status) ? true : false; c.setActive(active); String label = v.getProperty(Properties.title.toString()); c.setLabel(label); Iterable<Edge> es = v.getEdges(Direction.OUT, Relationship.hasModule.toString()); for (Edge edge : es) { Vertex vE = edge.getVertex(Direction.IN); if (vE != null) { String moduleId = vE.getProperty(Properties.sctid.toString()); c.setModule(moduleId); break; } } RefsetGraphFactory.commit(g); return c; } RefsetGraphFactory.commit(g); } catch (Exception e) { LOGGER.error("Error duing concept details fetch", e); RefsetGraphFactory.rollback(g); throw new ConceptServiceException(e); } finally { RefsetGraphFactory.shutdown(g); } throw new EntityNotFoundException(String.format("Invalid concept id", conceptId)); } /* (non-Javadoc) * @see org.ihtsdo.otf.snomed.service.ConceptLookupService#getConceptIds(int, int) */ @Override @Cacheable(value = { "conceptIds" }) public Set<String> getConceptIds(int offset, int limit) throws ConceptServiceException { LOGGER.debug("getting concept ids with offset {} and limit {} ", offset, limit); TreeSet<String> conceptIds = new TreeSet<String>(); TitanGraph g = null; try { g = factory.getReadOnlyGraph(); Iterable<Result<Vertex>> vs = g.indexQuery("concept","v.sctid:*").offset(offset).limit(limit).vertices(); for (Result<Vertex> v : vs) { String sctid = v.getElement().getProperty(Properties.sctid.toString()); if (!StringUtils.isEmpty(sctid)) { LOGGER.trace("Adding sctid {} to concept id list ", sctid); conceptIds.add(sctid); } } RefsetGraphFactory.commit(g); } catch (Exception e) { LOGGER.error("Error duing concept ids fetch ", e); RefsetGraphFactory.rollback(g); throw new ConceptServiceException(e); } finally { RefsetGraphFactory.shutdown(g); } LOGGER.debug("returning total {} concept ids ", conceptIds.size()); return Collections.unmodifiableSortedSet(conceptIds); } /* (non-Javadoc) * @see org.ihtsdo.otf.snomed.service.ConceptLookupService#getTypes(String) */ @Override public Map<String, String> getTypes(String id) throws ConceptServiceException { LOGGER.debug("getting types for given id {}", id); Map<String, String> types = new HashMap<String, String>(); TitanGraph g = null; try { g = factory.getReadOnlyGraph(); } catch (Exception e) { LOGGER.error("Error duing concept details for concept map fetch", e); throw new ConceptServiceException(e); } finally { RefsetGraphFactory.shutdown(g); } LOGGER.debug("returning total {} types ", types.size()); return Collections.unmodifiableMap(types); } /** * @param config the config to set */ public void setConfig(Configuration config) { this.config = config; } /** * @param factory the factory to set */ @Autowired public void setFactory(RefsetGraphFactory factory) { this.factory = factory; } }