/****************************************************************************** * Copyright: GPL v3 * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program 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 General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ package dbaCore.logic.normalization; import dbaCore.data.*; import dbaCore.logic.Analysis.RelationUtils; import java.util.ArrayList; /** * Class providing basic synthesis-methods */ public abstract class Synthese implements NormalizationAlgorithm { /** * Unites groups of fd's that are mutual dependent * * @param groups the groups of functional dependencies to work with */ protected void uniteMutualDepdendentGroups(ArrayList<ArrayList<FunctionalDependency>> groups) { ArrayList<ArrayList<FunctionalDependency>> mutualDependentGroups; do { mutualDependentGroups = getMutualDependentGroups(groups); if (mutualDependentGroups.size() == 2) { for (ArrayList<FunctionalDependency> list : groups) { if (list.equals(mutualDependentGroups.get(0))) { list.addAll(mutualDependentGroups.get(1)); break; } } groups.remove(mutualDependentGroups.get(1)); } } while (!mutualDependentGroups.isEmpty()); } /** * Returns two mutual dependent Groups * * @param groups the overall list of FunctionalDependencies to work with * @return A ArrayList of mutual dependent groups */ protected ArrayList<ArrayList<FunctionalDependency>> getMutualDependentGroups (ArrayList<ArrayList<FunctionalDependency>> groups) { ArrayList<ArrayList<FunctionalDependency>> mutualDependentGroups = new ArrayList<>(); for (ArrayList<FunctionalDependency> group : groups) { for (FunctionalDependency fd : group) { for (ArrayList<FunctionalDependency> group2 : groups) { if (group == group2) { continue; } for (FunctionalDependency fd2 : group2) { if (fd.getTargetAttributes().equals(fd2.getSourceAttributes()) && fd2.getTargetAttributes().equals(fd .getSourceAttributes())) { mutualDependentGroups.add(group); mutualDependentGroups.add(group2); return mutualDependentGroups; } } } } } return mutualDependentGroups; } /** * Returns one fully contained relation at a time * * @param schemata all relationSchemata to work with * @return the fully contained RelationSchema or null if none * existing */ protected RelationSchema getFullyContainedRelation(ArrayList<RelationSchema> schemata) { // TODO: Rework me! for (RelationSchema schemaToTest : schemata) { for (RelationSchema schema : schemata) { if (schemaToTest == schema) { continue; } if (getNumberOfMatchingFds(schemaToTest, schema) == schemaToTest.getFunctionalDependencies().size() && !schemaToTest.getFunctionalDependencies().isEmpty()) { return schemaToTest; } } } return null; } /** * Creates and returns a new RelationSchema from a given List of Fds * * @param fds the list of functional dependencies to work with * @return a new RelationSchema */ protected RelationSchema getSchemaFromFds(ArrayList<FunctionalDependency> fds) { RelationSchema schema = new RelationSchema(); // Add fd's schema.setFunctionalDependencies(fds); // Add attributes for (FunctionalDependency fd : schema.getFunctionalDependencies()) { for (Attribute attribute : fd.getSourceAttributes()) { schema.addAttribute(attribute); } for (Attribute attribute : fd.getTargetAttributes()) { schema.addAttribute(attribute); } } return schema; } /** * Looks up, if at least any of the relations contains a candidate * Key for everything * * @param schemata the ArrayList of Relations to search in * @param candidateKeys the candidateKeys to look for in the relations * @return true if any Relation contains a key, false if not */ protected boolean isAnyRelationContainingAKey(ArrayList<RelationSchema> schemata, ArrayList<Key> candidateKeys) { for (RelationSchema schema : schemata) { for (Key candidateKey : candidateKeys) { if (schema.getAttributes().containsAll(candidateKey.getAttributes())) { return true; } } } return false; } /** * Functional Depdendencies with the same left side get a own group * * @param fds the set of functional dependencies to work with * @return a ArrayList of Groups having the same left side */ protected ArrayList<ArrayList<FunctionalDependency>> getGroupsWithSameLeftSide(ArrayList<FunctionalDependency> fds) { ArrayList<ArrayList<FunctionalDependency>> groups = new ArrayList<>(); ArrayList<FunctionalDependency> newList; boolean inserted; for (FunctionalDependency fd : fds) { inserted = false; for (ArrayList<FunctionalDependency> fdlist : groups) { if (hasSameLeftSide(fd, fdlist)) { fdlist.add(fd); inserted = true; break; } } if (!inserted) { newList = new ArrayList<>(); newList.add(fd); groups.add(newList); } } return groups; } /** * Checks if a fd has the same left side as the fds of a list * * @param fd the fd to decide on * @param list the list of fds to compare with * @return true if it has the same left side, false if not */ private boolean hasSameLeftSide(FunctionalDependency fd, ArrayList<FunctionalDependency> list) { for (FunctionalDependency fdep : list) { if (fdep.getSourceAttributes().containsAll(fd.getSourceAttributes()) && fd.getSourceAttributes().containsAll (fdep.getSourceAttributes())) { return true; } } return false; } /** * Returns the number of matching fds of two relations * * @param schema1 first relation to compare * @param schema2 second relation to compare * @return the number of matching functional dependencies */ protected int getNumberOfMatchingFds(RelationSchema schema1, RelationSchema schema2) { int numberOfMatches = 0; for (FunctionalDependency fd1 : schema1.getFunctionalDependencies()) { for (FunctionalDependency fd2 : schema2.getFunctionalDependencies()) { if (fd1.equals(fd2)) { numberOfMatches++; break; } } } return numberOfMatches; } /** * Updates the primary- and foreignKeys of the given relations * * @param relations the relations to work with * @param foreignKeys the foreign keys to take into account */ public void updatePrimaryAndForeignKeys(ArrayList<RelationSchema> relations, ArrayList<ForeignKeyConstraint> foreignKeys) { // set primaryKey for newly created relation for (RelationSchema relation : relations) { RelationUtils.getInstance().resetPrimaryKey(relation); } // set foreign keys for (RelationSchema relation : relations) { for (RelationSchema subRelation : relations) { if (relation == subRelation) { continue; } for (Attribute attr : relation.getAttributes()) { for (Attribute subAttr : subRelation.getAttributes()) { if (attr.getName().equals(subAttr.getName()) && subAttr.getIsPrimaryKey() && RelationUtils.getInstance() .getKey(subRelation).getAttributes().size() == 1) { foreignKeys.add(new ForeignKeyConstraint(relation.getName(), attr.getName(), subRelation.getName(), subAttr.getName())); attr.setIsForeignKey(true); } } } } } } }