001/**
002 * Copyright 2005-2016 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> targetMappings;
039    private final DocumentTypeService documentTypeService;
040
041    private final String defaultDocumentTarget;
042    private final String defaultRouteLogTarget;
043
044    private final Map<String, String> documentTargetCache = new ConcurrentHashMap<>();
045    private final Map<String, String> routeLogTargetCache = new ConcurrentHashMap<>();
046
047    public DocumentTypeWindowTargets(String targetSpec, String defaultDocumentTarget, String defaultRouteLogTarget, DocumentTypeService documentTypeService) {
048        if (StringUtils.isBlank(defaultDocumentTarget)) {
049            throw new IllegalArgumentException("defaultDocumentTarget must not be blank");
050        }
051        if (StringUtils.isBlank(defaultRouteLogTarget)) {
052            throw new IllegalArgumentException("defaultRouteLogTarget must not be blank");
053        }
054        if (documentTypeService == null) {
055            throw new IllegalArgumentException("documentTypeService must not be nulll");
056        }
057        this.targetMappings = new HashMap<>();
058        this.documentTypeService = documentTypeService;
059        this.defaultDocumentTarget = defaultDocumentTarget;
060        this.defaultRouteLogTarget = defaultRouteLogTarget;
061
062        parseTargetSpec(targetSpec);
063    }
064
065    private void parseTargetSpec(String targetSpec) {
066        if (!StringUtils.isBlank(targetSpec)) {
067            String[] entries = targetSpec.split(",");
068            for (String entry : entries) {
069                String[] docTypeTarget = entry.split(":");
070                if (docTypeTarget.length != 2) {
071                    LOG.warn("Encountered an invalid entry in target spec, ignoring: " + entry);
072                } else {
073                    targetMappings.put(docTypeTarget[0], docTypeTarget[1]);
074                }
075            }
076        }
077    }
078
079    public String getDocumentTarget(String documentTypeName) {
080        return getTargetInternal(documentTypeName, false, 0);
081    }
082
083    public String getRouteLogTarget(String documentTypeName) {
084        return getTargetInternal(documentTypeName, true, 0);
085    }
086
087    private String getTargetInternal(String documentTypeName, boolean isRouteLog, int depth) {
088        if (StringUtils.isBlank(documentTypeName)) {
089            throw new IllegalArgumentException("Document type name must not be blank");
090        }
091        Map<String, String> targetCache = isRouteLog ? routeLogTargetCache : documentTargetCache;
092        if (!targetCache.containsKey(documentTypeName)) {
093            String target = targetMappings.get(documentTypeName);
094            if (target == null) {
095                // first if we are at depth 0, check if the doc type has a policy on it
096                if (depth == 0) {
097                    DocumentType documentType = documentTypeService.findByName(documentTypeName);
098                    if (documentType != null) {
099                        DocumentTypePolicy docSearchTarget = documentType.getDocSearchTarget();
100                        if (docSearchTarget.getPolicyStringValue() != null) {
101                            target = docSearchTarget.getPolicyStringValue();
102                        }
103                    }
104                }
105            }
106            // if there was no policy, check the parent document type if there is one
107            if (target == null) {
108                String parentDocumentTypeName = documentTypeService.findParentNameByName(documentTypeName);
109                if (parentDocumentTypeName != null) {
110                    target = getTargetInternal(parentDocumentTypeName, isRouteLog, depth + 1);
111                }
112            }
113            // fall back to the defaults if no other target can be determined
114            if (target == null) {
115                target = targetMappings.get(DEFAULT_KEY);
116                if (target == null) {
117                    target = isRouteLog ? defaultRouteLogTarget : defaultDocumentTarget;
118                }
119            }
120            targetCache.put(documentTypeName, target);
121        }
122        return targetCache.get(documentTypeName);
123    }
124
125}