View Javadoc

1   /**
2    * Copyright 2005-2012 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.datadictionary;
17  
18  import org.apache.commons.logging.Log;
19  import org.apache.commons.logging.LogFactory;
20  import org.springframework.beans.factory.support.DefaultListableBeanFactory;
21  
22  import java.util.HashMap;
23  import java.util.HashSet;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  
28  /**
29   * Encapsulates a set of statically generated (typically during startup)
30   * DataDictionary indexes 
31   * 
32   * @author Kuali Rice Team (rice.collab@kuali.org)
33   */
34  public class DataDictionaryIndex implements Runnable {
35  	private static final Log LOG = LogFactory.getLog(DataDictionaryIndex.class);
36  	
37  	private DefaultListableBeanFactory ddBeans;
38  	
39  	// keyed by BusinessObject class
40  	private Map<String, BusinessObjectEntry> businessObjectEntries;
41  	private Map<String, DataObjectEntry> objectEntries;
42  	
43  	// keyed by documentTypeName
44  	private Map<String, DocumentEntry> documentEntries;
45  	// keyed by other things
46  	private Map<Class, DocumentEntry> documentEntriesByBusinessObjectClass;
47  	private Map<Class, DocumentEntry> documentEntriesByMaintainableClass;
48  	private Map<String, DataDictionaryEntry> entriesByJstlKey;
49  
50  	// keyed by a class object, and the value is a set of classes that may block the class represented by the key from inactivation 
51  	private Map<Class, Set<InactivationBlockingMetadata>> inactivationBlockersForClass;
52  
53  	public DataDictionaryIndex(DefaultListableBeanFactory ddBeans) {
54  		this.ddBeans = ddBeans;
55  	}
56  
57  	public Map<String, BusinessObjectEntry> getBusinessObjectEntries() {
58  		return this.businessObjectEntries;
59  	}
60  
61  	public Map<String, DataObjectEntry> getDataObjectEntries() {
62  		return this.objectEntries;
63  	}
64  
65  	public Map<String, DocumentEntry> getDocumentEntries() {
66  		return this.documentEntries;
67  	}
68  
69  	public Map<Class, DocumentEntry> getDocumentEntriesByBusinessObjectClass() {
70  		return this.documentEntriesByBusinessObjectClass;
71  	}
72  
73  	public Map<Class, DocumentEntry> getDocumentEntriesByMaintainableClass() {
74  		return this.documentEntriesByMaintainableClass;
75  	}
76  
77  	public Map<String, DataDictionaryEntry> getEntriesByJstlKey() {
78  		return this.entriesByJstlKey;
79  	}
80  
81  	public Map<Class, Set<InactivationBlockingMetadata>> getInactivationBlockersForClass() {
82  		return this.inactivationBlockersForClass;
83  	}
84  
85  	private void buildDDIndicies() {
86          // primary indices
87          businessObjectEntries = new HashMap<String, BusinessObjectEntry>();
88          objectEntries = new HashMap<String, DataObjectEntry>();
89          documentEntries = new HashMap<String, DocumentEntry>();
90  
91          // alternate indices
92          documentEntriesByBusinessObjectClass = new HashMap<Class, DocumentEntry>();
93          documentEntriesByMaintainableClass = new HashMap<Class, DocumentEntry>();
94          entriesByJstlKey = new HashMap<String, DataDictionaryEntry>();
95          
96          // loop over all beans in the context
97          Map<String, DataObjectEntry> boBeans = ddBeans.getBeansOfType(DataObjectEntry.class);
98          for ( DataObjectEntry entry : boBeans.values() ) {
99          	
100             DataObjectEntry indexedEntry = objectEntries.get(entry.getJstlKey());
101             if (indexedEntry == null){
102             	indexedEntry = businessObjectEntries.get(entry.getJstlKey());
103             }
104         	if ( (indexedEntry != null) 
105                     && !(indexedEntry.getDataObjectClass().equals(entry.getDataObjectClass()))) {
106                 throw new DataDictionaryException(new StringBuffer("Two object classes may not share the same jstl key: this=").append(entry.getDataObjectClass()).append(" / existing=").append(indexedEntry.getDataObjectClass()).toString());
107             }
108 
109         	// put all BO and DO entries in the objectEntries map
110         	objectEntries.put(entry.getDataObjectClass().getName(), entry);
111             objectEntries.put(entry.getDataObjectClass().getSimpleName(), entry);
112             
113             // keep a separate map of BO entries for now
114         	if (entry instanceof BusinessObjectEntry){
115         		BusinessObjectEntry boEntry = (BusinessObjectEntry)entry; 
116 		
117 	            businessObjectEntries.put(boEntry.getBusinessObjectClass().getName(), boEntry);
118 	            businessObjectEntries.put(boEntry.getBusinessObjectClass().getSimpleName(), boEntry);
119 	            // If a "base" class is defined for the entry, index the entry by that class as well.
120 	            if (boEntry.getBaseBusinessObjectClass() != null) {
121 	                businessObjectEntries.put(boEntry.getBaseBusinessObjectClass().getName(), boEntry);
122 	                businessObjectEntries.put(boEntry.getBaseBusinessObjectClass().getSimpleName(), boEntry);
123 	            }
124         	}
125             
126         	entriesByJstlKey.put(entry.getJstlKey(), entry);
127         }
128         
129         //Build Document Entry Index
130         Map<String,DocumentEntry> docBeans = ddBeans.getBeansOfType(DocumentEntry.class);
131         for ( DocumentEntry entry : docBeans.values() ) {
132             String entryName = entry.getDocumentTypeName();
133 
134             if ((entry instanceof TransactionalDocumentEntry) 
135                     && (documentEntries.get(entry.getFullClassName()) != null) 
136                     && !((DocumentEntry)documentEntries.get(entry.getFullClassName())).getDocumentTypeName()
137                             .equals(entry.getDocumentTypeName())) {
138                 throw new DataDictionaryException(new StringBuffer("Two transactional document types may not share the same document class: this=")
139                         .append(entry.getDocumentTypeName())
140                         .append(" / existing=")
141                         .append(((DocumentEntry)documentEntries.get(entry.getDocumentClass().getName())).getDocumentTypeName()).toString());
142             }
143             if ((documentEntries.get(entry.getJstlKey()) != null) && !((DocumentEntry)documentEntries.get(entry.getJstlKey())).getDocumentTypeName().equals(entry.getDocumentTypeName())) {
144                 throw new DataDictionaryException(new StringBuffer("Two document types may not share the same jstl key: this=").append(entry.getDocumentTypeName()).append(" / existing=").append(((DocumentEntry)documentEntries.get(entry.getJstlKey())).getDocumentTypeName()).toString());
145             }
146 
147             documentEntries.put(entryName, entry);
148             //documentEntries.put(entry.getFullClassName(), entry);
149             documentEntries.put(entry.getDocumentClass().getName(), entry);
150             if (entry.getBaseDocumentClass() != null) {
151             	documentEntries.put(entry.getBaseDocumentClass().getName(), entry);
152             }
153             entriesByJstlKey.put(entry.getJstlKey(), entry);
154 
155             if (entry instanceof TransactionalDocumentEntry) {
156                 TransactionalDocumentEntry tde = (TransactionalDocumentEntry) entry;
157 
158                 documentEntries.put(tde.getDocumentClass().getSimpleName(), entry);
159                 if (tde.getBaseDocumentClass() != null) {
160                 	documentEntries.put(tde.getBaseDocumentClass().getSimpleName(), entry);
161                 }
162             }
163             if (entry instanceof MaintenanceDocumentEntry) {
164                 MaintenanceDocumentEntry mde = (MaintenanceDocumentEntry) entry;
165 
166                 documentEntriesByBusinessObjectClass.put(mde.getDataObjectClass(), entry);
167                 documentEntriesByMaintainableClass.put(mde.getMaintainableClass(), entry);
168                 documentEntries.put(mde.getDataObjectClass().getSimpleName() + "MaintenanceDocument", entry);
169             }
170         }
171     }
172 
173     private void buildDDInactivationBlockingIndices() {
174         inactivationBlockersForClass = new HashMap<Class, Set<InactivationBlockingMetadata>>();
175         Map<String,DataObjectEntry> doBeans = ddBeans.getBeansOfType(DataObjectEntry.class);
176         for ( DataObjectEntry entry : doBeans.values() ) {
177             List<InactivationBlockingDefinition> inactivationBlockingDefinitions = entry.getInactivationBlockingDefinitions();
178             if (inactivationBlockingDefinitions != null && !inactivationBlockingDefinitions.isEmpty()) {
179                 for (InactivationBlockingDefinition inactivationBlockingDefinition : inactivationBlockingDefinitions) {
180                     registerInactivationBlockingDefinition(inactivationBlockingDefinition);
181                 }
182             }
183         }
184     }
185     
186     private void registerInactivationBlockingDefinition(InactivationBlockingDefinition inactivationBlockingDefinition) {
187         Set<InactivationBlockingMetadata> inactivationBlockingDefinitions = inactivationBlockersForClass.get(inactivationBlockingDefinition.getBlockedBusinessObjectClass());
188         if (inactivationBlockingDefinitions == null) {
189             inactivationBlockingDefinitions = new HashSet<InactivationBlockingMetadata>();
190             inactivationBlockersForClass.put(inactivationBlockingDefinition.getBlockedBusinessObjectClass(), inactivationBlockingDefinitions);
191         }
192         boolean duplicateAdd = ! inactivationBlockingDefinitions.add(inactivationBlockingDefinition);
193         if (duplicateAdd) {
194             throw new DataDictionaryException("Detected duplicate InactivationBlockingDefinition for class " + inactivationBlockingDefinition.getBlockingReferenceBusinessObjectClass().getClass().getName());
195         }
196     }
197     
198     public void run() {
199         LOG.info( "Starting DD Index Building" );
200         buildDDIndicies();
201         LOG.info( "Completed DD Index Building" );
202 //        LOG.info( "Starting DD Validation" );
203 //        validateDD();
204 //        LOG.info( "Ending DD Validation" );
205         LOG.info( "Started DD Inactivation Blocking Index Building" );
206         buildDDInactivationBlockingIndices();
207         LOG.info( "Completed DD Inactivation Blocking Index Building" );
208     }
209 }