001 /* 002 * Copyright 2011 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.kfs.sys.service.impl; 017 018 import java.util.ArrayList; 019 import java.util.HashMap; 020 import java.util.HashSet; 021 import java.util.List; 022 import java.util.Map; 023 import java.util.Set; 024 import java.util.regex.Pattern; 025 import java.util.regex.PatternSyntaxException; 026 027 import org.apache.commons.beanutils.PropertyUtils; 028 import org.apache.commons.lang.StringUtils; 029 import org.apache.log4j.Logger; 030 import org.apache.ojb.broker.metadata.ClassDescriptor; 031 import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException; 032 import org.kuali.kfs.sys.KFSPropertyConstants; 033 import org.kuali.kfs.sys.businessobject.BusinessObjectComponent; 034 import org.kuali.kfs.sys.businessobject.BusinessObjectProperty; 035 import org.kuali.kfs.sys.businessobject.DataMappingFieldDefinition; 036 import org.kuali.kfs.sys.businessobject.FunctionalFieldDescription; 037 import org.kuali.kfs.sys.dataaccess.BusinessObjectMetaDataDao; 038 import org.kuali.kfs.sys.service.KfsBusinessObjectMetaDataService; 039 import org.kuali.kfs.sys.service.NonTransactional; 040 import org.kuali.rice.kns.bo.BusinessObject; 041 import org.kuali.rice.kns.bo.BusinessObjectRelationship; 042 import org.kuali.rice.kns.datadictionary.AttributeDefinition; 043 import org.kuali.rice.kns.datadictionary.BusinessObjectEntry; 044 import org.kuali.rice.kns.service.BusinessObjectMetaDataService; 045 import org.kuali.rice.kns.service.BusinessObjectService; 046 import org.kuali.rice.kns.service.DataDictionaryService; 047 import org.kuali.rice.kns.service.LookupService; 048 import org.kuali.rice.kns.service.ParameterService; 049 050 @NonTransactional 051 public class KfsBusinessObjectMetaDataServiceImpl implements KfsBusinessObjectMetaDataService { 052 private Logger LOG = Logger.getLogger(KfsBusinessObjectMetaDataServiceImpl.class); 053 private DataDictionaryService dataDictionaryService; 054 private ParameterService parameterService; 055 private BusinessObjectService businessObjectService; 056 private BusinessObjectMetaDataService businessObjectMetaDataService; 057 private BusinessObjectMetaDataDao businessObjectMetaDataDao; 058 private LookupService lookupService; 059 060 public void setParameterService(ParameterService parameterService) { 061 this.parameterService = parameterService; 062 } 063 064 public BusinessObjectComponent getBusinessObjectComponent(String componentClass) { 065 try { 066 return new BusinessObjectComponent(parameterService.getNamespace(Class.forName(componentClass)), dataDictionaryService.getDataDictionary().getBusinessObjectEntry(componentClass)); 067 } 068 catch (ClassNotFoundException e) { 069 throw new RuntimeException("KfsBusinessObjectMetaDataServiceImpl unable to translate the provided componentClass String into a Class: " + componentClass, e); 070 } 071 } 072 073 public BusinessObjectProperty getBusinessObjectProperty(String componentClass, String propertyName) { 074 return new BusinessObjectProperty(getBusinessObjectComponent(componentClass), dataDictionaryService.getDataDictionary().getBusinessObjectEntry(componentClass).getAttributeDefinition(propertyName)); 075 } 076 077 public DataMappingFieldDefinition getDataMappingFieldDefinition(String componentClass, String propertyName) { 078 Map<String, String> primaryKeys = new HashMap<String, String>(); 079 primaryKeys.put(KFSPropertyConstants.COMPONENT_CLASS, componentClass); 080 primaryKeys.put(KFSPropertyConstants.PROPERTY_NAME, propertyName); 081 FunctionalFieldDescription functionalFieldDescription = (FunctionalFieldDescription) businessObjectService.findByPrimaryKey(FunctionalFieldDescription.class, primaryKeys); 082 if (functionalFieldDescription == null) { 083 functionalFieldDescription = new FunctionalFieldDescription(componentClass, propertyName); 084 } 085 functionalFieldDescription.refreshNonUpdateableReferences(); 086 return getDataMappingFieldDefinition(functionalFieldDescription); 087 } 088 089 public DataMappingFieldDefinition getDataMappingFieldDefinition(FunctionalFieldDescription functionalFieldDescription) { 090 BusinessObjectEntry businessObjectEntry = dataDictionaryService.getDataDictionary().getBusinessObjectEntry(functionalFieldDescription.getComponentClass()); 091 String propertyType = ""; 092 try { 093 propertyType = PropertyUtils.getPropertyType(businessObjectEntry.getBusinessObjectClass().newInstance(), functionalFieldDescription.getPropertyName()).getSimpleName(); 094 } 095 catch (Exception e) { 096 if (LOG.isDebugEnabled()) { 097 LOG.debug("KfsBusinessObjectMetaDataServiceImpl unable to get type of property: " + functionalFieldDescription.getPropertyName(), e); 098 } 099 } 100 return new DataMappingFieldDefinition(functionalFieldDescription, businessObjectEntry, businessObjectEntry.getAttributeDefinition(functionalFieldDescription.getPropertyName()), businessObjectMetaDataDao.getFieldMetaData(businessObjectEntry.getBusinessObjectClass(), functionalFieldDescription.getPropertyName()), propertyType, getReferenceComponentLabel(businessObjectEntry.getBusinessObjectClass(), functionalFieldDescription.getPropertyName())); 101 } 102 103 public List<BusinessObjectComponent> findBusinessObjectComponents(String namespaceCode, String componentLabel) { 104 Map<Class, BusinessObjectComponent> matchingBusinessObjectComponents = new HashMap<Class, BusinessObjectComponent>(); 105 Pattern componentLabelRegex = null; 106 if (StringUtils.isNotBlank(componentLabel)) { 107 String patternStr = componentLabel.replace("*", ".*").toUpperCase(); 108 try { 109 componentLabelRegex = Pattern.compile(patternStr); 110 } 111 catch (PatternSyntaxException ex) { 112 LOG.error("KfsBusinessObjectMetaDataServiceImpl unable to parse componentLabel pattern, ignoring.", ex); 113 } 114 } 115 for (BusinessObjectEntry businessObjectEntry : dataDictionaryService.getDataDictionary().getBusinessObjectEntries().values()) { 116 if ((StringUtils.isBlank(namespaceCode) || namespaceCode.equals(parameterService.getNamespace(businessObjectEntry.getBusinessObjectClass()))) 117 && ((componentLabelRegex == null) || (StringUtils.isNotBlank(businessObjectEntry.getObjectLabel()) && componentLabelRegex.matcher(businessObjectEntry.getObjectLabel().toUpperCase()).matches()))) { 118 matchingBusinessObjectComponents.put(businessObjectEntry.getBusinessObjectClass(), new BusinessObjectComponent(parameterService.getNamespace(businessObjectEntry.getBusinessObjectClass()), businessObjectEntry)); 119 } 120 } 121 return new ArrayList<BusinessObjectComponent>(matchingBusinessObjectComponents.values()); 122 } 123 124 public List<BusinessObjectProperty> findBusinessObjectProperties(String namespaceCode, String componentLabel, String propertyLabel) { 125 List<BusinessObjectComponent> businessObjectComponents = findBusinessObjectComponents(namespaceCode, componentLabel); 126 127 Pattern propertyLabelRegex = null; 128 if (StringUtils.isNotBlank(propertyLabel)) { 129 String patternStr = propertyLabel.replace("*", ".*").toUpperCase(); 130 try { 131 propertyLabelRegex = Pattern.compile(patternStr); 132 } 133 catch (PatternSyntaxException ex) { 134 LOG.error("KfsBusinessObjectMetaDataServiceImpl unable to parse propertyLabel pattern, ignoring.", ex); 135 } 136 } 137 138 List<BusinessObjectProperty> matchingBusinessObjectProperties = new ArrayList<BusinessObjectProperty>(); 139 for (BusinessObjectComponent businessObjectComponent : businessObjectComponents) { 140 for (AttributeDefinition attributeDefinition : dataDictionaryService.getDataDictionary().getBusinessObjectEntry(businessObjectComponent.getComponentClass().toString()).getAttributes()) { 141 if (!attributeDefinition.getName().endsWith(KFSPropertyConstants.VERSION_NUMBER) && !attributeDefinition.getName().endsWith(KFSPropertyConstants.OBJECT_ID) && ((propertyLabelRegex == null) || propertyLabelRegex.matcher(attributeDefinition.getLabel().toUpperCase()).matches())) { 142 matchingBusinessObjectProperties.add(new BusinessObjectProperty(businessObjectComponent, attributeDefinition)); 143 } 144 } 145 } 146 147 return matchingBusinessObjectProperties; 148 } 149 150 public List<FunctionalFieldDescription> findFunctionalFieldDescriptions(String namespaceCode, String componentLabel, String propertyLabel, String description, String active) { 151 Set<String> componentClasses = new HashSet<String>(); 152 Set<String> propertyNames = new HashSet<String>(); 153 for (BusinessObjectProperty businessObjectProperty : findBusinessObjectProperties(namespaceCode, componentLabel, propertyLabel)) { 154 componentClasses.add(businessObjectProperty.getComponentClass()); 155 propertyNames.add(businessObjectProperty.getPropertyName()); 156 } 157 Map<String, String> fieldValues = new HashMap<String, String>(); 158 fieldValues.put(KFSPropertyConstants.NAMESPACE_CODE, namespaceCode); 159 fieldValues.put(KFSPropertyConstants.COMPONENT_CLASS, buildOrCriteria(componentClasses)); 160 fieldValues.put(KFSPropertyConstants.PROPERTY_NAME, buildOrCriteria(propertyNames)); 161 fieldValues.put(KFSPropertyConstants.DESCRIPTION, description); 162 fieldValues.put(KFSPropertyConstants.ACTIVE, active); 163 List<FunctionalFieldDescription> searchResults = (List<FunctionalFieldDescription>) lookupService.findCollectionBySearchHelper(FunctionalFieldDescription.class, fieldValues, false); 164 for (FunctionalFieldDescription functionalFieldDescription : searchResults) { 165 functionalFieldDescription.refreshNonUpdateableReferences(); 166 } 167 return searchResults; 168 } 169 170 protected String buildOrCriteria(Set<String> values) { 171 StringBuffer orCriteria = new StringBuffer(); 172 List<String> valueList = new ArrayList<String>(values); 173 for (int i = 0; i < valueList.size(); i++) { 174 orCriteria.append(valueList.get(i)); 175 if (i < (valueList.size() - 1)) { 176 orCriteria.append("|"); 177 } 178 } 179 return orCriteria.toString(); 180 } 181 182 public boolean isMatch(String componentClass, String propertyName, String tableNameSearchCriterion, String fieldNameSearchCriterion) { 183 ClassDescriptor classDescriptor = null; 184 try { 185 classDescriptor = org.apache.ojb.broker.metadata.MetadataManager.getInstance().getGlobalRepository().getDescriptorFor(componentClass); 186 Pattern tableNameRegex = null; 187 if (StringUtils.isNotBlank(tableNameSearchCriterion)) { 188 String patternStr = tableNameSearchCriterion.replace("*", ".*").toUpperCase(); 189 try { 190 tableNameRegex = Pattern.compile(patternStr); 191 } 192 catch (PatternSyntaxException ex) { 193 LOG.error("DataMappingFieldDefinitionLookupableHelperServiceImpl unable to parse tableName pattern, ignoring.", ex); 194 } 195 } 196 Pattern fieldNameRegex = null; 197 if (StringUtils.isNotBlank(fieldNameSearchCriterion)) { 198 String patternStr = fieldNameSearchCriterion.replace("*", ".*").toUpperCase(); 199 try { 200 fieldNameRegex = Pattern.compile(patternStr); 201 } 202 catch (PatternSyntaxException ex) { 203 LOG.error("DataMappingFieldDefinitionLookupableHelperServiceImpl unable to parse fieldName pattern, ignoring.", ex); 204 } 205 } 206 return ((tableNameRegex == null) || tableNameRegex.matcher(classDescriptor.getFullTableName().toUpperCase()).matches()) && ((fieldNameRegex == null) || ((classDescriptor.getFieldDescriptorByName(propertyName) != null) && fieldNameRegex.matcher(classDescriptor.getFieldDescriptorByName(propertyName).getColumnName().toUpperCase()).matches())); 207 } 208 catch (ClassNotPersistenceCapableException e) { 209 return StringUtils.isBlank(tableNameSearchCriterion) && StringUtils.isBlank(fieldNameSearchCriterion); 210 } 211 } 212 213 public String getReferenceComponentLabel(Class componentClass, String propertyName) { 214 BusinessObjectRelationship relationship = null; 215 try { 216 relationship = businessObjectMetaDataService.getBusinessObjectRelationship((BusinessObject) componentClass.newInstance(), propertyName); 217 } 218 catch (Exception e) { 219 LOG.debug("KfsBusinessObjectMetadataServiceImpl unable to instantiate componentClass: " + componentClass, e); 220 } 221 if (relationship != null) { 222 return dataDictionaryService.getDataDictionary().getBusinessObjectEntry(relationship.getRelatedClass().getName()).getObjectLabel(); 223 } 224 return ""; 225 } 226 227 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) { 228 this.dataDictionaryService = dataDictionaryService; 229 } 230 231 public void setBusinessObjectService(BusinessObjectService businessObjectService) { 232 this.businessObjectService = businessObjectService; 233 } 234 235 public void setBusinessObjectMetaDataService(BusinessObjectMetaDataService businessObjectMetaDataService) { 236 this.businessObjectMetaDataService = businessObjectMetaDataService; 237 } 238 239 public void setBusinessObjectMetaDataDao(BusinessObjectMetaDataDao businessObjectMetaDataDao) { 240 this.businessObjectMetaDataDao = businessObjectMetaDataDao; 241 } 242 243 public void setLookupService(LookupService lookupService) { 244 this.lookupService = lookupService; 245 } 246 }