/**
* Copyright (C) 2012-2013 Selventa, Inc.
*
* This file is part of the OpenBEL Framework.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The OpenBEL Framework 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the OpenBEL Framework. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms under LGPL v3:
*
* This license does not authorize you and you are prohibited from using the
* name, trademarks, service marks, logos or similar indicia of Selventa, Inc.,
* or, in the discretion of other licensors or authors of the program, the
* name, trademarks, service marks, logos or similar indicia of such authors or
* licensors, in any marketing or advertising materials relating to your
* distribution of the program or any covered product. This restriction does
* not waive or limit your obligation to keep intact all copyright notices set
* forth in the program as delivered to you.
*
* If you distribute the program in whole or in part, or any modified version
* of the program, and you assume contractual liability to the recipient with
* respect to the program or modified version, then you will indemnify the
* authors and licensors of the program for any liabilities that these
* contractual assumptions directly impose on those licensors and authors.
*/
package org.openbel.framework.api;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.regex.Pattern;
import org.openbel.framework.api.internal.KAMCatalogDao.KamInfo;
import org.openbel.framework.common.InvalidArgument;
import org.openbel.framework.common.enums.FunctionEnum;
import org.openbel.framework.common.enums.RelationshipType;
/**
* A {@link KamDialect} applies a {@link Dialect} to a {@link KamNode}s as
* needed.<br>
* When {@link KamNode}s are returned, the concrete object will be a wrapper
* around the original {@link KamNode} that applies the {@link Dialect} to
* generate a different label. Implementation considerations:
* <ul>
* <li>New wrapper objects are instantiated for every {@link KamNode} and
* {@link KamEdge} returned. This prevents additional memory requirements if a
* reference to the {@link KamDialect} is maintained by the user. There is
* additional young generation memory needs that may be tweaked with changes to
* gc if needed.</li>
* <li>The {@link Dialect} is queried for every call to
* {@link KamNode#getLabel()} is made. This allows {@link Dialect}
* implementations to provide caching if desired without introducing additional
* memory overhead.</li>
* <li>This implementation assumes {@link NodeFilter}s and {@link EdgeFilter}s
* do not perform any actions on the node labels. If/when this is changed, this
* implementation must be modified to account for filters that now need access
* to the label generated by the {@link Dialect}.</li>
* </ul>
*
* @author Steve Ungerer
*/
public final class KamDialect implements Kam {
private final Kam kam;
private final Dialect dialect;
/**
* Construct a new {@link KamDialect}
* @param kam The original {@link Kam}. Must not be <code>null</code>.
* @param dialect The {@link Dialect} to apply. Must not be <code>null</code>.
* @throws InvalidArgument Thrown if the provided {@link Kam} or {@link Dialect} is <code>null</code>.
*/
public KamDialect(Kam kam, Dialect dialect) throws InvalidArgument {
if (kam == null) {
throw new InvalidArgument("Kam must not be null");
}
if (dialect == null) {
throw new InvalidArgument("Dialect must not be null");
}
this.kam = kam;
this.dialect = dialect;
}
/**
* {@inheritDoc}
*/
@Override
public Integer getId() {
return kam.getId();
}
/**
* {@inheritDoc}
*/
@Override
public KamInfo getKamInfo() {
return kam.getKamInfo();
}
/**
* {@inheritDoc}
*/
@Override
public NodeFilter createNodeFilter() {
return kam.createNodeFilter();
}
/**
* {@inheritDoc}
*/
@Override
public EdgeFilter createEdgeFilter() {
return kam.createEdgeFilter();
}
/**
* {@inheritDoc}
*/
@Override
public KamNode findNode(String label) {
return findNode(label, null);
}
/**
* {@inheritDoc}
*/
@Override
public KamNode findNode(String label, NodeFilter filter) {
for (KamNode kamNode : getNodes()) {
boolean passedFilter = (filter == null || filter.accept(kamNode));
if (passedFilter) {
String nodeLabel = kamNode.getLabel();
if (nodeLabel.equalsIgnoreCase(label)) {
return kamNode;
}
}
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
public KamNode findNode(Integer kamNodeId) {
return findNode(kamNodeId, null);
}
/**
* {@inheritDoc}
*/
@Override
public KamNode findNode(Integer kamNodeId, NodeFilter filter) {
return wrapNode(kam.findNode(kamNodeId, filter));
}
/**
* {@inheritDoc}
*/
@Override
public Set<KamNode> findNode(Pattern labelPattern) {
return findNode(labelPattern, null);
}
/**
* {@inheritDoc}
*/
@Override
public Set<KamNode> findNode(Pattern labelPattern, NodeFilter filter) {
Set<KamNode> results = new LinkedHashSet<KamNode>();
for (KamNode node : getNodes()) {
boolean passedFilter = (filter == null || filter.accept(node));
if (passedFilter && labelPattern.matcher(node.getLabel()).matches()) {
results.add(node);
}
}
return results;
}
/**
* {@inheritDoc}
*/
@Override
public Set<KamNode> getAdjacentNodes(KamNode kamNode) {
return wrapNodes(kam.getAdjacentNodes(kamNode));
}
/**
* {@inheritDoc}
*/
@Override
public Set<KamNode> getAdjacentNodes(KamNode kamNode,
EdgeDirectionType edgeDirection) {
return wrapNodes(kam.getAdjacentNodes(kamNode, edgeDirection));
}
/**
* {@inheritDoc}
*/
@Override
public Set<KamNode> getAdjacentNodes(KamNode kamNode,
EdgeDirectionType edgeDirection, EdgeFilter edgeFilter) {
return wrapNodes(kam.getAdjacentNodes(kamNode, edgeDirection,
edgeFilter));
}
/**
* {@inheritDoc}
*/
@Override
public Set<KamNode> getAdjacentNodes(KamNode kamNode,
EdgeDirectionType edgeDirection, NodeFilter filter) {
return wrapNodes(kam.getAdjacentNodes(kamNode, edgeDirection, filter));
}
/**
* {@inheritDoc}
*/
@Override
public Set<KamNode> getAdjacentNodes(KamNode kamNode,
EdgeFilter edgeFilter, NodeFilter nodeFilter) {
return wrapNodes(kam.getAdjacentNodes(kamNode, edgeFilter, nodeFilter));
}
/**
* {@inheritDoc}
*/
@Override
public Set<KamNode> getAdjacentNodes(KamNode kamNode,
EdgeDirectionType edgeDirection, EdgeFilter edgeFilter,
NodeFilter nodeFilter) {
return wrapNodes(kam.getAdjacentNodes(kamNode, edgeDirection,
edgeFilter, nodeFilter));
}
/**
* {@inheritDoc}
*/
@Override
public Set<KamEdge> getAdjacentEdges(KamNode kamNode) {
return wrapEdges(kam.getAdjacentEdges(kamNode));
}
/**
* {@inheritDoc}
*/
@Override
public Set<KamEdge> getAdjacentEdges(KamNode kamNode, EdgeFilter filter) {
return wrapEdges(kam.getAdjacentEdges(kamNode, filter));
}
/**
* {@inheritDoc}
*/
@Override
public Set<KamEdge> getAdjacentEdges(KamNode kamNode,
EdgeDirectionType edgeDirection) {
return wrapEdges(kam.getAdjacentEdges(kamNode, edgeDirection));
}
/**
* {@inheritDoc}
*/
@Override
public Set<KamEdge> getAdjacentEdges(KamNode kamNode,
EdgeDirectionType edgeDirection, EdgeFilter filter) {
return wrapEdges(kam.getAdjacentEdges(kamNode, edgeDirection, filter));
}
/**
* {@inheritDoc}
*/
@Override
public Set<KamEdge> getEdges(KamNode sourceNode, KamNode targetNode) {
return wrapEdges(kam.getEdges(sourceNode, targetNode));
}
/**
* {@inheritDoc}
*/
@Override
public Set<KamEdge> getEdges(KamNode sourceNode, KamNode targetNode,
EdgeFilter filter) {
return wrapEdges(kam.getEdges(sourceNode, targetNode, filter));
}
/**
* {@inheritDoc}
*/
@Override
public KamEdge findEdge(Integer kamEdgeId) {
return wrapEdge(kam.findEdge(kamEdgeId));
}
/**
* {@inheritDoc}
*/
@Override
public KamEdge findEdge(KamNode sourceNode,
RelationshipType relationshipType, KamNode targetNode)
throws InvalidArgument {
return wrapEdge(kam.findEdge(sourceNode, relationshipType, targetNode));
}
/**
* {@inheritDoc}
*/
@Override
public boolean contains(KamNode kamNode) {
return kam.contains(kamNode);
}
/**
* {@inheritDoc}
*/
@Override
public boolean contains(KamEdge kamEdge) {
return kam.contains(kamEdge);
}
/**
* {@inheritDoc}
*/
@Override
public Collection<KamNode> getNodes() {
return wrapNodes(kam.getNodes());
}
/**
* {@inheritDoc}
*/
@Override
public Collection<KamNode> getNodes(NodeFilter filter) {
return wrapNodes(kam.getNodes(filter));
}
/**
* {@inheritDoc}
*/
@Override
public Collection<KamEdge> getEdges() {
return wrapEdges(kam.getEdges());
}
/**
* {@inheritDoc}
*/
@Override
public Collection<KamEdge> getEdges(EdgeFilter filter) {
return wrapEdges(kam.getEdges(filter));
}
/**
* {@inheritDoc}
*/
@Override
public void union(Collection<KamEdge> kamEdges) throws InvalidArgument {
// TODO does this need to be implemented?
throw new UnsupportedOperationException(
"union() is not supported by DialectKam");
}
/**
* {@inheritDoc}
*/
@Override
public KamEdge createEdge(Integer kamEdgeId, KamNode sourceNode,
RelationshipType relationshipType, KamNode targetNode)
throws InvalidArgument {
return kam.createEdge(kamEdgeId, sourceNode, relationshipType,
targetNode);
}
/**
* {@inheritDoc}
*/
@Override
public void removeEdge(KamEdge kamEdge) {
kam.removeEdge(kamEdge);
}
/**
* {@inheritDoc}
*/
@Override
public KamEdge replaceEdge(KamEdge kamEdge, FunctionEnum sourceFunction,
String sourceLabel, RelationshipType relationship,
FunctionEnum targetFunction, String targetLabel) {
return kam.replaceEdge(kamEdge, sourceFunction, sourceLabel,
relationship, targetFunction, targetLabel);
}
/**
* {@inheritDoc}
*/
@Override
public KamEdge replaceEdge(KamEdge kamEdge, KamEdge replacement) {
return kam.replaceEdge(kamEdge, replacement);
}
/**
* {@inheritDoc}
*/
@Override
public KamNode createNode(Integer id, FunctionEnum functionType,
String label) throws InvalidArgument {
return kam.createNode(id, functionType, label);
}
/**
* {@inheritDoc}
*/
@Override
public void removeNode(KamNode kamNode) {
kam.removeNode(kamNode);
}
/**
* {@inheritDoc}
*/
@Override
public KamNode replaceNode(KamNode kamNode, FunctionEnum function,
String label) {
return kam.replaceNode(kamNode, function, label);
}
/**
* {@inheritDoc}
*/
@Override
public KamNode replaceNode(KamNode kamNode, KamNode replacement) {
return kam.replaceNode(kamNode, replacement);
}
/**
* {@inheritDoc}
*/
@Override
public void collapseNode(KamNode from, KamNode to) {
kam.collapseNode(from, to);
}
private Set<KamNode> wrapNodes(Collection<KamNode> nodes) {
Set<KamNode> ret = new LinkedHashSet<KamNode>(nodes.size());
for (KamNode n : nodes) {
KamDialectNode d = wrapNode(n);
if (d != null) {
ret.add(d);
}
}
return ret;
}
private Set<KamEdge> wrapEdges(Collection<KamEdge> edges) {
Set<KamEdge> ret = new LinkedHashSet<KamEdge>(edges.size());
for (KamEdge e : edges) {
KamDialectEdge d = wrapEdge(e);
if (d != null) {
ret.add(d);
}
}
return ret;
}
private KamDialectNode wrapNode(KamNode kamNode) {
return kamNode == null ? null : new KamDialectNode(kamNode);
}
private KamDialectEdge wrapEdge(KamEdge kamEdge) {
return kamEdge == null ? null : new KamDialectEdge(kamEdge);
}
protected final class KamDialectNode implements KamNode {
private final KamNode kamNode;
protected KamDialectNode(KamNode kamNode) {
this.kamNode = kamNode;
}
@Override
public Kam getKam() {
return kamNode.getKam();
}
@Override
public Integer getId() {
return kamNode.getId();
}
@Override
public FunctionEnum getFunctionType() {
return kamNode.getFunctionType();
}
@Override
public String getLabel() {
return dialect.getLabel(kamNode);
}
/**
* Delegate to original {@link KamNode} to ensure a
* {@link KamDialectNode} can be used as a parameter for methods where
* map lookups are performed.
*/
@Override
public int hashCode() {
return kamNode.hashCode();
}
/**
* Delegate to original {@link KamNode} to ensure a
* {@link KamDialectNode} can be used as a parameter for methods where
* map lookups are performed.
*/
@Override
public boolean equals(Object obj) {
return kamNode.equals(obj);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return getLabel();
}
}
protected final class KamDialectEdge implements KamEdge {
private final KamEdge kamEdge;
protected KamDialectEdge(KamEdge kamEdge) {
this.kamEdge = kamEdge;
}
@Override
public Kam getKam() {
return kamEdge.getKam();
}
@Override
public Integer getId() {
return kamEdge.getId();
}
@Override
public KamNode getSourceNode() {
return wrapNode(kamEdge.getSourceNode());
}
@Override
public KamNode getTargetNode() {
return wrapNode(kamEdge.getTargetNode());
}
@Override
public RelationshipType getRelationshipType() {
return kamEdge.getRelationshipType();
}
/**
* Delegate to original {@link KamEdge} to ensure a
* {@link KamDialectEdge} can be used as a parameter for methods where
* map lookups are performed.
*/
@Override
public int hashCode() {
return kamEdge.hashCode();
}
/**
* Delegate to original {@link KamEdge} to ensure a
* {@link KamDialectEdge} can be used as a parameter for methods where
* map lookups are performed.
*/
@Override
public boolean equals(Object obj) {
return kamEdge.equals(obj);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getSourceNode().toString());
sb.append(" ");
sb.append(getRelationshipType().getDisplayValue());
sb.append(" ");
sb.append(getTargetNode().toString());
return sb.toString();
}
}
}