/*
* Copyright (c) 2013, University of Toronto.
*
* 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 edu.toronto.cs.xcurator.model;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Represents a relation between two schemas.
*
* @author Soheil Hassas Yeganeh <soheil@cs.toronto.edu>
*/
public class Relation {
String name;
String path;
Schema child;
Schema parent;
// Eric: What purpose does lookupkeys serve?
Set<Attribute> lookupKeys;
Map<SchemaInstance, Set<SchemaInstance>> instanceMap;
Map<SchemaInstance, Set<SchemaInstance>> reverseInstanceMap;
public Relation(Schema parent, String name, String path, Schema child,
Set<Attribute> lookupKeys) {
// Eric: Do we need super() here? Relation class does not extend
// any class.
super();
this.name = name;
this.path = path;
this.lookupKeys = lookupKeys;
instanceMap = new HashMap<SchemaInstance, Set<SchemaInstance>>();
reverseInstanceMap = new HashMap<SchemaInstance, Set<SchemaInstance>>();
// Also added here for the hashing to work
this.parent = parent;
this.child = child;
this.setParent(parent);
this.setChild(child);
}
public Map<SchemaInstance, Set<SchemaInstance>> getInstanceMap() {
return this.instanceMap;
}
public Map<SchemaInstance, Set<SchemaInstance>> getReverseInstanceMap() {
return this.reverseInstanceMap;
}
public void setParent(Schema parent) {
// TODO(soheil): We might need to remove it here.
this.parent = parent;
parent.addRelation(this);
}
public void setChild(Schema child) {
this.child = child;
child.addReverseRelation(this);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public Schema getChild() {
return child;
}
public Schema getParent() {
return parent;
}
public Set<Attribute> getLookupKeys() {
return lookupKeys;
}
@Override
public String toString() {
return "R@ " + name;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Relation) {
Relation relation = (Relation) obj;
// Eric: The following is wrong. Relations
// are EQUAL when they share the same parent
// and the child.
// return relation.name.equals(this.name) &&
// relation.child.equals(this.child);
return relation.parent.equals(this.parent)
&& relation.child.equals(this.child)
&& relation.name.equals(this.name);
}
return false;
}
@Override
public int hashCode() {
// Eric: The following is wrong. Hash should
// be based on both the parent and the child.
// return name.hashCode();
if (this.parent == null) {
System.out.println(this.name);
}
if (this.child == null) {
System.out.println(this.name);
}
return this.parent.hashCode() ^ this.child.hashCode() << 7;
}
public void addInstance(RelationInstance instance) {
Set<SchemaInstance> relations = instanceMap.get(instance.from);
if (relations == null) {
relations = new HashSet<SchemaInstance>();
instanceMap.put(instance.from, relations);
}
relations.add(instance.to);
relations = reverseInstanceMap.get(instance.to);
if (relations == null) {
relations = new HashSet<SchemaInstance>();
reverseInstanceMap.put(instance.to, relations);
}
relations.add(instance.from);
}
public boolean isOneToOne() {
for (Map.Entry<SchemaInstance, Set<SchemaInstance>> entry
: instanceMap.entrySet()) {
if (entry.getValue().size() > 1) {
return false;
}
}
for (Map.Entry<SchemaInstance, Set<SchemaInstance>> entry
: reverseInstanceMap.entrySet()) {
if (entry.getValue().size() > 1) {
return false;
}
}
return true;
}
}