001    /**
002     * Copyright 2005-2013 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.kuali.rice.core.api.mo.common.active.MutableInactivatable;
020    import org.kuali.rice.krad.bo.BusinessObject;
021    import org.kuali.rice.krad.bo.DataObjectRelationship;
022    import org.kuali.rice.krad.datadictionary.InactivationBlockingMetadata;
023    import org.kuali.rice.krad.service.BusinessObjectService;
024    import org.kuali.rice.krad.service.DataObjectMetaDataService;
025    import org.kuali.rice.krad.service.InactivationBlockingDetectionService;
026    import org.kuali.rice.krad.util.ObjectUtils;
027    import org.springframework.transaction.annotation.Transactional;
028    
029    import java.util.ArrayList;
030    import java.util.Collection;
031    import java.util.HashMap;
032    import java.util.Iterator;
033    import java.util.Map;
034    
035    /**
036     * Performs checking of inactivation blocking 
037     * 
038     * @author Kuali Rice Team (rice.collab@kuali.org)
039     */
040    @Transactional
041    public class InactivationBlockingDetectionServiceImpl implements InactivationBlockingDetectionService {
042        private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(InactivationBlockingDetectionServiceImpl.class);
043    
044        protected DataObjectMetaDataService dataObjectMetaDataService;
045        protected BusinessObjectService businessObjectService;
046        
047        /**
048         * Note we are checking the active getting after retrieving potential blocking records instead of setting criteria on the
049             * active field. This is because some implementations of {@link org.kuali.rice.core.api.mo.common.active.MutableInactivatable} might not have the active field, for example
050             * instances of {@link org.kuali.rice.krad.bo.InactivatableFromTo}
051             * 
052         * @see org.kuali.rice.krad.service.InactivationBlockingDetectionService#listAllBlockerRecords(org.kuali.rice.krad.datadictionary.InactivationBlockingDefinition)
053         * @see org.kuali.rice.core.api.mo.common.active.MutableInactivatable
054         */
055        @SuppressWarnings("unchecked")
056            public Collection<BusinessObject> listAllBlockerRecords(BusinessObject blockedBo, InactivationBlockingMetadata inactivationBlockingMetadata) {
057                    Collection<BusinessObject> blockingRecords = new ArrayList<BusinessObject>();
058    
059                    Map<String, String> queryMap = buildInactivationBlockerQueryMap(blockedBo, inactivationBlockingMetadata);
060                    if (LOG.isDebugEnabled()) {
061                            LOG.debug("Checking for blocker records for object: " + blockedBo);
062                            LOG.debug("    With Metadata: " + inactivationBlockingMetadata);
063                            LOG.debug("    Resulting Query Map: " + queryMap);
064                    }
065    
066                    if (queryMap != null) {
067                            Collection potentialBlockingRecords = businessObjectService.findMatching(
068                                            inactivationBlockingMetadata.getBlockingReferenceBusinessObjectClass(), queryMap);
069                            for (Iterator iterator = potentialBlockingRecords.iterator(); iterator.hasNext();) {
070                                    MutableInactivatable businessObject = (MutableInactivatable) iterator.next();
071                                    if (businessObject.isActive()) {
072                                            blockingRecords.add((BusinessObject) businessObject);
073                                    }
074                            }
075                    }
076    
077                    return blockingRecords;
078            }
079    
080            /**
081             * Note we are checking the active getting after retrieving potential blocking records instead of setting criteria on the
082             * active field. This is because some implementations of {@link org.kuali.rice.core.api.mo.common.active.MutableInactivatable} might not have the active field, for example
083             * instances of {@link org.kuali.rice.krad.bo.InactivatableFromTo}
084             * 
085             * @see org.kuali.rice.krad.service.InactivationBlockingDetectionService#hasABlockingRecord(org.kuali.rice.krad.bo.BusinessObject,
086             *      org.kuali.rice.krad.datadictionary.InactivationBlockingMetadata)
087             * @see org.kuali.rice.core.api.mo.common.active.MutableInactivatable
088             */
089            public boolean hasABlockingRecord(BusinessObject blockedBo, InactivationBlockingMetadata inactivationBlockingMetadata) {
090                    boolean hasBlockingRecord = false;
091    
092                    Map<String, String> queryMap = buildInactivationBlockerQueryMap(blockedBo, inactivationBlockingMetadata);
093                    if (queryMap != null) {
094                            Collection potentialBlockingRecords = businessObjectService.findMatching(
095                                            inactivationBlockingMetadata.getBlockingReferenceBusinessObjectClass(), queryMap);
096                            for (Iterator iterator = potentialBlockingRecords.iterator(); iterator.hasNext();) {
097                                    MutableInactivatable businessObject = (MutableInactivatable) iterator.next();
098                                    if (businessObject.isActive()) {
099                                            hasBlockingRecord = true;
100                                            break;
101                                    }
102                            }
103                    }
104    
105                    // if queryMap were null, means that we couldn't perform a query, and hence, need to return false
106                    return hasBlockingRecord;
107            }
108    
109            protected Map<String, String> buildInactivationBlockerQueryMap(BusinessObject blockedBo, InactivationBlockingMetadata inactivationBlockingMetadata) {
110                    BusinessObject blockingBo = (BusinessObject) ObjectUtils.createNewObjectFromClass(inactivationBlockingMetadata
111                                    .getBlockingReferenceBusinessObjectClass());
112    
113                    DataObjectRelationship dataObjectRelationship = dataObjectMetaDataService
114                                    .getDataObjectRelationship(blockingBo, blockedBo.getClass(),
115                            inactivationBlockingMetadata.getBlockedReferencePropertyName(), "", true, false, false);
116    
117                    // note, this method assumes that all PK fields of the blockedBo have a non-null and, for strings, non-blank values
118                    if (dataObjectRelationship != null) {
119                            Map<String, String> parentToChildReferences = dataObjectRelationship.getParentToChildReferences();
120                            Map<String, String> queryMap = new HashMap<String, String>();
121                            for (Map.Entry<String, String> parentToChildReference : parentToChildReferences.entrySet()) {
122                                    String fieldName = parentToChildReference.getKey();
123                                    Object fieldValue = ObjectUtils.getPropertyValue(blockedBo, parentToChildReference.getValue());
124                                    if (fieldValue != null && StringUtils.isNotBlank(fieldValue.toString())) {
125                                            queryMap.put(fieldName, fieldValue.toString());
126                                    } else {
127                                            LOG.error("Found null value for foreign key field " + fieldName
128                                                            + " while building inactivation blocking query map.");
129                                            throw new RuntimeException("Found null value for foreign key field '" + fieldName
130                                                            + "' while building inactivation blocking query map.");
131                                    }
132                            }
133    
134                            return queryMap;
135                    }
136    
137                    return null;
138            }
139        
140        public void setDataObjectMetaDataService(DataObjectMetaDataService dataObjectMetaDataService) {
141            this.dataObjectMetaDataService = dataObjectMetaDataService;
142        }
143    
144        public void setBusinessObjectService(BusinessObjectService businessObjectService) {
145            this.businessObjectService = businessObjectService;
146        }
147    
148    }