/*
* The Kuali Financial System, a comprehensive financial management system for higher education.
*
* Copyright 2005-2014 The Kuali Foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kuali.kfs.sys.service.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.ojb.broker.metadata.ClassDescriptor;
import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException;
import org.kuali.kfs.sys.KFSPropertyConstants;
import org.kuali.kfs.sys.businessobject.BusinessObjectComponent;
import org.kuali.kfs.sys.businessobject.BusinessObjectProperty;
import org.kuali.kfs.sys.businessobject.DataMappingFieldDefinition;
import org.kuali.kfs.sys.businessobject.FunctionalFieldDescription;
import org.kuali.kfs.sys.dataaccess.BusinessObjectMetaDataDao;
import org.kuali.kfs.sys.service.KfsBusinessObjectMetaDataService;
import org.kuali.kfs.sys.service.NonTransactional;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.kns.service.BusinessObjectMetaDataService;
import org.kuali.rice.kns.service.DataDictionaryService;
import org.kuali.rice.krad.bo.BusinessObject;
import org.kuali.rice.krad.bo.DataObjectRelationship;
import org.kuali.rice.krad.datadictionary.AttributeDefinition;
import org.kuali.rice.krad.datadictionary.BusinessObjectEntry;
import org.kuali.rice.krad.service.BusinessObjectService;
import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
import org.kuali.rice.krad.service.LookupService;
@NonTransactional
public class KfsBusinessObjectMetaDataServiceImpl implements KfsBusinessObjectMetaDataService {
private Logger LOG = Logger.getLogger(KfsBusinessObjectMetaDataServiceImpl.class);
private DataDictionaryService dataDictionaryService;
private ParameterService parameterService;
private BusinessObjectService businessObjectService;
private BusinessObjectMetaDataService businessObjectMetaDataService;
private BusinessObjectMetaDataDao businessObjectMetaDataDao;
private LookupService lookupService;
public void setParameterService(ParameterService parameterService) {
this.parameterService = parameterService;
}
protected BusinessObjectComponent getBusinessObjectComponent(Class<?> componentClass) {
return new BusinessObjectComponent(KRADServiceLocatorWeb.getKualiModuleService().getNamespaceCode(componentClass), (org.kuali.rice.kns.datadictionary.BusinessObjectEntry) dataDictionaryService.getDataDictionary().getBusinessObjectEntry(componentClass.getName()));
}
@Override
public BusinessObjectProperty getBusinessObjectProperty(String componentClass, String propertyName) {
try {
return new BusinessObjectProperty(getBusinessObjectComponent(Class.forName(componentClass)), dataDictionaryService.getDataDictionary().getBusinessObjectEntry(componentClass).getAttributeDefinition(propertyName));
}
catch (ClassNotFoundException ex) {
LOG.error( "Unable to resolve component class name: " + componentClass );
}
return null;
}
@Override
public DataMappingFieldDefinition getDataMappingFieldDefinition(String componentClass, String propertyName) {
Map<String, String> primaryKeys = new HashMap<String, String>();
primaryKeys.put(KFSPropertyConstants.COMPONENT_CLASS, componentClass);
primaryKeys.put(KFSPropertyConstants.PROPERTY_NAME, propertyName);
FunctionalFieldDescription functionalFieldDescription = (FunctionalFieldDescription) businessObjectService.findByPrimaryKey(FunctionalFieldDescription.class, primaryKeys);
if (functionalFieldDescription == null) {
functionalFieldDescription = new FunctionalFieldDescription(componentClass, propertyName);
}
functionalFieldDescription.refreshNonUpdateableReferences();
return getDataMappingFieldDefinition(functionalFieldDescription);
}
@Override
public DataMappingFieldDefinition getDataMappingFieldDefinition(FunctionalFieldDescription functionalFieldDescription) {
BusinessObjectEntry businessObjectEntry = dataDictionaryService.getDataDictionary().getBusinessObjectEntry(functionalFieldDescription.getComponentClass());
String propertyType = "";
try {
propertyType = PropertyUtils.getPropertyType(businessObjectEntry.getBusinessObjectClass().newInstance(), functionalFieldDescription.getPropertyName()).getSimpleName();
}
catch (Exception e) {
if (LOG.isDebugEnabled()) {
LOG.debug("KfsBusinessObjectMetaDataServiceImpl unable to get type of property: " + functionalFieldDescription.getPropertyName(), e);
}
}
return new DataMappingFieldDefinition(functionalFieldDescription, (org.kuali.rice.kns.datadictionary.BusinessObjectEntry) businessObjectEntry,
businessObjectEntry.getAttributeDefinition(functionalFieldDescription.getPropertyName()),
businessObjectMetaDataDao.getFieldMetaData(businessObjectEntry.getBusinessObjectClass(), functionalFieldDescription.getPropertyName()),
propertyType,
getReferenceComponentLabel(businessObjectEntry.getBusinessObjectClass(), functionalFieldDescription.getPropertyName()));
}
@Override
public List<BusinessObjectComponent> findBusinessObjectComponents(String namespaceCode, String componentLabel) {
Map<Class, BusinessObjectComponent> matchingBusinessObjectComponents = new HashMap<Class, BusinessObjectComponent>();
Pattern componentLabelRegex = null;
if (StringUtils.isNotBlank(componentLabel)) {
String patternStr = componentLabel.replace("*", ".*").toUpperCase();
try {
componentLabelRegex = Pattern.compile(patternStr);
}
catch (PatternSyntaxException ex) {
LOG.error("KfsBusinessObjectMetaDataServiceImpl unable to parse componentLabel pattern, ignoring.", ex);
}
}
for (BusinessObjectEntry businessObjectEntry : dataDictionaryService.getDataDictionary().getBusinessObjectEntries().values()) {
if ((StringUtils.isBlank(namespaceCode) || namespaceCode.equals(KRADServiceLocatorWeb.getKualiModuleService().getNamespaceCode(businessObjectEntry.getBusinessObjectClass())))
&& ((componentLabelRegex == null) || (StringUtils.isNotBlank(businessObjectEntry.getObjectLabel()) && componentLabelRegex.matcher(businessObjectEntry.getObjectLabel().toUpperCase()).matches()))) {
matchingBusinessObjectComponents.put(businessObjectEntry.getBusinessObjectClass(), new BusinessObjectComponent(KRADServiceLocatorWeb.getKualiModuleService().getNamespaceCode(businessObjectEntry.getBusinessObjectClass()), (org.kuali.rice.kns.datadictionary.BusinessObjectEntry) businessObjectEntry));
}
}
return new ArrayList<BusinessObjectComponent>(matchingBusinessObjectComponents.values());
}
@Override
public List<BusinessObjectProperty> findBusinessObjectProperties(String namespaceCode, String componentLabel, String propertyLabel) {
List<BusinessObjectComponent> businessObjectComponents = findBusinessObjectComponents(namespaceCode, componentLabel);
Pattern propertyLabelRegex = null;
if (StringUtils.isNotBlank(propertyLabel)) {
String patternStr = propertyLabel.replace("*", ".*").toUpperCase();
try {
propertyLabelRegex = Pattern.compile(patternStr);
}
catch (PatternSyntaxException ex) {
LOG.error("KfsBusinessObjectMetaDataServiceImpl unable to parse propertyLabel pattern, ignoring.", ex);
}
}
List<BusinessObjectProperty> matchingBusinessObjectProperties = new ArrayList<BusinessObjectProperty>();
for (BusinessObjectComponent businessObjectComponent : businessObjectComponents) {
for (AttributeDefinition attributeDefinition : dataDictionaryService.getDataDictionary().getBusinessObjectEntry(businessObjectComponent.getComponentClass().toString()).getAttributes()) {
if (!attributeDefinition.getName().endsWith(KFSPropertyConstants.VERSION_NUMBER) && !attributeDefinition.getName().endsWith(KFSPropertyConstants.OBJECT_ID) && ((propertyLabelRegex == null) || propertyLabelRegex.matcher(attributeDefinition.getLabel().toUpperCase()).matches())) {
matchingBusinessObjectProperties.add(new BusinessObjectProperty(businessObjectComponent, attributeDefinition));
}
}
}
return matchingBusinessObjectProperties;
}
@Override
public List<FunctionalFieldDescription> findFunctionalFieldDescriptions(String namespaceCode, String componentLabel, String propertyLabel, String description, String active) {
Set<String> componentClasses = new HashSet<String>();
Set<String> propertyNames = new HashSet<String>();
for (BusinessObjectProperty businessObjectProperty : findBusinessObjectProperties(namespaceCode, componentLabel, propertyLabel)) {
componentClasses.add(businessObjectProperty.getComponentClass());
propertyNames.add(businessObjectProperty.getPropertyName());
}
Map<String, String> fieldValues = new HashMap<String, String>();
fieldValues.put(KFSPropertyConstants.NAMESPACE_CODE, namespaceCode);
fieldValues.put(KFSPropertyConstants.COMPONENT_CLASS, buildOrCriteria(componentClasses));
fieldValues.put(KFSPropertyConstants.PROPERTY_NAME, buildOrCriteria(propertyNames));
fieldValues.put(KFSPropertyConstants.DESCRIPTION, description);
fieldValues.put(KFSPropertyConstants.ACTIVE, active);
List<FunctionalFieldDescription> searchResults = (List<FunctionalFieldDescription>) lookupService.findCollectionBySearchHelper(FunctionalFieldDescription.class, fieldValues, false);
for (FunctionalFieldDescription functionalFieldDescription : searchResults) {
functionalFieldDescription.refreshNonUpdateableReferences();
}
return searchResults;
}
protected String buildOrCriteria(Set<String> values) {
StringBuffer orCriteria = new StringBuffer();
List<String> valueList = new ArrayList<String>(values);
for (int i = 0; i < valueList.size(); i++) {
orCriteria.append(valueList.get(i));
if (i < (valueList.size() - 1)) {
orCriteria.append("|");
}
}
return orCriteria.toString();
}
@Override
public boolean isMatch(String componentClass, String propertyName, String tableNameSearchCriterion, String fieldNameSearchCriterion) {
ClassDescriptor classDescriptor = null;
try {
classDescriptor = org.apache.ojb.broker.metadata.MetadataManager.getInstance().getGlobalRepository().getDescriptorFor(componentClass);
Pattern tableNameRegex = null;
if (StringUtils.isNotBlank(tableNameSearchCriterion)) {
String patternStr = tableNameSearchCriterion.replace("*", ".*").toUpperCase();
try {
tableNameRegex = Pattern.compile(patternStr);
}
catch (PatternSyntaxException ex) {
LOG.error("DataMappingFieldDefinitionLookupableHelperServiceImpl unable to parse tableName pattern, ignoring.", ex);
}
}
Pattern fieldNameRegex = null;
if (StringUtils.isNotBlank(fieldNameSearchCriterion)) {
String patternStr = fieldNameSearchCriterion.replace("*", ".*").toUpperCase();
try {
fieldNameRegex = Pattern.compile(patternStr);
}
catch (PatternSyntaxException ex) {
LOG.error("DataMappingFieldDefinitionLookupableHelperServiceImpl unable to parse fieldName pattern, ignoring.", ex);
}
}
return ((tableNameRegex == null) || tableNameRegex.matcher(classDescriptor.getFullTableName().toUpperCase()).matches()) && ((fieldNameRegex == null) || ((classDescriptor.getFieldDescriptorByName(propertyName) != null) && fieldNameRegex.matcher(classDescriptor.getFieldDescriptorByName(propertyName).getColumnName().toUpperCase()).matches()));
}
catch (ClassNotPersistenceCapableException e) {
return StringUtils.isBlank(tableNameSearchCriterion) && StringUtils.isBlank(fieldNameSearchCriterion);
}
}
@Override
public String getReferenceComponentLabel(Class componentClass, String propertyName) {
DataObjectRelationship relationship = null;
try {
relationship = businessObjectMetaDataService.getBusinessObjectRelationship((BusinessObject) componentClass.newInstance(), propertyName);
}
catch (Exception e) {
if (LOG.isDebugEnabled()) {
LOG.debug("KfsBusinessObjectMetadataServiceImpl unable to instantiate componentClass: " + componentClass, e);
}
}
if (relationship != null) {
return dataDictionaryService.getDataDictionary().getBusinessObjectEntry(relationship.getRelatedClass().getName()).getObjectLabel();
}
return "";
}
public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
this.dataDictionaryService = dataDictionaryService;
}
public void setBusinessObjectService(BusinessObjectService businessObjectService) {
this.businessObjectService = businessObjectService;
}
public void setBusinessObjectMetaDataService(BusinessObjectMetaDataService businessObjectMetaDataService) {
this.businessObjectMetaDataService = businessObjectMetaDataService;
}
public void setBusinessObjectMetaDataDao(BusinessObjectMetaDataDao businessObjectMetaDataDao) {
this.businessObjectMetaDataDao = businessObjectMetaDataDao;
}
public void setLookupService(LookupService lookupService) {
this.lookupService = lookupService;
}
}