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.io.Serializable;
28 import java.util.Iterator;
29 import java.util.StringTokenizer;
30
31 import org.hibernate.MappingException;
32 import org.hibernate.PropertyNotFoundException;
33 import org.hibernate.EntityMode;
34 import org.hibernate.engine.CascadeStyle;
35 import org.hibernate.engine.Mapping;
36 import org.hibernate.property.Getter;
37 import org.hibernate.property.PropertyAccessor;
38 import org.hibernate.property.PropertyAccessorFactory;
39 import org.hibernate.property.Setter;
40 import org.hibernate.type.AbstractComponentType;
41 import org.hibernate.type.Type;
42 import org.hibernate.util.ArrayHelper;
43
44 /**
45 * Represents a property as part of an entity or a component.
46 *
47 * @author Gavin King
48 */
49 public class Property implements Serializable, MetaAttributable {
50
51 private String name;
52 private Value value;
53 private String cascade;
54 private boolean updateable = true;
55 private boolean insertable = true;
56 private boolean selectable = true;
57 private boolean optimisticLocked = true;
58 private PropertyGeneration generation = PropertyGeneration.NEVER;
59 private String propertyAccessorName;
60 private boolean lazy;
61 private boolean optional;
62 private String nodeName;
63 private java.util.Map metaAttributes;
64 private PersistentClass persistentClass;
65 private boolean naturalIdentifier;
66
67 public boolean isBackRef() {
68 return false;
69 }
70
71 public Type getType() throws MappingException {
72 return value.getType();
73 }
74
75 public int getColumnSpan() {
76 return value.getColumnSpan();
77 }
78
79 public Iterator getColumnIterator() {
80 return value.getColumnIterator();
81 }
82
83 public String getName() {
84 return name;
85 }
86
87 public boolean isComposite() {
88 return value instanceof Component;
89 }
90
91 public Value getValue() {
92 return value;
93 }
94
95 public boolean isPrimitive(Class clazz) {
96 return getGetter(clazz).getReturnType().isPrimitive();
97 }
98
99 public CascadeStyle getCascadeStyle() throws MappingException {
100 Type type = value.getType();
101 if ( type.isComponentType() && !type.isAnyType() ) {
102 AbstractComponentType actype = (AbstractComponentType) type;
103 int length = actype.getSubtypes().length;
104 for ( int i=0; i<length; i++ ) {
105 if ( actype.getCascadeStyle(i)!=CascadeStyle.NONE ) return CascadeStyle.ALL;
106 }
107 return CascadeStyle.NONE;
108 }
109 else if ( cascade==null || cascade.equals("none") ) {
110 return CascadeStyle.NONE;
111 }
112 else {
113 StringTokenizer tokens = new StringTokenizer(cascade, ", ");
114 CascadeStyle[] styles = new CascadeStyle[ tokens.countTokens() ] ;
115 int i=0;
116 while ( tokens.hasMoreTokens() ) {
117 styles[i++] = CascadeStyle.getCascadeStyle( tokens.nextToken() );
118 }
119 return new CascadeStyle.MultipleCascadeStyle(styles);
120 }
121 }
122
123 public String getCascade() {
124 return cascade;
125 }
126
127 public void setCascade(String cascade) {
128 this.cascade = cascade;
129 }
130
131 public void setName(String name) {
132 this.name = name==null ? null : name.intern();
133 }
134
135 public void setValue(Value value) {
136 this.value = value;
137 }
138
139 public boolean isUpdateable() {
140 // if the property mapping consists of all formulas,
141 // make it non-updateable
142 final boolean[] columnUpdateability = value.getColumnUpdateability();
143 return updateable && (
144 //columnUpdateability.length==0 ||
145 !ArrayHelper.isAllFalse(columnUpdateability)
146 );
147 }
148
149 public boolean isInsertable() {
150 // if the property mapping consists of all formulas,
151 // make it insertable
152 final boolean[] columnInsertability = value.getColumnInsertability();
153 return insertable && (
154 columnInsertability.length==0 ||
155 !ArrayHelper.isAllFalse(columnInsertability)
156 );
157 }
158
159 public PropertyGeneration getGeneration() {
160 return generation;
161 }
162
163 public void setGeneration(PropertyGeneration generation) {
164 this.generation = generation;
165 }
166
167 public void setUpdateable(boolean mutable) {
168 this.updateable = mutable;
169 }
170
171 public void setInsertable(boolean insertable) {
172 this.insertable = insertable;
173 }
174
175 public String getPropertyAccessorName() {
176 return propertyAccessorName;
177 }
178
179 public void setPropertyAccessorName(String string) {
180 propertyAccessorName = string;
181 }
182
183 /**
184 * Approximate!
185 */
186 boolean isNullable() {
187 return value==null || value.isNullable();
188 }
189
190 public boolean isBasicPropertyAccessor() {
191 return propertyAccessorName==null || "property".equals(propertyAccessorName);
192 }
193
194 public java.util.Map getMetaAttributes() {
195 return metaAttributes;
196 }
197
198 public MetaAttribute getMetaAttribute(String attributeName) {
199 return metaAttributes==null?null:(MetaAttribute) metaAttributes.get(attributeName);
200 }
201
202 public void setMetaAttributes(java.util.Map metas) {
203 this.metaAttributes = metas;
204 }
205
206 public boolean isValid(Mapping mapping) throws MappingException {
207 return getValue().isValid(mapping);
208 }
209
210 public String toString() {
211 return getClass().getName() + '(' + name + ')';
212 }
213
214 public void setLazy(boolean lazy) {
215 this.lazy=lazy;
216 }
217
218 public boolean isLazy() {
219 if ( value instanceof ToOne ) {
220 // both many-to-one and one-to-one are represented as a
221 // Property. EntityPersister is relying on this value to
222 // determine "lazy fetch groups" in terms of field-level
223 // interception. So we need to make sure that we return
224 // true here for the case of many-to-one and one-to-one
225 // with lazy="no-proxy"
226 //
227 // * impl note - lazy="no-proxy" currently forces both
228 // lazy and unwrap to be set to true. The other case we
229 // are extremely interested in here is that of lazy="proxy"
230 // where lazy is set to true, but unwrap is set to false.
231 // thus we use both here under the assumption that this
232 // return is really only ever used during persister
233 // construction to determine the lazy property/field fetch
234 // groupings. If that assertion changes then this check
235 // needs to change as well. Partially, this is an issue with
236 // the overloading of the term "lazy" here...
237 ToOne toOneValue = ( ToOne ) value;
238 return toOneValue.isLazy() && toOneValue.isUnwrapProxy();
239 }
240 return lazy;
241 }
242
243 public boolean isOptimisticLocked() {
244 return optimisticLocked;
245 }
246
247 public void setOptimisticLocked(boolean optimisticLocked) {
248 this.optimisticLocked = optimisticLocked;
249 }
250
251 public boolean isOptional() {
252 return optional || isNullable();
253 }
254
255 public void setOptional(boolean optional) {
256 this.optional = optional;
257 }
258
259 public PersistentClass getPersistentClass() {
260 return persistentClass;
261 }
262
263 public void setPersistentClass(PersistentClass persistentClass) {
264 this.persistentClass = persistentClass;
265 }
266
267 public boolean isSelectable() {
268 return selectable;
269 }
270
271 public void setSelectable(boolean selectable) {
272 this.selectable = selectable;
273 }
274
275 public String getNodeName() {
276 return nodeName;
277 }
278
279 public void setNodeName(String nodeName) {
280 this.nodeName = nodeName;
281 }
282
283 public String getAccessorPropertyName( EntityMode mode ) {
284 if ( mode == EntityMode.DOM4J ) {
285 return nodeName;
286 }
287 else {
288 return getName();
289 }
290 }
291
292 // todo : remove
293 public Getter getGetter(Class clazz) throws PropertyNotFoundException, MappingException {
294 return getPropertyAccessor(clazz).getGetter(clazz, name);
295 }
296
297 // todo : remove
298 public Setter getSetter(Class clazz) throws PropertyNotFoundException, MappingException {
299 return getPropertyAccessor(clazz).getSetter(clazz, name);
300 }
301
302 // todo : remove
303 public PropertyAccessor getPropertyAccessor(Class clazz) throws MappingException {
304 return PropertyAccessorFactory.getPropertyAccessor( clazz, getPropertyAccessorName() );
305 }
306
307 public boolean isNaturalIdentifier() {
308 return naturalIdentifier;
309 }
310
311 public void setNaturalIdentifier(boolean naturalIdentifier) {
312 this.naturalIdentifier = naturalIdentifier;
313 }
314 }