View Javadoc

1   /*
2    * Copyright 2007-2010 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.kns.datadictionary;
17  
18  import java.util.HashMap;
19  import java.util.HashSet;
20  import java.util.List;
21  import java.util.Map;
22  import java.util.Set;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.springframework.beans.factory.support.DefaultListableBeanFactory;
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  	// keyed by documentTypeName
42  	private Map<String, DocumentEntry> documentEntries;
43  	// keyed by other things
44  	private Map<Class, DocumentEntry> documentEntriesByBusinessObjectClass;
45  	private Map<Class, DocumentEntry> documentEntriesByMaintainableClass;
46  	private Map<String, DataDictionaryEntry> entriesByJstlKey;
47  
48  	// keyed by a class object, and the value is a set of classes that may block the class represented by the key from inactivation 
49  	private Map<Class, Set<InactivationBlockingMetadata>> inactivationBlockersForClass;
50  
51  	public DataDictionaryIndex(DefaultListableBeanFactory ddBeans) {
52  		this.ddBeans = ddBeans;
53  	}
54  
55  	public Map<String, BusinessObjectEntry> getBusinessObjectEntries() {
56  		return this.businessObjectEntries;
57  	}
58  
59  	public Map<String, DocumentEntry> getDocumentEntries() {
60  		return this.documentEntries;
61  	}
62  
63  	public Map<Class, DocumentEntry> getDocumentEntriesByBusinessObjectClass() {
64  		return this.documentEntriesByBusinessObjectClass;
65  	}
66  
67  	public Map<Class, DocumentEntry> getDocumentEntriesByMaintainableClass() {
68  		return this.documentEntriesByMaintainableClass;
69  	}
70  
71  	public Map<String, DataDictionaryEntry> getEntriesByJstlKey() {
72  		return this.entriesByJstlKey;
73  	}
74  
75  	public Map<Class, Set<InactivationBlockingMetadata>> getInactivationBlockersForClass() {
76  		return this.inactivationBlockersForClass;
77  	}
78  
79  	private void buildDDIndicies() {
80          // primary indices
81          businessObjectEntries = new HashMap<String, BusinessObjectEntry>();
82          documentEntries = new HashMap<String, DocumentEntry>();
83  
84          // alternate indices
85          documentEntriesByBusinessObjectClass = new HashMap<Class, DocumentEntry>();
86          documentEntriesByMaintainableClass = new HashMap<Class, DocumentEntry>();
87          entriesByJstlKey = new HashMap<String, DataDictionaryEntry>();
88          
89          // loop over all beans in the context
90          Map<String,BusinessObjectEntry> boBeans = ddBeans.getBeansOfType(BusinessObjectEntry.class);
91          for ( BusinessObjectEntry entry : boBeans.values() ) {
92              //String entryName = (entry.getBaseBusinessObjectClass() != null) ? entry.getBaseBusinessObjectClass().getName() : entry.getBusinessObjectClass().getName();
93              if ((businessObjectEntries.get(entry.getJstlKey()) != null) 
94                      && !((BusinessObjectEntry)businessObjectEntries.get(entry.getJstlKey())).getBusinessObjectClass().equals(entry.getBusinessObjectClass())) {
95                  throw new DataDictionaryException(new StringBuffer("Two business object classes may not share the same jstl key: this=").append(entry.getBusinessObjectClass()).append(" / existing=").append(((BusinessObjectEntry)businessObjectEntries.get(entry.getJstlKey())).getBusinessObjectClass()).toString());
96              }
97  
98              businessObjectEntries.put(entry.getBusinessObjectClass().getName(), entry);
99              businessObjectEntries.put(entry.getBusinessObjectClass().getSimpleName(), entry);
100             // If a "base" class is defined for the entry, index the entry by that class as well.
101             if (entry.getBaseBusinessObjectClass() != null) {
102                 businessObjectEntries.put(entry.getBaseBusinessObjectClass().getName(), entry);
103                 businessObjectEntries.put(entry.getBaseBusinessObjectClass().getSimpleName(), entry);
104             }
105             entriesByJstlKey.put(entry.getJstlKey(), entry);
106         }
107         Map<String,DocumentEntry> docBeans = ddBeans.getBeansOfType(DocumentEntry.class);
108         for ( DocumentEntry entry : docBeans.values() ) {
109             String entryName = entry.getDocumentTypeName();
110 
111             if ((entry instanceof TransactionalDocumentEntry) 
112                     && (documentEntries.get(entry.getFullClassName()) != null) 
113                     && !((DocumentEntry)documentEntries.get(entry.getFullClassName())).getDocumentTypeName()
114                             .equals(entry.getDocumentTypeName())) {
115                 throw new DataDictionaryException(new StringBuffer("Two transactional document types may not share the same document class: this=")
116                         .append(entry.getDocumentTypeName())
117                         .append(" / existing=")
118                         .append(((DocumentEntry)documentEntries.get(entry.getDocumentClass().getName())).getDocumentTypeName()).toString());
119             }
120             if ((entriesByJstlKey.get(entry.getJstlKey()) != null) && !((DocumentEntry)documentEntries.get(entry.getJstlKey())).getDocumentTypeName().equals(entry.getDocumentTypeName())) {
121                 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());
122             }
123 
124             documentEntries.put(entryName, entry);
125             //documentEntries.put(entry.getFullClassName(), entry);
126             documentEntries.put(entry.getDocumentClass().getName(), entry);
127             if (entry.getBaseDocumentClass() != null) {
128             	documentEntries.put(entry.getBaseDocumentClass().getName(), entry);
129             }
130             entriesByJstlKey.put(entry.getJstlKey(), entry);
131 
132             if (entry instanceof TransactionalDocumentEntry) {
133                 TransactionalDocumentEntry tde = (TransactionalDocumentEntry) entry;
134 
135                 documentEntries.put(tde.getDocumentClass().getSimpleName(), entry);
136                 if (tde.getBaseDocumentClass() != null) {
137                 	documentEntries.put(tde.getBaseDocumentClass().getSimpleName(), entry);
138                 }
139             }
140             if (entry instanceof MaintenanceDocumentEntry) {
141                 MaintenanceDocumentEntry mde = (MaintenanceDocumentEntry) entry;
142 
143                 documentEntriesByBusinessObjectClass.put(mde.getBusinessObjectClass(), entry);
144                 documentEntriesByMaintainableClass.put(mde.getMaintainableClass(), entry);
145                 documentEntries.put(mde.getBusinessObjectClass().getSimpleName() + "MaintenanceDocument", entry);
146             }
147         }
148     }
149 
150     private void buildDDInactivationBlockingIndices() {
151         inactivationBlockersForClass = new HashMap<Class, Set<InactivationBlockingMetadata>>();
152         Map<String,BusinessObjectEntry> boBeans = ddBeans.getBeansOfType(BusinessObjectEntry.class);
153         for ( BusinessObjectEntry entry : boBeans.values() ) {
154             List<InactivationBlockingDefinition> inactivationBlockingDefinitions = entry.getInactivationBlockingDefinitions();
155             if (inactivationBlockingDefinitions != null && !inactivationBlockingDefinitions.isEmpty()) {
156                 for (InactivationBlockingDefinition inactivationBlockingDefinition : inactivationBlockingDefinitions) {
157                     registerInactivationBlockingDefinition(inactivationBlockingDefinition);
158                 }
159             }
160         }
161     }
162     
163     private void registerInactivationBlockingDefinition(InactivationBlockingDefinition inactivationBlockingDefinition) {
164         Set<InactivationBlockingMetadata> inactivationBlockingDefinitions = inactivationBlockersForClass.get(inactivationBlockingDefinition.getBlockedBusinessObjectClass());
165         if (inactivationBlockingDefinitions == null) {
166             inactivationBlockingDefinitions = new HashSet<InactivationBlockingMetadata>();
167             inactivationBlockersForClass.put(inactivationBlockingDefinition.getBlockedBusinessObjectClass(), inactivationBlockingDefinitions);
168         }
169         boolean duplicateAdd = ! inactivationBlockingDefinitions.add(inactivationBlockingDefinition);
170         if (duplicateAdd) {
171             throw new DataDictionaryException("Detected duplicate InactivationBlockingDefinition for class " + inactivationBlockingDefinition.getBlockingReferenceBusinessObjectClass().getClass().getName());
172         }
173     }
174     
175     public void run() {
176         LOG.info( "Starting DD Index Building" );
177         buildDDIndicies();
178         LOG.info( "Completed DD Index Building" );
179 //        LOG.info( "Starting DD Validation" );
180 //        validateDD();
181 //        LOG.info( "Ending DD Validation" );
182         LOG.info( "Started DD Inactivation Blocking Index Building" );
183         buildDDInactivationBlockingIndices();
184         LOG.info( "Completed DD Inactivation Blocking Index Building" );
185     }
186 }