View Javadoc

1   /* Copyright 2004, 2005 Acegi Technology Pty Limited
2    *
3    * Licensed under the Apache License, Version 2.0 (the "License");
4    * you may not use this file except in compliance with the License.
5    * You may obtain a copy of the License at
6    *
7    *     http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  
16  package org.acegisecurity.domain.hibernate;
17  
18  import org.acegisecurity.domain.validation.IntrospectionManager;
19  import org.acegisecurity.domain.validation.ValidationRegistryManager;
20  
21  import org.hibernate.EntityMode;
22  import org.hibernate.Hibernate;
23  import org.hibernate.HibernateException;
24  import org.hibernate.SessionFactory;
25  
26  import org.hibernate.metadata.ClassMetadata;
27  
28  import org.hibernate.type.Type;
29  
30  import org.springframework.beans.factory.InitializingBean;
31  
32  import org.springframework.orm.hibernate3.HibernateSystemException;
33  
34  import org.springframework.util.Assert;
35  
36  import java.util.Collection;
37  import java.util.Iterator;
38  import java.util.List;
39  import java.util.Map;
40  
41  
42  /***
43   * {@link IntrospectionManager} that uses Hibernate metadata to locate
44   * children.
45   * 
46   * <p>
47   * Add children objects are added to the <code>List</code> of children objects
48   * to validate, irrespective of whether a save/update/delete operation will
49   * cascade to them. This is not a perfect solution, but addresses most
50   * real-world validation requirements (you can always implement your own
51   * <code>IntrospectionManager</code> if you prefer).
52   * </p>
53   * 
54   * <p>
55   * This implementation only adds properties of a parent object that have a
56   * Hibernate {@link net.sf.hibernate.type.Type} that indicates it is an object
57   * type (ie {@link net.sf.hibernate.type.Type#isObjectType()}).
58   * </p>
59   *
60   * @author Matthew Porter
61   * @author Ben Alex
62   */
63  public class IntrospectionManagerHibernate implements IntrospectionManager,
64      InitializingBean {
65      //~ Instance fields ========================================================
66  
67      private SessionFactory[] sessionFactories;
68      private ValidationRegistryManager validationRegistryManager;
69  
70      //~ Methods ================================================================
71  
72      public void setSessionFactories(SessionFactory[] sessionFactorys) {
73          this.sessionFactories = sessionFactorys;
74      }
75  
76      public SessionFactory[] getSessionFactories() {
77          return this.sessionFactories;
78      }
79  
80      public void setValidationRegistryManager(
81          ValidationRegistryManager validationRegistryManager) {
82          this.validationRegistryManager = validationRegistryManager;
83      }
84  
85      public ValidationRegistryManager getValidationRegistryManager() {
86          return validationRegistryManager;
87      }
88  
89      public void afterPropertiesSet() throws Exception {
90          Assert.notNull(validationRegistryManager, "ValidationRegistryManager is required");
91          Assert.notNull(sessionFactories, "SessionFactories are required");
92          Assert.notEmpty(sessionFactories, "SessionFactories are required");
93          
94          // Eagerly pre-register Validators for all Hibernate metadata-defined classes
95          for (int i = 0; i < sessionFactories.length; i++) {
96      		Map<String,ClassMetadata> metadataMap = this.sessionFactories[i].getAllClassMetadata();
97              Collection<String> mappedClasses = metadataMap.keySet();
98  
99              for (Iterator<String> iter = mappedClasses.iterator(); iter.hasNext();) {
100                 String className = iter.next();
101                 this.validationRegistryManager.findValidator(Class.forName(className));
102             }
103         }
104     }
105 
106     public void obtainImmediateChildren(Object parentObject, List<Object> allObjects) {
107         Assert.notNull(parentObject,
108             "Violation of interface contract: parentObject null");
109         Assert.notNull(allObjects,
110             "Violation of interface contract: allObjects null");
111 
112         ClassMetadata classMetadata = null;
113 
114         try {
115             classMetadata = findMetadata(parentObject.getClass());
116 
117             if (classMetadata != null) {
118                 String[] propertyNames = classMetadata.getPropertyNames();
119 
120                 for (int i = 0; i < propertyNames.length; i++) {
121                     Type propertyType = classMetadata.getPropertyType(propertyNames[i]);
122 
123                     // Add this property to the List of Objects to validate
124                     // only if a Validator is registered for that Object AND
125 					// the object is initialized (ie not lazy loaded)
126                     if (this.validationRegistryManager.findValidator(
127                             propertyType.getReturnedClass()) != null) {
128                         Object childObject = classMetadata.getPropertyValue(parentObject, propertyNames[i], EntityMode.POJO);
129                         if (childObject != null && Hibernate.isInitialized(childObject)) {
130                             allObjects.add(childObject);
131                         }
132                     }
133                 }
134             }
135         } catch (HibernateException he) {
136             throw new HibernateSystemException(he);
137         }
138     }
139     
140     private ClassMetadata findMetadata(Class clazz) throws HibernateSystemException {
141     	for (int i = 0; i < sessionFactories.length; i++) {
142     		ClassMetadata result = sessionFactories[i].getClassMetadata(clazz);
143     		if (result != null) {
144     			return result;
145     		}
146     	}
147     	return null;
148     }
149 }