/* * Copyright (C) 2014 University of Dundee & Open Microscopy Environment. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package ome.services.query; import java.util.Collection; import java.util.Map; import java.util.Set; import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.SetMultimap; import ome.api.IQuery; /** * Convenience class for creating versions of {@link HierarchyNavigator} with different model object representations. * @author m.t.b.carroll@dundee.ac.uk * @since 5.0 */ public abstract class HierarchyNavigatorWrap<T, E> extends HierarchyNavigator { public HierarchyNavigatorWrap(IQuery iQuery) { super(iQuery); } /** * Convert the given object type to the type strings expected by {@link HierarchyNavigator}. * @param type an object type * @return the corresponding type string */ protected abstract String typeToString(T type); /** * Convert the given type string to the object type. * @param typeName a type string * @return the corresponding object type */ protected abstract T stringToType(String typeName); /** * Convert a model object to the type string and database ID expected by {@link HierarchyNavigator}. * @param entity a model object * @return the corresponding type string and database ID */ protected abstract Map.Entry<String, Long> entityToStringLong(E entity); /** * Convert the given type string and database ID to the model object. * @param typeName a type string * @param id a database ID * @return the corresponding model object */ protected abstract E stringLongToEntity(String typeName, long id); /** * Batch bulk database queries to prime the cache for {@link #doLookup(Object, Object)}. * It is not necessary to call this method, but it is advised if many lookups are anticipated. * Wraps {@link HierarchyNavigator#prepareLookups(String, String, Collection)}. * @param toType the type of the objects to which the query objects may be related, not <code>null</code> * @param from the query objects, none <code>null</code>, may be of differing types */ public void prepareLookups(T toType, Collection<E> from) { final String toTypeAsString = typeToString(toType); final SetMultimap<String, Long> fromIdsByType = HashMultimap.create(); for (final E entity : from) { final Map.Entry<String, Long> fromAsStringLong = entityToStringLong(entity); fromIdsByType.put(fromAsStringLong.getKey(), fromAsStringLong.getValue()); } for (final String fromTypeAsString : fromIdsByType.keySet()) { final Set<Long> fromIdsAsLongs = fromIdsByType.get(fromTypeAsString); prepareLookups(toTypeAsString, fromTypeAsString, fromIdsAsLongs); } } /** * Look up which objects of a given type relate to the given query object. * Caches results, and one may bulk-cache results in advance using {@link #prepareLookups(Object, Collection)}. * Wraps {@link HierarchyNavigator#doLookup(String, String, Long)}. * @param toType the type of the objects to which the query object may be related, not <code>null</code> * @param from the query object, not <code>null</code> * @return the related objects, never <code>null</code> */ public ImmutableSet<E> doLookup(T toType, E from) { final String toTypeAsString = typeToString(toType); final Map.Entry<String, Long> fromAsStringLong = entityToStringLong(from); final ImmutableSet.Builder<E> to = ImmutableSet.builder(); for (final Long toIdAsLong : doLookup(toTypeAsString, fromAsStringLong.getKey(), fromAsStringLong.getValue())) { to.add(stringLongToEntity(toTypeAsString, toIdAsLong)); } return to.build(); } }