001/**
002 * Copyright 2005-2016 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 */
016package org.kuali.rice.krad.service.impl;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022
023import org.apache.commons.lang.StringUtils;
024import org.apache.log4j.Logger;
025import org.kuali.rice.core.api.config.ConfigurationException;
026import org.kuali.rice.coreservice.api.CoreServiceApiServiceLocator;
027import org.kuali.rice.coreservice.api.component.Component;
028import org.kuali.rice.coreservice.api.component.ComponentService;
029import org.kuali.rice.coreservice.framework.parameter.ParameterConstants;
030import org.kuali.rice.krad.datadictionary.BusinessObjectEntry;
031import org.kuali.rice.krad.datadictionary.DataObjectEntry;
032import org.kuali.rice.krad.datadictionary.DocumentEntry;
033import org.kuali.rice.krad.datadictionary.TransactionalDocumentEntry;
034import org.kuali.rice.krad.document.TransactionalDocument;
035import org.kuali.rice.krad.service.DataDictionaryComponentPublisherService;
036import org.kuali.rice.krad.service.DataDictionaryService;
037import org.kuali.rice.krad.service.KualiModuleService;
038import org.kuali.rice.krad.util.KRADUtils;
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 */
047public 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 (DataObjectEntry dataObjectEntry : getDataDictionaryService().getDataDictionary().getDataObjectEntries().values()) {
076            try {
077                Component component = deriveComponentFromDataObjectEntry(dataObjectEntry);
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: " + dataObjectEntry.getDataObjectClass(), 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 deriveComponentFromDataObjectEntry(DataObjectEntry dataObjectEntry) {
111        if (dataObjectEntry.getBaseDataObjectClass() != null) {
112            return deriveComponentFromClass(dataObjectEntry.getBaseDataObjectClass());
113        }
114
115        return deriveComponentFromClass(dataObjectEntry.getDataObjectClass());
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 annotation.  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            DataObjectEntry doe = getDataDictionaryService().getDataDictionary().getDataObjectEntry(componentSourceClass.getName());
139            if (doe != null) {
140                return doe.getObjectLabel();
141            } else {
142                return componentSourceClass.getAnnotation(ParameterConstants.COMPONENT.class).component();
143            }
144        }
145
146        /*
147         * If block that determines if the class is either a BusinessObject or a TransactionalDocument
148         * return calls try to either get the BusinessObjectEntry's ObjectLable, or grabbing the
149         * data dictionary's BusinessTitleForClass if it is a BusinessObject, or the DocumentLabel if it is a
150         * TransactionalDocument
151         */
152        if (TransactionalDocument.class.isAssignableFrom(componentSourceClass)) {
153            return getDataDictionaryService().getDocumentLabelByClass(componentSourceClass);
154        }
155        DataObjectEntry doe = getDataDictionaryService().getDataDictionary().getDataObjectEntry(componentSourceClass.getName());
156        if (doe != null) {
157            return doe.getObjectLabel();
158        } else {
159            return KRADUtils.getBusinessTitleForClass(componentSourceClass);
160        }
161    }
162
163    public DataDictionaryService getDataDictionaryService() {
164        return dataDictionaryService;
165    }
166
167    public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
168        this.dataDictionaryService = dataDictionaryService;
169    }
170
171    public KualiModuleService getKualiModuleService() {
172        return kualiModuleService;
173    }
174
175    public void setKualiModuleService(KualiModuleService kualiModuleService) {
176        this.kualiModuleService = kualiModuleService;
177    }
178
179    public ComponentService getComponentService() {
180        if (componentService == null) {
181            componentService = CoreServiceApiServiceLocator.getComponentService();
182        }
183        return componentService;
184    }
185
186    public void setComponentService(ComponentService componentService) {
187        this.componentService = componentService;
188    }
189
190    public String getApplicationId() {
191        return applicationId;
192    }
193
194    public void setApplicationId(String applicationId) {
195        this.applicationId = applicationId;
196    }
197
198}