/* * 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 an attribute in a schema. * * @author Soheil Hassas Yeganeh <soheil@cs.toronto.edu> */ public class Attribute { // Eric: Moved member variables to top to be consistent // with other xcurator classes String name; String path; Schema parent; boolean key; Set<String> typeURIs = new HashSet<String>(); Map<SchemaInstance, Set<AttributeInstance>> instanceMap; Map<String, Set<AttributeInstance>> reverseInstanceMap; // Eric: I think when an attribute is created, its key value should // automatically be false, until later specified otherwise (most // probably by the key identification mapping step). This means that // the constructor does not need to take key as a parameter. public Attribute(Schema parent, String name, String path, boolean key) { // Eric: Do we need super() here? Attribute class does not extend // any class. super(); this.name = name; this.path = path; this.parent = parent; this.key = key; instanceMap = new HashMap<SchemaInstance, Set<AttributeInstance>>(); reverseInstanceMap = new HashMap<String, Set<AttributeInstance>>(); } public void addInstance(AttributeInstance instance) { addInstance(instance, this.instanceMap, this.reverseInstanceMap); } // Added maps as parameters for the function to be re-used. public void addInstance(AttributeInstance instance, Map<SchemaInstance, Set<AttributeInstance>> instanceMap, Map<String, Set<AttributeInstance>> reverseInstanceMap) { Set<AttributeInstance> attributes = instanceMap.get(instance.schemaInstance); if (attributes == null) { attributes = new HashSet<AttributeInstance>(); instanceMap.put(instance.schemaInstance, attributes); } attributes.add(instance); attributes = reverseInstanceMap.get(instance.content); if (attributes == null) { attributes = new HashSet<AttributeInstance>(); reverseInstanceMap.put(instance.content, attributes); } attributes.add(instance); } public boolean isOneToOne() { for (Map.Entry<SchemaInstance, Set<AttributeInstance>> entry : instanceMap.entrySet()) { if (entry.getValue().size() > 1) { return false; } } for (Map.Entry<String, Set<AttributeInstance>> entry : reverseInstanceMap.entrySet()) { if (entry.getValue().size() > 1) { return false; } } return true; } public boolean hasUniqueAttributeInstance() { for (Map.Entry<SchemaInstance, Set<AttributeInstance>> entry : instanceMap.entrySet()) { if (entry.getValue().size() > 1) { return false; } } return true; } // Used during schema flattening, where the original parent schema // is replaced by the new parent schema, with whom the original parent // schema has a one-to-one relation. public void updateAttributeInstances(Relation rel) { // Create new maps to replace the current ones later Map<SchemaInstance, Set<AttributeInstance>> newInstanceMap = new HashMap<SchemaInstance, Set<AttributeInstance>>(); Map<String, Set<AttributeInstance>> newReverseInstanceMap = new HashMap<String, Set<AttributeInstance>>(); // Iterate through all schema instances for (SchemaInstance parentSI : this.instanceMap.keySet()) { // Find the parent schema instance to the current // schema instance. // Due to a schema can have multiple parents, we know that for // the current schema instance, if it exists in the current // relation, there must be EXACTLY one parent schema due to // one-to-one relation Set<SchemaInstance> grandSISet = rel.getReverseInstanceMap().get(parentSI); SchemaInstance grandSI = null; // Take into account that the current schema instance may not exist // in the current relation, but some other relation because this schema // can have multiple parents if (grandSISet != null) { if (grandSISet.size() != 1) { System.out.println("MORE THAN ONE GRAND PARENT SCHEMA INSTANCE. SOMETHING IS WRONG!"); } else { grandSI = grandSISet.iterator().next(); } // Iterate through all attribute instances for (AttributeInstance ai : this.instanceMap.get(parentSI)) { // Update its schema instance ai.setSchemaInstance(grandSI); // Add it to the new maps addInstance(ai, newInstanceMap, newReverseInstanceMap); } } } // Replace current maps with the new ones this.instanceMap = newInstanceMap; this.reverseInstanceMap = newReverseInstanceMap; } public Map<SchemaInstance, Set<AttributeInstance>> getInstanceMap() { return this.instanceMap; } public Map<String, Set<AttributeInstance>> getReverseInstanceMap() { return this.reverseInstanceMap; } public void setParent(Schema parent) { this.parent = parent; } 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 boolean isKey() { return key; } public void setKey(boolean key) { this.key = key; } public Schema getParent() { return parent; } @Override public String toString() { return "A@ " + name; } @Override public boolean equals(Object obj) { if (obj instanceof Attribute) { Attribute attr = (Attribute) obj; return attr.name.equals(this.name) && attr.parent.equals(this.parent) && attr.path.equals(this.path); } return super.equals(obj); } @Override public int hashCode() { return name.hashCode(); } public Set<String> getTypeURIs() { return typeURIs; } public void setTypeURIs(Set<String> typeURIs) { this.typeURIs = typeURIs; } }