001    /**
002     * Copyright 2005-2014 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.rice.krad.service.impl;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.apache.log4j.Logger;
020    import org.kuali.rice.core.api.config.ConfigurationException;
021    import org.kuali.rice.coreservice.api.CoreServiceApiServiceLocator;
022    import org.kuali.rice.coreservice.api.component.Component;
023    import org.kuali.rice.coreservice.api.component.ComponentService;
024    import org.kuali.rice.coreservice.framework.parameter.ParameterConstants;
025    import org.kuali.rice.krad.bo.BusinessObject;
026    import org.kuali.rice.krad.datadictionary.BusinessObjectEntry;
027    import org.kuali.rice.krad.datadictionary.DocumentEntry;
028    import org.kuali.rice.krad.datadictionary.TransactionalDocumentEntry;
029    import org.kuali.rice.krad.document.TransactionalDocument;
030    import org.kuali.rice.krad.service.DataDictionaryComponentPublisherService;
031    import org.kuali.rice.krad.service.DataDictionaryService;
032    import org.kuali.rice.krad.service.KualiModuleService;
033    import org.kuali.rice.krad.util.KRADUtils;
034    
035    import java.util.ArrayList;
036    import java.util.HashMap;
037    import java.util.List;
038    import java.util.Map;
039    
040    /**
041     * Reference implementation of the {@code DataDictionaryComponentPublisherService}.
042     *
043     * This implementation derives components from the DataDictionary for all BusinessObjects and Documents.
044     *
045     * @author Kuali Rice Team (rice.collab@kuali.org)
046     */
047    public class DataDictionaryComponentPublisherServiceImpl implements DataDictionaryComponentPublisherService {
048    
049        private static final Logger LOG = Logger.getLogger(DataDictionaryComponentPublisherServiceImpl.class);
050    
051        private static final String DEFAULT_COMPONENT_SET_ID_PREFIX = "DD:";
052    
053        private DataDictionaryService dataDictionaryService;
054        private KualiModuleService kualiModuleService;
055        private ComponentService componentService;
056        private String applicationId;
057    
058        @Override
059        public void publishAllComponents() {
060            List<Component> componentsToPublish = getComponentsToPublish();
061            getComponentService().publishDerivedComponents(generateComponentSetId(), componentsToPublish);
062        }
063    
064        protected String generateComponentSetId() {
065            if (StringUtils.isBlank(getApplicationId())) {
066                throw new ConfigurationException("A valid non-null, non-blank application id was not injected into " + getClass().getName());
067            }
068            return DEFAULT_COMPONENT_SET_ID_PREFIX + getApplicationId();
069        }
070    
071        protected List<Component> getComponentsToPublish() {
072            List<Component> components = new ArrayList<Component>();
073    
074            Map<String, Component> uniqueComponentMap = new HashMap<String, Component>();
075            for (BusinessObjectEntry businessObjectEntry : getDataDictionaryService().getDataDictionary().getBusinessObjectEntries().values()) {
076                try {
077                    Component component = deriveComponentFromBusinessObjectEntry(businessObjectEntry);
078                    uniqueComponentMap.put(component.getCode(), component);
079                }
080                catch (Exception e) {
081                    LOG.error("An exception was encountered when attempting to publish all components for business object class: " + businessObjectEntry.getBusinessObjectClass(), e);
082                }
083            }
084            for (DocumentEntry documentEntry : getDataDictionaryService().getDataDictionary().getDocumentEntries().values()) {
085                if (documentEntry instanceof TransactionalDocumentEntry) {
086                    try {
087                        Component component = deriveComponentFromDocumentEntry(documentEntry);
088                        uniqueComponentMap.put(component.getCode(), component);
089                    }
090                    catch (Exception e) {
091                        LOG.error("An exception was encountered when attempting to publish all components for transactional document class: " + documentEntry.getDocumentClass(), e);
092                    }
093                }
094            }
095            components.addAll(uniqueComponentMap.values());
096            return components;
097        }
098    
099            protected Component deriveComponentFromClass(Class<?> componentSourceClass) {
100            String componentCode = getKualiModuleService().getComponentCode(componentSourceClass);
101            String componentName = deriveComponentName(componentSourceClass);
102            String namespace = getKualiModuleService().getNamespaceCode(componentSourceClass);
103            if (StringUtils.isBlank(componentName)) {
104                componentName = componentCode;
105            }
106            Component.Builder detailType = Component.Builder.create(namespace, componentCode, componentName);
107            return detailType.build();
108        }
109    
110        protected Component deriveComponentFromBusinessObjectEntry(BusinessObjectEntry businessObjectEntry) {
111            Class<?> businessObjectClass = businessObjectEntry.getBaseBusinessObjectClass();
112            if (businessObjectClass == null) {
113                businessObjectClass = businessObjectEntry.getBusinessObjectClass();
114            }
115            return deriveComponentFromClass(businessObjectClass);
116        }
117    
118        protected Component deriveComponentFromDocumentEntry(DocumentEntry documentEntry) {
119            Class<?> documentClass = documentEntry.getBaseDocumentClass();
120            if (documentClass == null) {
121                documentClass = documentEntry.getDocumentClass();
122            }
123            return deriveComponentFromClass(documentClass);
124        }
125    
126            protected String deriveComponentName(Class<?> componentSourceClass) {
127            if (componentSourceClass == null) {
128                throw new IllegalArgumentException("The deriveComponentName method requires non-null componentSourceClass");
129            }
130            
131            /*
132             * Some business objects have a Component annotation that sets the value
133             * of the classes annotaion.  This if block will test to see if it is there, try to get the
134             * component value from the Data Dictionary if the BusinessObjectEntry exists, if it doesn't
135             * exist, it will fall back to the annotation's value.
136             */
137            if (componentSourceClass.isAnnotationPresent(ParameterConstants.COMPONENT.class)) {
138                BusinessObjectEntry boe = getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(componentSourceClass.getName());
139                if (boe != null) {
140                    return boe.getObjectLabel();
141                }
142                else {
143                    return ((ParameterConstants.COMPONENT) componentSourceClass.getAnnotation(ParameterConstants.COMPONENT.class)).component();
144                }
145            }
146    
147            /*
148             * If block that determines if the class is either a BusinessObject or a TransactionalDocument
149             * return calls try to either get the BusinessObjectEntry's ObjectLable, or grabbing the
150             * data dictionary's BusinessTitleForClass if it is a BusinessObject, or the DocumentLabel if it is a
151             * TransactionalDocument
152             */
153            if (TransactionalDocument.class.isAssignableFrom(componentSourceClass)) {
154                return getDataDictionaryService().getDocumentLabelByClass(componentSourceClass);
155            }
156            else if (BusinessObject.class.isAssignableFrom(componentSourceClass) ) {
157                BusinessObjectEntry boe = getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(componentSourceClass.getName());
158                if (boe != null) {
159                    return boe.getObjectLabel();
160                }
161                else {
162                    return KRADUtils.getBusinessTitleForClass(componentSourceClass);
163                }
164            }
165            throw new IllegalArgumentException("The deriveComponentName method of requires TransactionalDocument or BusinessObject class. Was: " + componentSourceClass.getName() );
166        }
167    
168        public DataDictionaryService getDataDictionaryService() {
169            return dataDictionaryService;
170        }
171    
172        public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
173            this.dataDictionaryService = dataDictionaryService;
174        }
175    
176        public KualiModuleService getKualiModuleService() {
177            return kualiModuleService;
178        }
179    
180        public void setKualiModuleService(KualiModuleService kualiModuleService) {
181            this.kualiModuleService = kualiModuleService;
182        }
183    
184        public ComponentService getComponentService() {
185            if (componentService == null) {
186                componentService = CoreServiceApiServiceLocator.getComponentService();
187            }
188            return componentService;
189        }
190    
191        public void setComponentService(ComponentService componentService) {
192            this.componentService = componentService;
193        }
194    
195        public String getApplicationId() {
196            return applicationId;
197        }
198    
199        public void setApplicationId(String applicationId) {
200            this.applicationId = applicationId;
201        }
202        
203    }