/*
* Copyright (C) 2014-2016 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 omero.cmd.graphs;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.base.Function;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.SetMultimap;
import ome.model.IObject;
import ome.security.ACLVoter;
import ome.security.SystemTypes;
import ome.services.graphs.GraphPathBean;
import ome.services.graphs.GraphPolicy;
import ome.services.graphs.GraphTraversal;
import omero.cmd.ERR;
import omero.cmd.Helper;
/**
* Factors common code out of {@link omero.cmd.GraphModify2} implementations for reuse.
* @author m.t.b.carroll@dundee.ac.uk
* @since 5.2.3
*/
public class GraphHelper {
private final Helper helper;
private final GraphPathBean graphPathBean;
/**
* Construct a helper for a graph request instance.
* @param helper the general request helper for the graph request instance
* @param graphPathBean the graph path bean
*/
public GraphHelper(Helper helper, GraphPathBean graphPathBean) {
this.helper = helper;
this.graphPathBean = graphPathBean;
}
/**
* Construct a graph traversal manager for a {@link omero.cmd.GraphModify2} request.
* @param childOptions the child options set on the request
* @param requiredPermissions the abilities that the user must have to operate upon an object for it to be included
* @param graphPolicy the graph policy for the request
* @param graphPolicyAdjusters the adjusters to be applied to the graph policy
* @param aclVoter ACL voter for permissions checking
* @param systemTypes for identifying the system types
* @param graphPathBean the graph path bean
* @param unnullable properties that, while nullable, may not be nulled by a graph traversal operation
* @param processor how to operate on the resulting target object graph
* @param dryRun if the request should skip the actual model object updates
* @return the new graph traversal manager
*/
public GraphTraversal prepareGraphTraversal(List<ChildOption> childOptions, Set<GraphPolicy.Ability> requiredPermissions,
GraphPolicy graphPolicy, Iterable<Function<GraphPolicy, GraphPolicy>> graphPolicyAdjusters,
ACLVoter aclVoter, SystemTypes systemTypes, GraphPathBean graphPathBean,
SetMultimap<String, String> unnullable, GraphTraversal.Processor processor, boolean dryRun) {
if (childOptions != null) {
final List<ChildOptionI> childOptionsI = ChildOptionI.castChildOptions(childOptions);
for (final ChildOptionI childOption : childOptionsI) {
childOption.init();
}
graphPolicy = ChildOptionsPolicy.getChildOptionsPolicy(graphPolicy, childOptionsI, requiredPermissions);
}
for (final Function<GraphPolicy, GraphPolicy> adjuster : graphPolicyAdjusters) {
graphPolicy = adjuster.apply(graphPolicy);
}
if (dryRun) {
processor = GraphUtil.disableProcessor(processor);
}
return new GraphTraversal(helper.getSession(), helper.getEventContext(), aclVoter, systemTypes, graphPathBean, unnullable,
graphPolicy, processor);
}
/**
* Converts the Ice {@code StringLongListMap} to a multimap.
* @param targetClasses legal target object classes
* @param targetObjects the model objects to process
* @return a multimap of the legal model objects to process
* @throws ome.conditions.InternalException if any of the target object classes are illegal
*/
public SetMultimap<String, Long> getTargetMultimap(Set<Class<? extends IObject>> targetClasses,
Map<String, java.util.List<Long>> targetObjects) {
/* if targetObjects were an IObjectList then this would need IceMapper.reverse */
final SetMultimap<String, Long> targetMultimap = HashMultimap.create();
for (final Map.Entry<String, List<Long>> oneClassToTarget : targetObjects.entrySet()) {
/* determine actual class from given target object class name */
String targetObjectClassName = oneClassToTarget.getKey();
final int lastDot = targetObjectClassName.lastIndexOf('.');
if (lastDot > 0) {
targetObjectClassName = targetObjectClassName.substring(lastDot + 1);
}
final Class<? extends IObject> targetObjectClass = graphPathBean.getClassForSimpleName(targetObjectClassName);
/* check that it is legal to target the given class */
final Iterator<Class<? extends IObject>> legalTargetsIterator = targetClasses.iterator();
do {
if (!legalTargetsIterator.hasNext()) {
final Exception e = new IllegalArgumentException("cannot target " + targetObjectClassName);
throw helper.cancel(new ERR(), e, "bad-target");
}
} while (!legalTargetsIterator.next().isAssignableFrom(targetObjectClass));
/* note IDs to target for the class */
final Collection<Long> ids = oneClassToTarget.getValue();
targetMultimap.putAll(targetObjectClass.getName(), ids);
}
return targetMultimap;
}
}