1 package com.bonevich.erj.model;
2
3 import com.bonevich.util.dependency.Dynamic;
4
5 import java.util.Iterator;
6
7 /*** A class that represents ...
8 *
9 * @see Relation
10 * @author Jeffrey D. Bonevich <bonevich@telocity.com>
11 */
12 public final class ForeignKey extends KeyConstraint
13 {
14 //////////////////////////////////////////////////////////
15 // Constants
16 public static final String NEW_FOREIGNKEY_STR = "fk_";
17
18 public static final String ZERO_TO_ZERO_STR = "ZERO_TO_ZERO";
19 public static final String ONE_TO_ZERO_STR = "ONE_TO_ZERO";
20 public static final String ONE_TO_ONE_STR = "ONE_TO_ONE";
21 public static final String ZERO_TO_MANY_STR = "ZERO_TO_MANY";
22 public static final String ONE_TO_MANY_STR = "ONE_TO_MANY";
23 public static final String ZERO_TO_MANY_MANDATORY_STR = "ZERO_TO_MANY_MANDATORY";
24 public static final String ONE_TO_MANY_MANDATORY_STR = "ONE_TO_MANY_MANDATORY";
25 public static final String MANY_TO_MANY_STR = "MANY_TO_MANY";
26
27 public static class Cardinality
28 {
29 private String _name;
30 private String _label;
31 protected Cardinality(String name, String label)
32 {
33 _name = name;
34 _label = label;
35 }
36 public String getName()
37 {
38 return _name;
39 }
40 public String toString()
41 {
42 return _label;
43 }
44 }
45 public static final Cardinality ZERO_TO_ZERO = new Cardinality(ZERO_TO_ZERO_STR, "0:0");
46 public static final Cardinality ONE_TO_ZERO = new Cardinality(ONE_TO_ZERO_STR, "1:0");
47 public static final Cardinality ONE_TO_ONE = new Cardinality(ONE_TO_ONE_STR, "1:1");
48 public static final Cardinality ZERO_TO_MANY = new Cardinality(ZERO_TO_MANY_STR, "0:M");
49 public static final Cardinality ONE_TO_MANY = new Cardinality(ONE_TO_MANY_STR, "1:M");
50 public static final Cardinality ZERO_TO_MANY_MANDATORY = new Cardinality(ZERO_TO_MANY_MANDATORY_STR, "0:M+");
51 public static final Cardinality ONE_TO_MANY_MANDATORY = new Cardinality(ONE_TO_MANY_MANDATORY_STR, "1:M+");
52 public static final Cardinality MANY_TO_MANY = new Cardinality(MANY_TO_MANY_STR, "M:M");
53
54 public static final Cardinality[] CARDINALITY_ARRAY = {
55 ZERO_TO_ZERO,
56 ONE_TO_ZERO ,
57 ONE_TO_ONE ,
58 ZERO_TO_MANY,
59 ONE_TO_MANY ,
60 ZERO_TO_MANY_MANDATORY,
61 ONE_TO_MANY_MANDATORY ,
62 MANY_TO_MANY
63 };
64
65 //////////////////////////////////////////////////////////
66 // Attributes
67 private Cardinality _cardinality = ZERO_TO_MANY;
68
69 //////////////////////////////////////////////////////////
70 // Associations
71 private Relation _referentRelation;
72
73 //////////////////////////////////////////////////////////
74 // Dependency sentries
75 private Dynamic _dyn_cardinality = new Dynamic();
76
77 //////////////////////////////////////////////////////////
78 // Constructors
79 public ForeignKey(Relation relation, Attribute[] attributes, Relation referentRelation)
80 {
81 super(relation, attributes);
82 _referentRelation = referentRelation;
83 setIdentifier(NEW_FOREIGNKEY_STR + relation.getKeyCount());
84 }
85
86 //////////////////////////////////////////////////////////
87 // Getter/Setters
88 public Cardinality getCardinality()
89 {
90 _dyn_cardinality.onGet();
91 return _cardinality;
92 }
93 public void setCardinality(Cardinality cardinality)
94 {
95 if (_cardinality != cardinality)
96 {
97 _dyn_cardinality.onSet();
98 _cardinality = cardinality;
99
100 if (cardinality != MANY_TO_MANY)
101 {
102 // copy over attributes from referent's primary key
103 // FIXME: don't want to do this multiple times, just once
104 // Maybe make it a dependency tracked issue - automatically update
105 // by tracking PK of referent as a dependent attr?
106
107 // go with more traditional entity-relationship model?
108 // more accurately reflected in graph than relational model,
109 // but not really the info model I want
110 }
111
112 if (cardinality == ONE_TO_MANY ||
113 cardinality == ONE_TO_MANY_MANDATORY)
114 {
115 Iterator attrs = getAttributeIterator();
116 while (attrs.hasNext())
117 {
118 ((Attribute) attrs.next()).setConstraint(AttributeConstraint.NOTNULL);
119 }
120 }
121 else if (cardinality == ONE_TO_ZERO ||
122 cardinality == ONE_TO_ONE)
123 {
124 boolean makePK = true;
125 Iterator keys = getRelation().getKeyIterator();
126 while (keys.hasNext())
127 {
128 if (keys.next() instanceof PrimaryKey)
129 {
130 makePK = false;
131 break;
132 }
133 }
134
135 Attribute[] attrArray = new Attribute[_attributes.size()];
136 attrArray = (Attribute[])_attributes.toArray(attrArray);
137 if (makePK)
138 {
139 getRelation().createPrimaryKey(attrArray);
140 } else {
141 getRelation().createUniqueKey(attrArray);
142 for (int i = 0; i < attrArray.length; i++)
143 {
144 attrArray[i].setConstraint(AttributeConstraint.NOTNULL);
145 }
146 }
147 }
148 else if (cardinality == MANY_TO_MANY)
149 {
150 Iterator attrs = getAttributeIterator();
151 while (attrs.hasNext())
152 {
153 //FIXME: concurrent mod problem here?
154 // or something else; can still see attr in FigRelation,
155 // changed to null or notnull constraint
156 getRelation().deleteAttribute((Attribute) attrs.next());
157 }
158 }
159
160 }
161 }
162
163 //////////////////////////////////////////////////////////
164 // Operations
165 public Relation getReferentRelation()
166 {
167 return _referentRelation;
168 }
169
170 public void accept(KeyVisitor visitor)
171 {
172 visitor.visitForeignKey(this);
173 }
174
175 } /* end class ForeignKey */
This page was automatically generated by Maven