omero.cmd.graphs.ChildOptionI.java Source code

Java tutorial

Introduction

Here is the source code for omero.cmd.graphs.ChildOptionI.java

Source

/*
 * 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 omero.cmd.graphs;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableSet;

import ome.model.IObject;
import ome.services.graphs.GraphPathBean;

/**
 * Child options adjust how child objects are treated according to their type and, if annotations, namespace,
 * overriding the default graph traversal policy for orphans.
 * @author m.t.b.carroll@dundee.ac.uk
 * @since 5.1.0
 */
public class ChildOptionI extends ChildOption {

    private final GraphPathBean graphPathBean;
    private final ImmutableSet<String> defaultExcludeNs;

    private Function<Class<? extends IObject>, Boolean> isIncludeType = null;
    private Predicate<String> isTargetNamespace = null;

    /**
     * Construct a new child option instance.
     * @param graphPathBean the graph path bean
     * @param defaultExcludeNs annotation namespaces to exclude by default
     */
    public ChildOptionI(GraphPathBean graphPathBean, ImmutableSet<String> defaultExcludeNs) {
        this.graphPathBean = graphPathBean;
        this.defaultExcludeNs = defaultExcludeNs;
    }

    /**
     * Construct a new child option instance identical to that given. If the original was initialized, this one is too.
     * @param original a child option instance
     */
    public ChildOptionI(ChildOptionI original) {
        graphPathBean = original.graphPathBean;
        defaultExcludeNs = original.defaultExcludeNs;

        includeType = original.includeType == null ? null : new ArrayList<String>(original.includeType);
        excludeType = original.excludeType == null ? null : new ArrayList<String>(original.excludeType);
        includeNs = original.includeNs == null ? null : new ArrayList<String>(original.includeNs);
        excludeNs = original.excludeNs == null ? null : new ArrayList<String>(original.excludeNs);
        isIncludeType = original.isIncludeType;
        isTargetNamespace = original.isTargetNamespace;
    }

    /**
     * Initialize this child option instance.
     * An option takes effect according to the {@link ChildOption} field values set when this method was last called.
     */
    public void init() {
        /* convert the class names to actual classes */

        final Function<String, Class<? extends IObject>> getClassFromName = new Function<String, Class<? extends IObject>>() {
            @Override
            public Class<? extends IObject> apply(String className) {
                final int lastDot = className.lastIndexOf('.');
                if (lastDot > 0) {
                    className = className.substring(lastDot + 1);
                }
                return graphPathBean.getClassForSimpleName(className);
            }
        };

        /* construct the function corresponding to the type-based inclusion requirements */

        final ImmutableSet<Class<? extends IObject>> typeInclusions;
        final ImmutableSet<Class<? extends IObject>> typeExclusions;

        if (CollectionUtils.isEmpty(includeType)) {
            typeInclusions = ImmutableSet.of();
        } else {
            typeInclusions = ImmutableSet.copyOf(Collections2.transform(includeType, getClassFromName));
        }
        if (CollectionUtils.isEmpty(excludeType)) {
            typeExclusions = ImmutableSet.of();
        } else {
            typeExclusions = ImmutableSet.copyOf(Collections2.transform(excludeType, getClassFromName));
        }

        if (typeInclusions.isEmpty() && typeExclusions.isEmpty()) {
            throw new IllegalArgumentException("child option must include or exclude some type");
        }

        isIncludeType = new Function<Class<? extends IObject>, Boolean>() {
            @Override
            public Boolean apply(Class<? extends IObject> objectClass) {
                for (final Class<? extends IObject> typeInclusion : typeInclusions) {
                    if (typeInclusion.isAssignableFrom(objectClass)) {
                        return Boolean.TRUE;
                    }
                }
                for (final Class<? extends IObject> typeExclusion : typeExclusions) {
                    if (typeExclusion.isAssignableFrom(objectClass)) {
                        return Boolean.FALSE;
                    }
                }
                return null;
            }
        };

        /* if no annotation namespaces are set, then apply the defaults */

        if (CollectionUtils.isEmpty(includeNs) && CollectionUtils.isEmpty(excludeNs)) {
            excludeNs = new ArrayList<String>(defaultExcludeNs);
        }

        /* construct the predicate corresponding to the namespace restriction */

        if (CollectionUtils.isEmpty(includeNs)) {
            if (CollectionUtils.isEmpty(excludeNs)) {
                /* there is no adjustment to make, not even for any default namespaces */
                isTargetNamespace = Predicates.alwaysTrue();
            } else {
                final ImmutableSet<String> nsExclusions = ImmutableSet.copyOf(excludeNs);
                isTargetNamespace = new Predicate<String>() {
                    @Override
                    public boolean apply(String namespace) {
                        return !nsExclusions.contains(namespace);
                    }
                };
            }
        } else {
            if (CollectionUtils.isEmpty(excludeNs)) {
                final ImmutableSet<String> nsInclusions = ImmutableSet.copyOf(includeNs);
                isTargetNamespace = new Predicate<String>() {
                    @Override
                    public boolean apply(String namespace) {
                        return nsInclusions.contains(namespace);
                    }
                };
            } else {
                throw new IllegalArgumentException("child option may not both include and exclude namespace");
            }
        }
    }

    /**
     * Test if this child option adjusts graph traversal policy for the given child object class.
     * Requires {@link #init()} to have been called previously.
     * @param objectClass a child object class
     * @return {@code true} if such children should be included in the operation,
     * {@code false} if such children should not be included in the operation, or
     * {@code null} if this child option does not affect the treatment of such children
     */
    public Boolean isIncludeType(Class<? extends IObject> objectClass) {
        return isIncludeType.apply(objectClass);
    }

    /**
     * Test if this child option adjusts graph traversal policy for child objects that are annotations in the given namespace.
     * Requires {@link #init()} to have been called previously.
     * @param namespace an annotation namespace
     * @return if child objects that are annotations in this namespace are affected by this child option
     */
    public boolean isTargetNamespace(String namespace) {
        return isTargetNamespace.apply(namespace);
    }

    /**
     * Cast {@code ChildOption[]} to {@code ChildOptionI[]}.
     * @param childOptions an array of {@code ChildOption} which may all be casted to {@code ChildOptionI}, may be {@code null}
     * @return an array of {@code ChildOptionI}, may be {@code null}
     */
    public static List<ChildOptionI> castChildOptions(Collection<ChildOption> childOptions) {
        if (childOptions == null) {
            return null;
        } else {
            final List<ChildOptionI> childOptionsI = new ArrayList<ChildOptionI>(childOptions.size());
            for (final ChildOption childOption : childOptions) {
                childOptionsI.add((ChildOptionI) childOption);
            }

            return childOptionsI;
        }
    }
}