001/** 002 * Copyright 2005-2018 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.krad.messages.providers; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.rice.core.api.exception.RiceRuntimeException; 020import org.kuali.rice.core.api.search.SearchOperator; 021import org.kuali.rice.krad.messages.Message; 022import org.kuali.rice.krad.messages.MessageProvider; 023import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 024import org.kuali.rice.krad.service.LookupService; 025 026import java.util.Collection; 027import java.util.HashMap; 028import java.util.Map; 029 030/** 031 * Implementation of {@link MessageProvider} that stores messages in a database 032 * 033 * @author Kuali Rice Team (rice.collab@kuali.org) 034 */ 035public class DatabaseMessageProvider implements MessageProvider { 036 037 private LookupService lookupService; 038 039 /** 040 * @see org.kuali.rice.krad.messages.MessageProvider#getMessage(java.lang.String, java.lang.String, 041 * java.lang.String, java.lang.String) 042 */ 043 public Message getMessage(String namespace, String component, String key, String locale) { 044 Collection<Message> results = getMessageByCriteria(namespace, component, key, locale); 045 046 if ((results != null) && !results.isEmpty()) { 047 return results.iterator().next(); 048 } 049 050 return null; 051 } 052 053 /** 054 * @see org.kuali.rice.krad.messages.MessageProvider#getAllMessagesForComponent(java.lang.String, 055 * java.lang.String, java.lang.String) 056 */ 057 public Collection<Message> getAllMessagesForComponent(String namespace, String component, String locale) { 058 return getMessageByCriteria(namespace, component, null, locale); 059 } 060 061 /** 062 * Performs a query using the {@link LookupService} to retrieve messages that match the given 063 * namespace, component, name, and locale. Not parameters maybe empty in which case they will not be added 064 * to the criteria 065 * 066 * @param namespace namespace code to search for 067 * @param component component code to search for 068 * @param key key of the parameter to find 069 * @param locale locale code to search for 070 * @return Collection<Message> matching messages or empty collection if not are found 071 */ 072 protected Collection<Message> getMessageByCriteria(String namespace, String component, String key, String locale) { 073 Collection<Message> results = null; 074 075 Map<String, String> criteria = new HashMap<String, String>(); 076 077 if (StringUtils.isNotBlank(namespace)) { 078 criteria.put("namespaceCode", namespace); 079 } 080 081 if (StringUtils.isNotBlank(component)) { 082 criteria.put("componentCode", component); 083 } 084 085 if (StringUtils.isNotBlank(key)) { 086 criteria.put("key", key); 087 } 088 089 if (StringUtils.isNotBlank(locale)) { 090 // build or condition that will match just the language as well 091 String[] localeIdentifiers = StringUtils.split(locale, "-"); 092 if ((localeIdentifiers == null) || (localeIdentifiers.length != 2)) { 093 throw new RiceRuntimeException("Invalid locale code: " + (locale == null ? "Null" : locale)); 094 } 095 096 String localeLanguage = localeIdentifiers[0]; 097 if ( StringUtils.isNotBlank(localeLanguage)) { 098 criteria.put("locale", locale + SearchOperator.OR.op() + localeLanguage); 099 } else { 100 criteria.put("locale", locale ); 101 } 102 } 103 104 results = getLookupService().findCollectionBySearch(Message.class, criteria); 105 106 // filter out duplicate message results due to locale wildcard search (for example could have a match 107 // for en and en-US, in which case we want to take the record for the more specific locale 108 Map<String, Message> uniqueMessages = new HashMap<String, Message>(); 109 for (Message message : results) { 110 String messageKey = message.getNamespaceCode() + "|" + message.getComponentCode() + "|" + message.getKey(); 111 if (uniqueMessages.containsKey(messageKey)) { 112 Message duplicateMessage = uniqueMessages.get(messageKey); 113 // attempt to find the one that matches the locale exactly 114 if (message.getLocale().equals(locale)) { 115 // use current message, otherwise leave the previous message 116 uniqueMessages.put(messageKey, message); 117 } 118 } else { 119 uniqueMessages.put(messageKey, message); 120 } 121 } 122 123 return uniqueMessages.values(); 124 } 125 126 public LookupService getLookupService() { 127 if (lookupService == null) { 128 lookupService = KRADServiceLocatorWeb.getLookupService(); 129 } 130 131 return lookupService; 132 } 133 134 public void setLookupService(LookupService lookupService) { 135 this.lookupService = lookupService; 136 } 137 138}