/* * Copyright 2009-2011 Collaborative Research Centre SFB 632 * * 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. */ package annis.model; import java.io.Serializable; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; import org.apache.commons.lang.Validate; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import annis.sqlgen.model.Join; import annis.sqlgen.model.RankTableJoin; public class AnnisNode implements Serializable { // this class is send to the front end private static final long serialVersionUID = 6376277416278198777L; // node object in database private long id; private long corpus; // FIXME: Corpus object with annotations or move to // graph? private long textId; private long left; private long right; private String spannedText; private Long tokenIndex; private long leftToken; private long rightToken; private Set<Annotation> nodeAnnotations; // annotation graph private AnnotationGraph graph; // node position in annotation graph private Set<Edge> incomingEdges; private Set<Edge> outgoingEdges; private String name; private String namespace; // node constraints private boolean partOfEdge; private boolean root; private boolean token; private TextMatching spanTextMatching; private List<Join> joins; private String variable; private Set<Annotation> edgeAnnotations; private Range arity; private Range tokenArity; // for sql generation private String marker; private Long matchedNodeInQuery; public enum TextMatching { EXACT_EQUAL("=", "\""), REGEXP_EQUAL("~", "/"), EXACT_NOT_EQUAL("<>", "\""), REGEXP_NOT_EQUAL("!~", "/"); private String sqlOperator; private String annisQuote; private TextMatching(String sqlOperator, String annisQuote) { this.sqlOperator = sqlOperator; this.annisQuote = annisQuote; } public String toString() { return sqlOperator; } public String sqlOperator() { return sqlOperator; } public String quote() { return annisQuote; } }; public static class Range { private int min; private int max; public Range(int _min, int _max) { min = _min; max = _max; } public int getMin() { return min; } public int getMax() { return max; } @Override public int hashCode() { return new HashCodeBuilder().append(min).append(max).toHashCode(); } @Override public boolean equals(Object obj) { if (obj instanceof Range) { Range other = (Range) obj; return new EqualsBuilder().append(min, other.min).append(max, other.max).isEquals(); } return false; } }; public AnnisNode() { nodeAnnotations = new TreeSet<Annotation>(); edgeAnnotations = new TreeSet<Annotation>(); incomingEdges = new HashSet<Edge>(); outgoingEdges = new HashSet<Edge>(); joins = new ArrayList<Join>(); } public AnnisNode(long id) { this(); this.id = id; } public AnnisNode(long id, long corpusRef, long textRef, long left, long right, String namespace, String name, long tokenIndex, String span, long leftToken, long rightToken) { this(id); this.corpus = corpusRef; this.textId = textRef; this.left = left; this.right = right; this.leftToken = leftToken; this.rightToken = rightToken; setNamespace(namespace); setName(name); setTokenIndex(tokenIndex); setSpannedText(span, TextMatching.EXACT_EQUAL); } public static String qName(String namespace, String name) { return name == null ? null : (namespace == null ? name : namespace + ":" + name); } public void setSpannedText(String span) { setSpannedText(span, TextMatching.EXACT_EQUAL); } public void setSpannedText(String spannedText, TextMatching textMatching) { if (spannedText != null) { Validate.notNull(textMatching); } this.spannedText = spannedText; this.spanTextMatching = textMatching; } public void clearSpannedText() { this.spannedText = null; this.spanTextMatching = null; } @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append("node "); sb.append(id); if (marker != null) { sb.append("; marked '"); sb.append(marker); sb.append("'"); } if (variable != null) { sb.append("; bound to '"); sb.append(variable); sb.append("'"); } if (name != null) { sb.append("; named '"); sb.append(qName(namespace, name)); sb.append("'"); } if (token) { sb.append("; is a token"); } if (spannedText != null) { sb.append("; spans"); String op = spanTextMatching != null ? spanTextMatching.sqlOperator() : " "; String quote = spanTextMatching != null ? spanTextMatching.quote() : "?"; sb.append(op); sb.append(quote); sb.append(spannedText); sb.append(quote); } if (isRoot()) { sb.append("; root node"); } if (!nodeAnnotations.isEmpty()) { sb.append("; node labels: "); sb.append(nodeAnnotations); } if (!edgeAnnotations.isEmpty()) { sb.append("; edge labes: "); sb.append(edgeAnnotations); } for (Join join : joins) { sb.append("; "); sb.append(join); } return sb.toString(); } public boolean addIncomingEdge(Edge edge) { return incomingEdges.add(edge); } public boolean addOutgoingEdge(Edge edge) { return outgoingEdges.add(edge); } public boolean addEdgeAnnotation(Annotation annotation) { return edgeAnnotations.add(annotation); } public boolean addNodeAnnotation(Annotation annotation) { return nodeAnnotations.add(annotation); } public boolean addJoin(Join join) { boolean result = joins.add(join); if (join instanceof RankTableJoin) { this.setPartOfEdge(true); AnnisNode target = join.getTarget(); target.setPartOfEdge(true); } return result; } public String getQualifiedName() { return qName(namespace, name); } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final AnnisNode other = (AnnisNode) obj; if (this.id != other.id) { return false; } if (this.corpus != other.corpus) { return false; } if (this.textId != other.textId) { return false; } if (this.left != other.left) { return false; } if (this.right != other.right) { return false; } if ((this.spannedText == null) ? (other.spannedText != null) : !this.spannedText.equals(other.spannedText)) { return false; } if (this.leftToken != other.leftToken) { return false; } if (this.nodeAnnotations != other.nodeAnnotations && (this.nodeAnnotations == null || !this.nodeAnnotations.equals(other.nodeAnnotations))) { return false; } if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { return false; } if ((this.namespace == null) ? (other.namespace != null) : !this.namespace.equals(other.namespace)) { return false; } if (this.partOfEdge != other.partOfEdge) { return false; } if (this.root != other.root) { return false; } if (this.token != other.token) { return false; } if (this.spanTextMatching != other.spanTextMatching) { return false; } if (this.joins != other.joins && (this.joins == null || !this.joins.equals(other.joins))) { return false; } if ((this.variable == null) ? (other.variable != null) : !this.variable.equals(other.variable)) { return false; } if (this.edgeAnnotations != other.edgeAnnotations && (this.edgeAnnotations == null || !this.edgeAnnotations.equals(other.edgeAnnotations))) { return false; } if ((this.marker == null) ? (other.marker != null) : !this.marker.equals(other.marker)) { return false; } if ((this.arity == null) ? (other.arity != null) : !this.arity.equals(other.arity)) { return false; } if ((this.tokenArity == null) ? (other.tokenArity != null) : !this.tokenArity.equals(other.tokenArity)) { return false; } return true; } // @Override // public boolean equals(Object obj) { // if (obj == null || !(obj instanceof AnnisNode)) // return false; // // AnnisNode other = (AnnisNode) obj; // // return new EqualsBuilder() // .append(this.id, other.id) // .append(this.corpus, other.corpus) // .append(this.textId, other.textId) // .append(this.left, other.left) // .append(this.right, other.right) // .append(this.spannedText, other.spannedText) // .append(this.leftToken, other.leftToken) // .append(this.nodeAnnotations, other.nodeAnnotations) // .append(this.name, other.name) // .append(this.namespace, other.namespace) // .append(this.partOfEdge, other.partOfEdge) // .append(this.root, other.root) // .append(this.token, other.token) // .append(this.spanTextMatching, other.spanTextMatching) // .append(this.joins, other.joins) // .append(this.variable, other.variable) // .append(this.edgeAnnotations, other.edgeAnnotations) // .append(this.marker, other.marker) // .isEquals(); // } // @Override public int hashCode() { return (int) id; } // /// Getter / Setter public Set<Annotation> getEdgeAnnotations() { return edgeAnnotations; } public void setEdgeAnnotations(Set<Annotation> edgeAnnotations) { this.edgeAnnotations = edgeAnnotations; } public boolean isRoot() { return root; } public void setRoot(boolean root) { this.root = root; } public String getMarker() { return marker; } public void setMarker(String marker) { this.marker = marker; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getNamespace() { return namespace; } public void setNamespace(String namespace) { this.namespace = namespace; } public String getSpannedText() { return spannedText; } public TextMatching getSpanTextMatching() { return spanTextMatching; } public Set<Annotation> getNodeAnnotations() { return nodeAnnotations; } public void setNodeAnnotations(Set<Annotation> nodeAnnotations) { this.nodeAnnotations = nodeAnnotations; } public String getVariable() { return variable; } public void setVariable(String variable) { this.variable = variable; } public long getId() { return id; } public List<Join> getJoins() { return joins; } public boolean isToken() { return token; } public void setToken(boolean token) { this.token = token; } public boolean isPartOfEdge() { return partOfEdge; } public void setPartOfEdge(boolean partOfEdge) { this.partOfEdge = partOfEdge; } public long getCorpus() { return corpus; } public void setCorpus(long corpus) { this.corpus = corpus; } public long getTextId() { return textId; } public void setTextId(long textIndex) { this.textId = textIndex; } public long getLeft() { return left; } public void setLeft(long left) { this.left = left; } public long getRight() { return right; } public void setRight(long right) { this.right = right; } public Long getTokenIndex() { return tokenIndex; } public void setTokenIndex(Long tokenIndex) { this.tokenIndex = tokenIndex; // FIXME: vermengung von node und constraint semantik setToken(tokenIndex != null); } public long getLeftToken() { return leftToken; } public void setLeftToken(long leftToken) { this.leftToken = leftToken; } public long getRightToken() { return rightToken; } public void setRightToken(long rightToken) { this.rightToken = rightToken; } public Set<Edge> getIncomingEdges() { return incomingEdges; } public void setIncomingEdges(Set<Edge> incomingEdges) { this.incomingEdges = incomingEdges; } public Set<Edge> getOutgoingEdges() { return outgoingEdges; } public void setOutgoingEdges(Set<Edge> outgoingEdges) { this.outgoingEdges = outgoingEdges; } public AnnotationGraph getGraph() { return graph; } public void setGraph(AnnotationGraph graph) { this.graph = graph; } public Range getArity() { return arity; } public void setArity(Range arity) { this.arity = arity; } public Range getTokenArity() { return tokenArity; } public void setTokenArity(Range tokenArity) { this.tokenArity = tokenArity; } public Long getMatchedNodeInQuery() { return matchedNodeInQuery; } public void setMatchedNodeInQuery(Long matchedNodeInQuery) { this.matchedNodeInQuery = matchedNodeInQuery; } }