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 }