Java tutorial
/* * #%L * Protempa Framework * %% * Copyright (C) 2012 - 2013 Emory University * %% * 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. * #L% */ package org.protempa.dest.table; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.ToStringBuilder; import org.protempa.KnowledgeSource; import org.protempa.KnowledgeSourceCache; import org.protempa.KnowledgeSourceReadException; import org.protempa.PropositionDefinition; import org.protempa.ProtempaUtil; import org.protempa.ReferenceDefinition; import org.protempa.proposition.Proposition; import org.protempa.proposition.UniqueId; /** * Specifies reference traversals from one proposition to other propositions. * * @author Andrew Post */ public final class Reference extends Link { private final String[] referenceNames; /** * Creates an instance that specifies traversals using the specified * references from a proposition to all referred-to propositions. * * @param referenceNames a {@link String[]} of reference names. An empty * * or <code>null</code> array specifies that all references should be * traversed. */ public Reference(String[] referenceNames) { this(referenceNames, null); } /** * Creates an instance that specifies traversals using the specified * references from a proposition only to propositions with the given ids. * * @param referenceNames a {@link String[]} of reference names. An empty * * or <code>null</code> array specifies that all references should be * traversed. * @param propositionIds a {@link String[]} of proposition ids. An empty * * or <code>null</code> array specifies that all propositions on the * right-hand-side of the reference should be used. */ public Reference(String[] referenceNames, String[] propositionIds) { this(referenceNames, propositionIds, null); } /** * Creates an instance that specifies traversals using the specified * references from a proposition only to propositions with the given ids and * that satisfy the specified constraints. * * @param referenceNames a {@link String[]} of reference names. An empty * * or <code>null</code> array specifies that all references should be * traversed. * @param propositionIds a {@link String[]} of proposition ids. An empty * * or <code>null</code> array specifies that all propositions on the * right-hand-side of a reference should be used. * @param constraints a {@link PropertyConstraint[]} of property constraints * on the propositions on the right-hand-side of a reference. An empty or * null array specifies that no constraints should be applied. */ public Reference(String[] referenceNames, String[] propositionIds, PropertyConstraint[] constraints) { this(referenceNames, propositionIds, constraints, null, -1, -1); } /** * Creates an instance that specifies traversals using the specified * references from a proposition only to propositions with the given ids and * that satisfy the specified constraints. It also allows specifying the * first, second, or other proposition on the right-hand-side of the * reference. * * @param referenceNames a {@link String[]} of reference names. An empty * * or <code>null</code> array specifies that all references should be * traversed. * @param propositionIds a {@link String[]} of proposition ids. An empty * * or <code>null</code> array specifies that all propositions on the * right-hand-side of a reference should be used. * @param constraints a {@link PropertyConstraint[]} of property constraints * on the propositions on the right-hand-side of a reference. An empty * or <code>null</code> array specifies that no constraints should be * applied. * @param comparator a comparison function representing the total order to * apply to propositions on the right-hand-side of the reference when using * the <code>index</code> parameter. If <code>null</code> and an * <code>index</code> is specified, the total order is unspecified. * @param index the position of the proposition on the right-hand-side of * the reference to traverse to, using the total order specified by the * <code>comparator</code> argument. An index of <code>-1</code> means that * all propositions on the right-hand-side will be traversed to. */ public Reference(String[] referenceNames, String[] propositionIds, PropertyConstraint[] constraints, Comparator<Proposition> comparator, int index) { this(referenceNames, propositionIds, constraints, comparator, index, index >= 0 ? index + 1 : -1); } /** * Creates an instance that specifies traversals using the specified * references from a proposition only to propositions with the given ids and * that satisfy the specified constraints. It also allows specifying a range * of propositions on the right-hand-side of the reference to be traversed * to (first and second, first through third, etc.). * * @param referenceNames a {@link String[]} of reference names. An empty * * or <code>null</code> array specifies that all references should be * traversed. * @param propositionIds a {@link String[]} of proposition ids. An empty * * or <code>null</code> array specifies that all propositions on the * right-hand-side of a reference should be used. * @param constraints a {@link PropertyConstraint[]} of property constraints * on the propositions on the right-hand-side of a reference. An empty * or <code>null</code> array specifies that no constraints should be * applied. * @param comparator a comparison function representing the total order to * apply to propositions on the right-hand-side of the reference when using * the <code>index</code> parameter. If <code>null</code> and an * <code>index</code> is specified, the total order is unspecified. * @param fromIndex the lower-bound on the positions of the propositions on * the right-hand-side of the reference to traverse to, inclusive, using the * total order specified by the <code>comparator</code> argument. An index * of <code>-1</code> means that all propositions on the right-hand-side * will be traversed to. * @param toIndex the upper-bound on the positions of the propositions on * the right-hand-side of the reference to traverse to, exclusive, using the * total order specified by the <code>comparator</code> argument. An index * of <code>-1</code> means that all propositions on the right-hand-side * will be traversed to. */ public Reference(String[] referenceNames, String[] propositionIds, PropertyConstraint[] constraints, Comparator<Proposition> comparator, int fromIndex, int toIndex) { super(propositionIds, constraints, comparator, fromIndex, toIndex); if (referenceNames != null) { ProtempaUtil.checkArrayForNullElement(referenceNames, "referenceNames"); String[] refNames = referenceNames.clone(); for (int i = 0; i < refNames.length; i++) { refNames[i] = refNames[i].intern(); } this.referenceNames = refNames; } else { this.referenceNames = ArrayUtils.EMPTY_STRING_ARRAY; } } /** * Creates an instance that specifies traversals using the specified * reference from a proposition to all referred-to propositions. * * @param referenceName a reference name {@link String} A value of * <code>null</code> specifies that all references should be traversed. */ public Reference(String referenceName) { this(referenceName, null); } /** * Creates an instance that specifies traversals using the specified * reference from a proposition only to propositions with the given ids. * * @param referenceName a reference name {@link String} A value of * <code>null</code> specifies that all references should be traversed. * @param propositionIds a {@link String[]} of proposition ids. An empty * * or <code>null</code> array specifies that all propositions on the * right-hand-side of the reference should be used. */ public Reference(String referenceName, String[] propositionIds) { this(referenceName, propositionIds, null); } /** * Creates an instance that specifies traversals using the specified * references from a proposition only to propositions with the given ids and * that satisfy the specified property constraints. * * @param referenceName a reference name {@link String} A value of * <code>null</code> specifies that all references should be traversed. * @param propositionIds a {@link String[]} of proposition ids. An empty * * or <code>null</code> array specifies that all propositions on the * right-hand-side of a reference should be used. * @param constraints a {@link PropertyConstraint[]} of property constraints * on the propositions on the right-hand-side of a reference. An empty or * null array specifies that no constraints should be applied. */ public Reference(String referenceName, String[] propositionIds, PropertyConstraint[] constraints) { this(referenceName, propositionIds, constraints, null, -1, -1); } /** * Creates an instance that specifies traversals using the specified * reference from a proposition only to propositions with the given ids and * that satisfy the specified property constraints. It also allows * specifying the first, second, or other proposition on the right-hand-side * of the reference. * * @param referenceName a reference name {@link String} A value of * <code>null</code> specifies that all references should be traversed. * @param propositionIds a {@link String[]} of proposition ids. An empty * * or <code>null</code> array specifies that all propositions on the * right-hand-side of a reference should be used. * @param constraints a {@link PropertyConstraint[]} of property constraints * on the propositions on the right-hand-side of a reference. An empty * or <code>null</code> array specifies that no constraints should be * applied. * @param comparator a comparison function representing the total order to * apply to propositions on the right-hand-side of the reference when using * the <code>index</code> parameter. If <code>null</code> and an * <code>index</code> is specified, the total order is unspecified. * @param index the position of the proposition on the right-hand-side of * the reference to traverse to, using the total order specified by the * <code>comparator</code> argument. An index of <code>-1</code> means that * all propositions on the right-hand-side will be traversed to. */ public Reference(String referenceName, String[] propositionIds, PropertyConstraint[] constraints, Comparator<Proposition> comparator, int index) { this(referenceName, propositionIds, constraints, comparator, index, index >= 0 ? index + 1 : -1); } /** * Creates an instance that specifies traversals using the specified * reference from a proposition only to propositions with the given ids and * that satisfy the specified constraints. It also allows specifying a range * of propositions on the right-hand-side of the reference to be traversed * to (first and second, first through third, etc.). * * @param referenceName a reference name {@link String} A value of * <code>null</code> specifies that all references should be traversed. * @param propositionIds a {@link String[]} of proposition ids. An empty * * or <code>null</code> array specifies that all propositions on the * right-hand-side of a reference should be used. * @param constraints a {@link PropertyConstraint[]} of property constraints * on the propositions on the right-hand-side of a reference. An empty * or <code>null</code> array specifies that no constraints should be * applied. * @param comparator a comparison function representing the total order to * apply to propositions on the right-hand-side of the reference when using * the <code>index</code> parameter. If <code>null</code> and an * <code>index</code> is specified, the total order is unspecified. * @param fromIndex the lower-bound on the positions of the propositions on * the right-hand-side of the reference to traverse to, inclusive, using the * ordering specified by the <code>comparator</code> argument. An index * of <code>-1</code> means that all propositions on the * right-hand-side will be traversed to. * @param toIndex the upper-bound on the positions of the propositions on * the right-hand-side of the reference to traverse to, exclusive, using the * ordering specified by the <code>comparator</code> argument. An index * of <code>-1</code> means that all propositions on the * right-hand-side will be traversed to. */ public Reference(String referenceName, String[] propositionIds, PropertyConstraint[] constraints, Comparator<Proposition> comparator, int fromIndex, int toIndex) { super(propositionIds, constraints, comparator, fromIndex, toIndex); if (referenceName == null) { throw new IllegalArgumentException("referenceName cannot be null"); } this.referenceNames = new String[] { referenceName.intern() }; } /** * Gets the names of the reference(s) to be traversed. * * @return a {@link String[]} of reference names. */ public String[] getReferenceNames() { if (this.referenceNames != null) { return this.referenceNames.clone(); } else { return this.referenceNames; } } @Override String headerFragment() { String references = StringUtils.join(this.referenceNames, ','); return createHeaderFragment(references); } /** * Traverses a reference. * * @param proposition a {@link Proposition} at which to start the traversal. * @param forwardDerivations a {@link Map<Proposition,List<Proposition>>} of * derived propositions. * @param backwardDerivations a {@link Map<Proposition,List<Proposition>>} * of derived propositions. * @param references a {@link Map<Proposition,Proposition>} of unique * identifiers to {@link Proposition}s, used to resolve references. * @param knowledgeSource the {@link KnowledgeSource}. * @param cache a {@link Set<Proposition>} for convenience in checking if * duplicate propositions are traversed to. It is cleared in between calls * to this method. * @return the {@link Collection<Proposition>} at the end of the traversal * step. */ @Override Collection<Proposition> traverse(Proposition proposition, Map<Proposition, List<Proposition>> forwardDerivations, Map<Proposition, List<Proposition>> backwardDerivations, Map<UniqueId, Proposition> references, KnowledgeSourceCache ksCache, Set<Proposition> cache) { List<Proposition> props = new ArrayList<>(); String[] refNames = this.referenceNames.length > 0 ? this.referenceNames : proposition.getReferenceNames(); for (String referenceName : refNames) { List<UniqueId> uids = proposition.getReferences(referenceName); for (UniqueId uid : uids) { Proposition prop = references.get(uid); if (prop != null && cache.add(prop) && isMatch(prop)) { props.add(prop); } } } return createResults(props); } @Override public String[] getInferredPropositionIds(KnowledgeSource knowledgeSource, String[] inPropIds) throws KnowledgeSourceReadException { String[] explicitPropIds = getPropositionIds(); if (explicitPropIds.length > 0) { return explicitPropIds.clone(); } else { Set<String> result = new HashSet<>(); for (String propId : inPropIds) { PropositionDefinition propDef = knowledgeSource.readPropositionDefinition(propId); if (propDef == null) { throw new IllegalArgumentException("Invalid propId: " + propId); } for (String refName : this.referenceNames) { ReferenceDefinition refDef = propDef.referenceDefinition(refName); if (refDef != null) { org.arp.javautil.arrays.Arrays.addAll(result, refDef.getPropositionIds()); } } } return result.toArray(new String[result.size()]); } } @Override public String toString() { return ToStringBuilder.reflectionToString(this); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + Arrays.hashCode(referenceNames); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } Reference other = (Reference) obj; if (!Arrays.equals(referenceNames, other.referenceNames)) { return false; } return true; } }