DBVIEW
src/org/dbview/db/structure/Field.java
00001 /*
00002         DbView - Graph Visualization
00003     Copyright (C) 2012  Denis BEURIVE
00004 
00005     This program is free software: you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published by
00007     the Free Software Foundation, either version 3 of the License, or
00008     (at your option) any later version.
00009 
00010     This program is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017 */
00018 
00019 /**
00020  * @author Denis Beurive
00021  */
00022 
00023 package org.dbview.db.structure;
00024 
00025 import org.dbview.db.structure.Table;
00026 
00027 /**
00028  * This class represents a table's field.
00029  * @author Denis Beurive
00030  */
00031 public class Field
00032 {
00033         /**
00034          * This constant is used to say that a field is not an index.
00035          */
00036     final static int NOT_INDEX      = 0;
00037 
00038     /**
00039      * This constant is used to say that a field is not a key.
00040      */
00041     final static int NOT_KEY        = 0;
00042 
00043     /**
00044      * This constant is used to say that a field is a multiple index.
00045      */
00046     final static int MULTIPLE_INDEX = 1;
00047 
00048     /**
00049      * This constant is used to say that a field is a unique index.
00050      */
00051     final static int UNIQUE_INDEX   = 2;
00052 
00053     /**
00054      * This constant is used to say that a field is a (hard or soft) foreign key.
00055      */
00056     final static int KEY_FOREIGN    = 1;
00057 
00058     /**
00059      * This constant is used to say that a field is a primary index.
00060      */
00061     final static int KEY_PRIMRY     = 2;
00062     
00063     /**
00064      * This constant is used to say that a field is a "dead" foreign key.
00065      */
00066     final static int KEY_DEAD_FOREIGN = 3;
00067 
00068     /**
00069      * This constant is used to say that a field can not be null.
00070      */
00071     final static int NOT_NULL       = 0;
00072 
00073     /**
00074      * This constant is used to say that a field can be null.
00075      */
00076     final static int CAN_BE_NULL    = 1;
00077 
00078     /** Name of the table. */
00079     private Table __table = null;
00080 
00081     /** Name of the field. */
00082     private String __name = null;
00083     
00084     /** Name of the index that uses this field. */
00085     private String __index_name = null;
00086 
00087     /** Is the field a key? */
00088     private int __key = Field.NOT_KEY;
00089 
00090     /** Is the field an index? **/
00091     private int __index = Field.NOT_INDEX;
00092 
00093     /** Can the field be null? **/
00094     private int __null = Field.NOT_NULL;
00095 
00096     /** If the field is a foreign key (type IFieldTypes.FOREIGN_KEY), then his member represents the field's "reference". */
00097     private Field __reference = null;
00098 
00099     /** If this field is a "reference" for a foreign key, then this field represents the foreign key. */
00100     private Field __fk = null;
00101 
00102     /** If the field is a foreign key, then this attribute tells whether the field is a "hard" (as opposed to "soft") foreign key or not.  */
00103     private Boolean __fk_hard = Boolean.TRUE;
00104     
00105     /** If the field is a "dead" foreign key (type IFieldTypes.DEAD_FOREIGN_KEY), then his member represents the "dead" field's "reference". */
00106     private DeadForeignKey __dead_reference = null;
00107 
00108     /**
00109      * Assuming that this field is a dead foreign key, then the method returns the dead foreign key's reference.
00110      * @return If this field is a dead foreign key, then the method returns its reference.
00111      */
00112     public DeadForeignKey getDeadForeignKey() throws org.dbview.db.structure.FieldException
00113     {
00114         if (! this.isDeadForeignKey()) { throw new FieldException("Field " + this.getFullName() + " is not a dead foreing key!"); }
00115         return this.__dead_reference;
00116     }
00117     
00118     /**
00119      * This method is used to specify that a foreign key is a soft one.
00120      * @remark A soft foreign key defines a soft join. A soft join is defined by foreign keys' names only. You can find this type of joins in MyIsam (MySql) tables, for example.
00121      */
00122     public void isASoftForeignKey()
00123     {
00124         this.__fk_hard = Boolean.FALSE;
00125     }
00126 
00127     /**
00128      * This method is used to specify that a foreign key is a hard one.
00129      * @remark A hard foreign key defines a hard join. A hard join is defined by the table's constraint.
00130      */
00131     public void isAHardForeignKey()
00132     {
00133         this.__fk_hard = Boolean.TRUE;
00134     }
00135 
00136     /**
00137      * Test if a foreign key is soft.
00138      * @return The method returns the value TRUE if the foreign key is soft.
00139      */
00140     public Boolean isSoftForeignKey()
00141     {
00142         return ! this.__fk_hard;
00143     }
00144 
00145     /**
00146      * Test if a foreign key is hard.
00147      * @return The method returns the value TRUE if the foreign key is hard.
00148      */
00149     public Boolean isHardForeignKey()
00150     {
00151         return this.__fk_hard;
00152     }
00153 
00154     /**
00155      * Set the name of the index that uses this field.
00156      * @param in_index_name Name of the index.
00157      */
00158     public void setIndexName(String in_index_name)
00159     {
00160         this.__index_name = in_index_name;
00161     }
00162 
00163     /**
00164      * Return the name of the index that uses this field.
00165      * @return The method returns the name of the index that uses this field.
00166      */
00167     public String getIndexName()
00168     {
00169         return this.__index_name;
00170     }
00171     
00172     /**
00173      * Create a field, and add the field to a table.
00174      * @param in_table Table that contains <i>this</i> field.
00175      * @param in_name Name of the field.
00176      * @throw org.dbview.db.structure.TableException
00177      */
00178     public Field(Table in_table, String in_name) throws org.dbview.db.structure.TableException
00179     {
00180         this.__name = in_name;
00181         this.__table = in_table;
00182         in_table.addField(this);
00183     }
00184 
00185     /**
00186      * Set the field "can be NULL".
00187      */
00188     public void isANull()
00189     {
00190         this.__null = Field.CAN_BE_NULL;
00191     }
00192 
00193     /**
00194      * Set the field a primary key.
00195      */
00196     public void isAPrimaryKey()
00197     {
00198         this.__key = Field.KEY_PRIMRY;
00199     }
00200 
00201     /**
00202      * Set the field a foreign key.
00203      * @param in_reference "Reference" field.
00204      */
00205     public void isAforeignKey(Field in_reference) throws org.dbview.db.structure.FieldException
00206     {
00207         // Debug utile:
00208         // if (this.__fk != null) System.out.println("      " +  this.getFullName() + ".__fk = " + this.__fk.getFullName() + " reference is " + in_reference.getFullName());
00209         
00210         // We make sure that the field has not already been defined as a foreign key.
00211         if (this.__key == Field.KEY_FOREIGN) // if (null != this.__fk) // BUG !!!
00212         { throw new FieldException("Field " + in_reference.getFullName() + " has already been assigned to a foreign key (" + in_reference.__fk.getFullName() + ")!"); }
00213         
00214         // We make sure that the foreign key does not point to its own table.
00215         // Note: A foreign key *CAN* point to its own table.
00216         // if (0 == in_target.getTableName().compareTo(this.getTableName()))
00217         // { throw new FieldException("Field " + this.__name + ": You try to set a foreign key the same table than the foreign key itself!"); }
00218 
00219         this.__key       = Field.KEY_FOREIGN;
00220         this.__reference = in_reference;
00221 
00222         in_reference.__fk = this;
00223     }
00224     
00225     /**
00226      * Set the field a "dead" foreign key.
00227      * @param in_reference_table Name of the reference table.
00228      * @param in_reference_field Name of the reference field.
00229      */
00230     public void isADeadforeignKey(String in_reference_table, String in_reference_field) throws org.dbview.db.structure.FieldException
00231     {
00232         // We make sure that the field has not already been defined as a foreign key.
00233         if (this.__key == Field.KEY_FOREIGN) 
00234         { throw new FieldException("Field " + in_reference_field + " has already been assigned to a foreign key!"); }
00235         
00236         // We make sure that the field has not already been defined as a dead foreign key.
00237         if (this.__key == Field.KEY_DEAD_FOREIGN)
00238         { throw new FieldException("Field " + in_reference_field + " has already been assigned to a dead foreign key!"); }
00239         
00240         this.__key            = Field.KEY_DEAD_FOREIGN;
00241         this.__dead_reference = new DeadForeignKey(in_reference_table, in_reference_field); 
00242     }
00243 
00244     /**
00245      * Set the field a unique index.
00246      */
00247     public void isAUniqueIndex()
00248     {
00249         this.__index = Field.UNIQUE_INDEX;
00250     }
00251 
00252     /**
00253      * Set the field a multiple index.
00254      */
00255     public void isAMultipleIndex()
00256     {
00257         this.__index = Field.MULTIPLE_INDEX;
00258     }
00259 
00260     /**
00261      * If the field is a "reference" for a foreign key, then the method returns the foreign key.
00262      * @return If the field is a "reference" for a foreign key, then the method returns the foreign key.
00263      *         Otherwise, the method returns the value null.
00264      */
00265     public Field getFkToMe()
00266     {
00267         return this.__fk;
00268     }
00269 
00270     /**
00271      * Return the name of the field.
00272      * @return The method returns the name of the field.
00273      */
00274     public String getName()
00275     {
00276         return this.__name;
00277     }
00278 
00279     /**
00280      * This method returns the full name of the field. The full name includes the table's name.
00281      * @return The method returns the full name of the field.
00282      */
00283     public String getFullName()
00284     {
00285         return this.__table.getName() + "." + this.__name;
00286     }
00287 
00288     /**
00289      * Return the field's "reference" (if the field is a foreign key).
00290      * @return The method returns the field's "reference".
00291      * @throws org.dbview.db.structure.FieldException
00292      */
00293     public Field getReference() throws org.dbview.db.structure.FieldException
00294     {
00295         if (Field.KEY_FOREIGN != this.__key)
00296         { throw new FieldException("The field \"" + this.__name + "\" is not a foreign key."); }
00297         return this.__reference;
00298     }
00299 
00300     /**
00301      * Return the table that contains <i>this</i> field.
00302      * @return The method returns the table that contains "this" field.
00303      */
00304     public Table getTable()
00305     {
00306         return this.__table;
00307     }
00308 
00309     /**
00310      * This method returns the name of the field's table.
00311      * @return The method returns the name of the field's table.
00312      */
00313     public String getTableName()
00314     {
00315         return this.__table.getName();
00316     }
00317 
00318     /**
00319      * Test if the field is a primary key.
00320      * @return The method returns the value TRUE if the field is a primary key.
00321      *         Otherwise the method returns the value FALSE.
00322      */
00323     public Boolean isPrimaryKey()
00324     {
00325         return Field.KEY_PRIMRY == this.__key;
00326     }
00327 
00328     /**
00329      * Test if the field is a foreign key.
00330      * @return The method returns the value TRUE if the field is a foreign key.
00331      *         Otherwise the method returns the value FALSE.
00332      */
00333     public Boolean isForeignKey()
00334     {
00335         return Field.KEY_FOREIGN == this.__key;
00336     }
00337     
00338     /**
00339      * Test if the field is a dead foreign key.
00340      * @return The method returns the value TRUE if the field is a dead foreign key.
00341      *         Otherwise the method returns the value FALSE.
00342      */
00343     public Boolean isDeadForeignKey()
00344     {
00345         return Field.KEY_DEAD_FOREIGN == this.__key;
00346     }
00347 
00348     /**
00349      * Test if the field is a key (primary or foreign).
00350      * @return The method returns the value TRUE if the field is a key.
00351      *         Otherwise the method returns the value FALSE.
00352      */
00353     public Boolean isKey()
00354     {
00355         return Field.KEY_FOREIGN == this.__key
00356                ||
00357                Field.KEY_PRIMRY == this.__key;
00358     }
00359 
00360     /**
00361      * Test if the field is a unique index.
00362      * @return The method returns the value TRUE if the field is a unique index.
00363      *         Otherwise the method returns the value FALSE.
00364      */
00365     public Boolean isUniqueIndex()
00366     {
00367         return Field.UNIQUE_INDEX == this.__index;
00368     }
00369 
00370     /**
00371      * Test if the field has a unique constraint.
00372      * @return The method returns the value TRUE if the field is a unique constraint.
00373      *         Otherwise the method returns the value FALSE.
00374      */
00375     public Boolean isUnique()
00376     {
00377         return this.isUniqueIndex();
00378     }
00379 
00380     /**
00381      * Test if the field is a multiple index.
00382      * @return The method returns the value TRUE if the field is a multiple index.
00383      *         Otherwise the method returns the value FALSE.
00384      */
00385     public Boolean isMultipleIndex()
00386     {
00387         return Field.MULTIPLE_INDEX == this.__index;
00388     }
00389 
00390     /**
00391      * Test if the field is an index.
00392      * @return The method returns the value TRUE if the field is an index.
00393      *         Otherwise the method returns the value FALSE.
00394      */
00395     public Boolean isIndex()
00396     {
00397         return Field.UNIQUE_INDEX == this.__index
00398                ||
00399                Field.MULTIPLE_INDEX == this.__index;
00400     }
00401 
00402     /**
00403      * Test if the field can be null.
00404      * @return The method returns the value TRUE if the field can be null.
00405      */
00406     public Boolean isNull()
00407     {
00408         return this.__null == Field.CAN_BE_NULL;
00409     }
00410 
00411     /**
00412      * Create a textual representation of the field.
00413          * @return The method returns a textual representation of the field.
00414      */
00415     public String toString()
00416     {
00417         String prefix = "";
00418         String back   = "";
00419 
00420         if (null != this.__fk) { back = " <= " + this.__fk.getFullName(); }
00421 
00422         if (this.isPrimaryKey())  { return "PK " + this.getFullName() + back; }
00423 
00424         if (this.isUniqueIndex()) { prefix = "UI"; }
00425         else if (this.isMultipleIndex()) { prefix = "MI"; }
00426         else { prefix = "ST"; }
00427 
00428         if (this.isForeignKey()) { return "FK(" + prefix + ") " + this.getFullName() + " => " + this.__reference.getFullName() + back; }
00429         
00430         if (this.isDeadForeignKey()) { return "DFK(" + prefix + ") " + this.getFullName() + " => " + this.__dead_reference.getFullName() + back; }
00431 
00432         return prefix + " " + this.getFullName() + back;
00433     }
00434 }