/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * 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: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.db.layer0.adapter.impl; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.primitiverequest.Adapter; import org.simantics.db.common.procedure.adapter.TransientCacheListener; import org.simantics.db.common.request.ObjectsWithType; import org.simantics.db.common.request.TernaryRead; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.adapter.Instances; import org.simantics.db.layer0.genericrelation.IndexQueries; import org.simantics.db.layer0.util.Layer0Utils; import org.simantics.db.request.ReadExt; import org.simantics.db.request.RequestFlags; import org.simantics.db.service.CollectionSupport; import org.simantics.layer0.Layer0; import org.simantics.operation.Layer0X; import org.simantics.scl.runtime.function.Function; import gnu.trove.set.hash.THashSet; /** * @author Antti Villberg * @author Tuukka Lehtonen */ public class EntityInstances implements Instances { private static final boolean TRACE_QUERIES = false; private final Resource type; public EntityInstances(Resource type) { this.type = type; } @Override public Collection find(ReadGraph graph, Resource index) throws DatabaseException { return find(graph, index, ""); } /** * A (cacheable) query to optimize single index queries for immutable * indexes such as ontologies. */ public static class QueryIndex extends TernaryRead> implements ReadExt { public QueryIndex(Resource index, Resource type, String filter) { super(index, type, filter); } @Override public List perform(ReadGraph graph) throws DatabaseException { Resource type = parameter2; Layer0 L0 = Layer0.getInstance(graph); Layer0X L0X = Layer0X.getInstance(graph); String typeName = graph.getRelatedValue(type, L0.HasName); if (typeName.isEmpty()) return Collections.emptyList(); @SuppressWarnings({ "unchecked", "rawtypes" }) Function dependencyResources = graph.syncRequest(new Adapter(L0X.DependencyResources, Function.class), TransientCacheListener.instance()); StringBuilder filtersb = new StringBuilder(); filtersb.append("Types:*").append( IndexQueries.escape( typeName, true ) ); if (parameter3.length() > 0) filtersb.append(" AND ").append( parameter3 ); String filter = filtersb.toString(); if (TRACE_QUERIES) { System.out.println("EntityInstances.QueryIndex: finding " + filter + " from index " + graph.getPossibleURI(parameter)); //new Exception("EntityInstances: finding " + filter + " from index " + graph.getPossibleURI(parameter)).printStackTrace(); } @SuppressWarnings("unchecked") List results = (List)dependencyResources.apply(graph, parameter, filter); if (results == null || results.isEmpty()) return Collections.emptyList(); if (TRACE_QUERIES) System.out.println(" EntityInstances.QueryIndex: got " + results.size() + " results"); // // TreeSet to keep the results in deterministic order. // Set resultSet = new TreeSet(); // for (Map entry : results) { // Resource res = (Resource)entry.get("Resource"); // if (res != null && !resultSet.contains(res)) // resultSet.add(res); // } CollectionSupport coll = graph.getService(CollectionSupport.class); List result = coll.createList(); for (Resource res : Layer0Utils.sortByCluster(graph, results)) { if (graph.isInstanceOf(res, type)) result.add(res); } if (TRACE_QUERIES) System.out.println(" EntityInstances.QueryIndex: got " + results.size() + " unique type-matching results"); return result; } @Override public String toString() { return "QueryIndex " + parameter + " " + parameter2 + " " + parameter3; } @Override public boolean isImmutable(ReadGraph graph) throws DatabaseException { // TODO Auto-generated method stub return false; } @Override public int getType() { return RequestFlags.IMMEDIATE_UPDATE; } } private List findRec(ReadGraph graph, Resource index, String filter, Set visited) throws DatabaseException { if(!visited.add(index)) return Collections.emptyList(); CollectionSupport coll = graph.getService(CollectionSupport.class); List indexResult = graph.syncRequest(new QueryIndex(index, type, filter), TransientCacheListener.>instance()); Layer0 L0 = Layer0.getInstance(graph); Collection linkedRoots = graph.syncRequest(new ObjectsWithType(index, L0.IsLinkedTo, L0.IndexRoot)); if (linkedRoots.isEmpty()) return indexResult; List result = indexResult; for (Resource dep : linkedRoots) { Collection linkedIndexResults = findRec(graph, dep, filter, visited); if (linkedIndexResults.isEmpty()) continue; if (result == indexResult) { result = coll.createList(); result.addAll(indexResult); } else { } result.addAll(linkedIndexResults); } return result; } @Override public Collection find(ReadGraph graph, Resource index, String filter) throws DatabaseException { CollectionSupport coll = graph.getService(CollectionSupport.class); THashSet visited = new THashSet<>(); List rec = findRec(graph, index, filter, visited); for(Resource global : Layer0Utils.listGlobalOntologies(graph)) { if(!visited.add(global)) continue; List rs = graph.syncRequest(new QueryIndex(global, type, filter), TransientCacheListener.>instance()); if(rec.isEmpty() && !rs.isEmpty()) { // TODO: rec could be an immutable empty list rec = new ArrayList(); } rec.addAll(rs); } Collection result = coll.asSortedList(rec); return result; } @Override public Collection findByName(ReadGraph graph, Resource model, String name) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); CollectionSupport coll = graph.getService(CollectionSupport.class); List results = coll.createList(); for(Resource match : find(graph, model, name)) { if(name.equals(graph.getPossibleRelatedValue(match, L0.HasName, Bindings.STRING))) results.add(match); } return results; } }