1 /*
2 * Hibernate, Relational Persistence for Idiomatic Java
3 *
4 * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
5 * indicated by the @author tags or express copyright attribution
6 * statements applied by the authors. All third-party contributions are
7 * distributed under license by Red Hat Middleware LLC.
8 *
9 * This copyrighted material is made available to anyone wishing to use, modify,
10 * copy, or redistribute it subject to the terms and conditions of the GNU
11 * Lesser General Public License, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this distribution; if not, write to:
20 * Free Software Foundation, Inc.
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301 USA
23 *
24 */
25 package org.hibernate.mapping;
26
27 import java.util.ArrayList;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Properties;
31
32 import org.hibernate.FetchMode;
33 import org.hibernate.MappingException;
34 import org.hibernate.dialect.Dialect;
35 import org.hibernate.engine.Mapping;
36 import org.hibernate.id.IdentifierGenerator;
37 import org.hibernate.id.IdentifierGeneratorFactory;
38 import org.hibernate.id.IdentityGenerator;
39 import org.hibernate.id.PersistentIdentifierGenerator;
40 import org.hibernate.type.Type;
41 import org.hibernate.type.TypeFactory;
42 import org.hibernate.util.ReflectHelper;
43
44 /**
45 * Any value that maps to columns.
46 * @author Gavin King
47 */
48 public class SimpleValue implements KeyValue {
49
50 private final List columns = new ArrayList();
51 private String typeName;
52 private Properties identifierGeneratorProperties;
53 private String identifierGeneratorStrategy = "assigned";
54 private String nullValue;
55 private Table table;
56 private String foreignKeyName;
57 private boolean alternateUniqueKey;
58 private Properties typeParameters;
59 private boolean cascadeDeleteEnabled;
60
61 public boolean isCascadeDeleteEnabled() {
62 return cascadeDeleteEnabled;
63 }
64
65 public void setCascadeDeleteEnabled(boolean cascadeDeleteEnabled) {
66 this.cascadeDeleteEnabled = cascadeDeleteEnabled;
67 }
68
69 public void addColumn(Column column) {
70 if ( !columns.contains(column) ) columns.add(column);
71 column.setValue(this);
72 column.setTypeIndex( columns.size()-1 );
73 }
74
75 public void addFormula(Formula formula) {
76 columns.add(formula);
77 }
78
79 public boolean hasFormula() {
80 Iterator iter = getColumnIterator();
81 while ( iter.hasNext() ) {
82 Object o = iter.next();
83 if (o instanceof Formula) return true;
84 }
85 return false;
86 }
87
88 public int getColumnSpan() {
89 return columns.size();
90 }
91 public Iterator getColumnIterator() {
92 return columns.iterator();
93 }
94 public List getConstraintColumns() {
95 return columns;
96 }
97 public String getTypeName() {
98 return typeName;
99 }
100 public void setTypeName(String type) {
101 this.typeName = type;
102 }
103 public void setTable(Table table) {
104 this.table = table;
105 }
106
107 public SimpleValue(Table table) {
108 this.table = table;
109 }
110
111 public SimpleValue() {}
112
113 public void createForeignKey() throws MappingException {}
114
115 public void createForeignKeyOfEntity(String entityName) {
116 if ( !hasFormula() && !"none".equals(getForeignKeyName())) {
117 ForeignKey fk = table.createForeignKey( getForeignKeyName(), getConstraintColumns(), entityName );
118 fk.setCascadeDeleteEnabled(cascadeDeleteEnabled);
119 }
120 }
121
122 public IdentifierGenerator createIdentifierGenerator(
123 Dialect dialect,
124 String defaultCatalog,
125 String defaultSchema,
126 RootClass rootClass)
127 throws MappingException {
128
129 Properties params = new Properties();
130
131 //if the hibernate-mapping did not specify a schema/catalog, use the defaults
132 //specified by properties - but note that if the schema/catalog were specified
133 //in hibernate-mapping, or as params, they will already be initialized and
134 //will override the values set here (they are in identifierGeneratorProperties)
135 if ( defaultSchema!=null ) {
136 params.setProperty(PersistentIdentifierGenerator.SCHEMA, defaultSchema);
137 }
138 if ( defaultCatalog!=null ) {
139 params.setProperty(PersistentIdentifierGenerator.CATALOG, defaultCatalog);
140 }
141
142 //pass the entity-name, if not a collection-id
143 if (rootClass!=null) {
144 params.setProperty( IdentifierGenerator.ENTITY_NAME, rootClass.getEntityName() );
145 }
146
147 //init the table here instead of earlier, so that we can get a quoted table name
148 //TODO: would it be better to simply pass the qualified table name, instead of
149 // splitting it up into schema/catalog/table names
150 String tableName = getTable().getQuotedName(dialect);
151 params.setProperty( PersistentIdentifierGenerator.TABLE, tableName );
152
153 //pass the column name (a generated id almost always has a single column)
154 String columnName = ( (Column) getColumnIterator().next() ).getQuotedName(dialect);
155 params.setProperty( PersistentIdentifierGenerator.PK, columnName );
156
157 if (rootClass!=null) {
158 StringBuffer tables = new StringBuffer();
159 Iterator iter = rootClass.getIdentityTables().iterator();
160 while ( iter.hasNext() ) {
161 Table table= (Table) iter.next();
162 tables.append( table.getQuotedName(dialect) );
163 if ( iter.hasNext() ) tables.append(", ");
164 }
165 params.setProperty( PersistentIdentifierGenerator.TABLES, tables.toString() );
166 }
167 else {
168 params.setProperty( PersistentIdentifierGenerator.TABLES, tableName );
169 }
170
171 if (identifierGeneratorProperties!=null) {
172 params.putAll(identifierGeneratorProperties);
173 }
174
175 return IdentifierGeneratorFactory.create(
176 identifierGeneratorStrategy,
177 getType(),
178 params,
179 dialect
180 );
181
182 }
183
184 public boolean isUpdateable() {
185 //needed to satisfy KeyValue
186 return true;
187 }
188
189 public FetchMode getFetchMode() {
190 return FetchMode.SELECT;
191 }
192
193 public Properties getIdentifierGeneratorProperties() {
194 return identifierGeneratorProperties;
195 }
196
197 public String getNullValue() {
198 return nullValue;
199 }
200
201 public Table getTable() {
202 return table;
203 }
204
205 /**
206 * Returns the identifierGeneratorStrategy.
207 * @return String
208 */
209 public String getIdentifierGeneratorStrategy() {
210 return identifierGeneratorStrategy;
211 }
212
213 public boolean isIdentityColumn(Dialect dialect) {
214 return IdentifierGeneratorFactory.getIdentifierGeneratorClass(identifierGeneratorStrategy, dialect)
215 .equals(IdentityGenerator.class);
216 }
217
218 /**
219 * Sets the identifierGeneratorProperties.
220 * @param identifierGeneratorProperties The identifierGeneratorProperties to set
221 */
222 public void setIdentifierGeneratorProperties(Properties identifierGeneratorProperties) {
223 this.identifierGeneratorProperties = identifierGeneratorProperties;
224 }
225
226 /**
227 * Sets the identifierGeneratorStrategy.
228 * @param identifierGeneratorStrategy The identifierGeneratorStrategy to set
229 */
230 public void setIdentifierGeneratorStrategy(String identifierGeneratorStrategy) {
231 this.identifierGeneratorStrategy = identifierGeneratorStrategy;
232 }
233
234 /**
235 * Sets the nullValue.
236 * @param nullValue The nullValue to set
237 */
238 public void setNullValue(String nullValue) {
239 this.nullValue = nullValue;
240 }
241
242 public String getForeignKeyName() {
243 return foreignKeyName;
244 }
245
246 public void setForeignKeyName(String foreignKeyName) {
247 this.foreignKeyName = foreignKeyName;
248 }
249
250 public boolean isAlternateUniqueKey() {
251 return alternateUniqueKey;
252 }
253
254 public void setAlternateUniqueKey(boolean unique) {
255 this.alternateUniqueKey = unique;
256 }
257
258 public boolean isNullable() {
259 if ( hasFormula() ) return true;
260 boolean nullable = true;
261 Iterator iter = getColumnIterator();
262 while ( iter.hasNext() ) {
263 if ( !( (Column) iter.next() ).isNullable() ) {
264 nullable = false;
265 return nullable; //shortcut
266 }
267 }
268 return nullable;
269 }
270
271 public boolean isSimpleValue() {
272 return true;
273 }
274
275 public boolean isValid(Mapping mapping) throws MappingException {
276 return getColumnSpan()==getType().getColumnSpan(mapping);
277 }
278
279 public Type getType() throws MappingException {
280 if (typeName==null) {
281 throw new MappingException("No type name");
282 }
283 Type result = TypeFactory.heuristicType(typeName, typeParameters);
284 if (result==null) {
285 String msg = "Could not determine type for: " + typeName;
286 if(table != null){
287 msg += ", at table: " + table.getName();
288 }
289 if(columns!=null && columns.size()>0) {
290 msg += ", for columns: " + columns;
291 }
292 throw new MappingException(msg);
293 }
294 return result;
295 }
296
297 public void setTypeUsingReflection(String className, String propertyName) throws MappingException {
298 if (typeName==null) {
299 if (className==null) {
300 throw new MappingException("you must specify types for a dynamic entity: " + propertyName);
301 }
302 typeName = ReflectHelper.reflectedPropertyClass(className, propertyName).getName();
303 }
304 }
305
306 public boolean isTypeSpecified() {
307 return typeName!=null;
308 }
309
310 public void setTypeParameters(Properties parameterMap) {
311 this.typeParameters = parameterMap;
312 }
313
314 public Properties getTypeParameters() {
315 return typeParameters;
316 }
317
318 public String toString() {
319 return getClass().getName() + '(' + columns.toString() + ')';
320 }
321
322 public Object accept(ValueVisitor visitor) {
323 return visitor.accept(this);
324 }
325
326 public boolean[] getColumnInsertability() {
327 boolean[] result = new boolean[ getColumnSpan() ];
328 int i = 0;
329 Iterator iter = getColumnIterator();
330 while ( iter.hasNext() ) {
331 Selectable s = (Selectable) iter.next();
332 result[i++] = !s.isFormula();
333 }
334 return result;
335 }
336
337 public boolean[] getColumnUpdateability() {
338 return getColumnInsertability();
339 }
340 }