001/**
002 * Copyright 2005-2017 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.kew.util;
017
018import org.apache.commons.lang.StringUtils;
019import org.apache.log4j.Logger;
020import org.kuali.rice.kew.doctype.DocumentTypePolicy;
021import org.kuali.rice.kew.doctype.bo.DocumentType;
022import org.kuali.rice.kew.doctype.service.DocumentTypeService;
023
024import java.util.HashMap;
025import java.util.Map;
026import java.util.concurrent.ConcurrentHashMap;
027
028/**
029 * A simple utility class which can parse a target specification for a set of defined Document Types.
030 *
031 * @author Eric Westfall
032 */
033public class DocumentTypeWindowTargets {
034
035    private static final Logger LOG = Logger.getLogger(DocumentTypeWindowTargets.class);
036    private static final String DEFAULT_KEY = "*";
037
038    private final Map<String, String> documentTargetMappings;
039    private final Map<String, String> routeLogTargetMappings;
040    private final DocumentTypeService documentTypeService;
041
042    private final String defaultDocumentTarget;
043    private final String defaultRouteLogTarget;
044
045    private final Map<String, String> documentTargetCache = new ConcurrentHashMap<>();
046    private final Map<String, String> routeLogTargetCache = new ConcurrentHashMap<>();
047
048    public DocumentTypeWindowTargets(String documentTargetSpec, String routeLogTargetSpec, String defaultDocumentTarget, String defaultRouteLogTarget, DocumentTypeService documentTypeService) {
049        if (StringUtils.isBlank(defaultDocumentTarget)) {
050            throw new IllegalArgumentException("defaultDocumentTarget must not be blank");
051        }
052        if (StringUtils.isBlank(defaultRouteLogTarget)) {
053            throw new IllegalArgumentException("defaultRouteLogTarget must not be blank");
054        }
055        if (documentTypeService == null) {
056            throw new IllegalArgumentException("documentTypeService must not be nulll");
057        }
058        this.documentTargetMappings = new HashMap<>();
059        this.routeLogTargetMappings = new HashMap<>();
060        this.documentTypeService = documentTypeService;
061        this.defaultDocumentTarget = defaultDocumentTarget;
062        this.defaultRouteLogTarget = defaultRouteLogTarget;
063
064        parseTargetSpec(documentTargetSpec, this.documentTargetMappings);
065        parseTargetSpec(routeLogTargetSpec, this.routeLogTargetMappings);
066    }
067
068    private void parseTargetSpec(String targetSpec, Map<String, String> targetMappings) {
069        if (!StringUtils.isBlank(targetSpec)) {
070            String[] entries = targetSpec.split(",");
071            for (String entry : entries) {
072                String[] docTypeTarget = entry.split(":");
073                if (docTypeTarget.length != 2) {
074                    LOG.warn("Encountered an invalid entry in target spec, ignoring: " + entry);
075                } else {
076                    targetMappings.put(docTypeTarget[0], docTypeTarget[1]);
077                }
078            }
079        }
080    }
081
082    public String getDocumentTarget(String documentTypeName) {
083        return getTargetInternal(documentTypeName, false, 0);
084    }
085
086    public String getRouteLogTarget(String documentTypeName) {
087        return getTargetInternal(documentTypeName, true, 0);
088    }
089
090    private String getTargetInternal(String documentTypeName, boolean isRouteLog, int depth) {
091        if (StringUtils.isBlank(documentTypeName)) {
092            throw new IllegalArgumentException("Document type name must not be blank");
093        }
094        Map<String, String> targetCache = isRouteLog ? routeLogTargetCache : documentTargetCache;
095        if (!targetCache.containsKey(documentTypeName)) {
096            Map<String, String> targetMappings = isRouteLog ? routeLogTargetMappings : documentTargetMappings;
097            String target = targetMappings.get(documentTypeName);
098            if (target == null) {
099                // first if we are at depth 0, check if the doc type has a policy on it
100                if (depth == 0) {
101                    DocumentType documentType = documentTypeService.findByName(documentTypeName);
102                    if (documentType != null) {
103                        DocumentTypePolicy docSearchTarget = documentType.getDocSearchTarget();
104                        if (docSearchTarget.getPolicyStringValue() != null) {
105                            target = docSearchTarget.getPolicyStringValue();
106                        }
107                    }
108                }
109            }
110            // if there was no policy, check the parent document type if there is one
111            if (target == null) {
112                String parentDocumentTypeName = documentTypeService.findParentNameByName(documentTypeName);
113                if (parentDocumentTypeName != null) {
114                    target = getTargetInternal(parentDocumentTypeName, isRouteLog, depth + 1);
115                }
116            }
117            // fall back to the defaults if no other target can be determined
118            if (target == null) {
119                target = targetMappings.get(DEFAULT_KEY);
120                if (target == null) {
121                    target = isRouteLog ? defaultRouteLogTarget : defaultDocumentTarget;
122                }
123            }
124            targetCache.put(documentTypeName, target);
125        }
126        return targetCache.get(documentTypeName);
127    }
128
129}