package controller; import java.awt.Color; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.HashMap; import java.util.Observable; import util.Failure; import db.Database; import db.DatabaseAccessException; import db.DatabaseConfiguration; /** * The class {@code GroupController} manages all existing {@link Group}s. You can add and remove a {@link Group} and * request a list with all existing {@link Group}s. */ public class GroupController extends Observable { /** * The {@link Database}, where these {@link Group}s are stored. */ private final Database database; /** * The {@link SubspaceController} to rebuild the {@link Feature}s. */ private final SubspaceController subspaceController; /** * Constructs a new {@code GroupController} and sets the static {@code idCountStaticConstraint} in {@link Group}. * * @param database * the {@link Database} where the {@link Group}s are stored. * @param subspaceController * the {@link SubspaceController} the {@link Feature}s refer to. * @throws DatabaseAccessException * if the read operation failed in {@link Database}. */ public GroupController(Database database, SubspaceController subspaceController) throws DatabaseAccessException { if (database == null || subspaceController == null) { throw new IllegalArgumentException("database or subspaceController is null"); } this.database = database; this.subspaceController = subspaceController; try { Statement stmt = database.getConnection().createStatement(); ResultSet rs = stmt.executeQuery("SELECT MAX(Id) FROM StaticConstraints;"); Group.setIdCountStaticConstraint(rs.getInt(1)); stmt.close(); } catch (SQLException e) { throw new DatabaseAccessException(Failure.READ); } } /** * Create a new {@link Group}, and store it in the {@link Database}. * * @param name * The name of the new {@link Group}, may not be {@code null}. * @return The new created {@link Group}. * @throws DatabaseAccessException * if the write operation in the {@link Database} failed. */ public Group createGroup(String name) throws DatabaseAccessException { if (name == null || DatabaseConfiguration.VARCHARLENGTH < name.length()) { throw new IllegalArgumentException("name is null or to long"); } int groupId = 0; Color groupColor = Color.getHSBColor((float) Math.random(), 1f, 1f); try { PreparedStatement prepStmt = this.database.getConnection().prepareStatement( "INSERT INTO Groups VALUES (NULL,?,?,?,?,?)"); prepStmt.setString(1, name); prepStmt.setBoolean(2, true); prepStmt.setInt(3, groupColor.getRGB()); prepStmt.setInt(4, 0); prepStmt.setString(5, ""); prepStmt.execute(); prepStmt.close(); Statement stmt = this.database.getConnection().createStatement(); ResultSet rs = stmt.executeQuery("SELECT MAX(Id) FROM Groups;"); groupId = rs.getInt(1); stmt.close(); } catch (SQLException e) { throw new DatabaseAccessException(Failure.WRITE); } informOberserver(); return new Group(this, database, groupId, name, true, groupColor.getRGB(), null, ""); } /** * Deletes the {@link Group} from the {@link Database}. * * @param group * The {@link Group} to remove. * @throws DatabaseAccessException * if write operation failed in {@link Database}. */ public void removeGroup(Group group) throws DatabaseAccessException { group.remove(); informOberserver(); } /** * Returns a list of all existing {@link Group}s, stored in the {@link Database}. * * @return The list of {@link Group}s. * @throws DatabaseAccessException * if the read operation in the {@link Database} failed. */ public Group[] getGroups() throws DatabaseAccessException { ArrayList<Group> groups = new ArrayList<Group>(); try { HashMap<Integer, Feature> colorFeatures = getRequiredColorFeaturesToRebuildGroups(); Statement stmt = this.database.getConnection().createStatement(); ResultSet rs = stmt.executeQuery("SELECT" + " Id, Name, Visibility, Color, ColorCalculatedByFeature, Description" + " FROM Groups;"); while (rs.next()) { Group group = new Group(this, this.database, rs.getInt(1), rs.getString(2), rs .getBoolean(3), rs.getInt(4), colorFeatures.get(rs .getInt(5)), rs.getString(6)); group.rebuildConstraintsFromDatabase(); groups.add(group); } stmt.close(); } catch (SQLException e) { throw new DatabaseAccessException(Failure.READ); } Group[] groupsArray = new Group[groups.size()]; groups.toArray(groupsArray); return groupsArray; } /** * Returns the max length for a {@code String} handled by the {@code Database}. * * @return the max length. */ public int maxStringLength() { return DatabaseConfiguration.VARCHARLENGTH; } /** * The method gets all needed features to rebuild the list of groups and creates the matching features. * * @return the created list of {@link Feature}s. * @throws SQLException * error in database access. */ private HashMap<Integer, Feature> getRequiredColorFeaturesToRebuildGroups() throws SQLException { Statement stmt = this.database.getConnection().createStatement(); ArrayList<Integer> neededFeatures = new ArrayList<Integer>(); // get all needed Features form the database ResultSet rs = stmt.executeQuery("SELECT ColorCalculatedByFeature FROM Groups;"); while (rs.next()) { neededFeatures.add(rs.getInt(1)); } HashMap<Integer, Feature> features = new HashMap<Integer, Feature>(); for (int i = 0; i < neededFeatures.size(); i++) { if (neededFeatures.get(i) < 0) { // this is legal because we don't need this values when using this function features.put(neededFeatures.get(i), new Feature(this.subspaceController, this.database, -1, "Effect. Outlierness", false, true, 0, 1)); } else if (neededFeatures.get(i) == 0) { features.put(0, null); } else { int featureId = neededFeatures.get(i); rs = stmt.executeQuery("SELECT Name, OutlierFlag, Min, Max" + " FROM Features WHERE Id=" + featureId + ";"); features.put(neededFeatures.get(i), new Feature(this.subspaceController, this.database, featureId, rs.getString(1), rs.getBoolean(2), false, rs.getFloat(3), rs.getFloat(4))); } } stmt.close(); return features; } /** * Returns the {@link SubspaceController} the {@link Feature}s belong to. * * @return the subspace controller. */ public SubspaceController getSubspaceController() { return this.subspaceController; } /** * This method is called to update all Observer, registered to this {@code GroupController}. */ public void informOberserver() { // update observers this.setChanged(); this.notifyObservers(); } }