001    /**
002     * Copyright 2005-2014 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.messages;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
020    import org.kuali.rice.krad.util.KRADConstants;
021    
022    import java.util.ArrayList;
023    import java.util.Collection;
024    import java.util.List;
025    
026    /**
027     * Implementation of the {@link MessageService} that allows {@link MessageProvider} implementations
028     * to be configured for exposing external message repositories
029     *
030     * <p>
031     * This message service implementation essentially delegates all calls down to one or more message
032     * providers. When more than one message provider is configured, providers higher up in the chain will
033     * receive priority. That is, when finding a message the first provider that has the message will be used
034     * and no others will be consulted. When finding a collection of messages, if the same message (key) exists
035     * from more than one provider, the message from the first encountered provider (in the List) will
036     * be used.
037     * </p>
038     *
039     * <p>
040     * The default namespace and component are constants of the service implementation and may not be changed.
041     * </p>
042     *
043     * @author Kuali Rice Team (rice.collab@kuali.org)
044     */
045    public class MessageServiceImpl implements MessageService {
046        private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(MessageServiceImpl.class);
047    
048        private List<MessageProvider> messageProviders;
049    
050        /**
051         * @see MessageService#getMessage(java.lang.String, java.lang.String, java.lang.String)
052         */
053        public Message getMessage(String namespace, String component, String key) {
054            return getMessage(namespace, component, key, getDefaultLocaleCode());
055        }
056    
057        /**
058         * @see MessageService#getMessage(java.lang.String, java.lang.String, java.lang.String)
059         */
060        public Message getMessage(String namespace, String component, String key, String locale) {
061            Message message = null;
062    
063            // use default namespace and component if not given
064            if (StringUtils.isBlank(namespace)) {
065                namespace = DEFAULT_NAMESPACE_CODE;
066            }
067    
068            if (StringUtils.isBlank(component)) {
069                component = DEFAULT_COMPONENT_CODE;
070            }
071    
072            if (StringUtils.isBlank(locale)) {
073                locale = getDefaultLocaleCode();
074            }
075    
076            for (MessageProvider provider : messageProviders) {
077                message = provider.getMessage(namespace, component, key, locale);
078    
079                if (message != null) {
080                    // don't check with any additional providers
081                    break;
082                }
083            }
084    
085            return message;
086        }
087    
088        /**
089         * @see MessageService#getMessageText(java.lang.String, java.lang.String, java.lang.String)
090         */
091        public String getMessageText(String namespace, String component, String key) {
092            return getMessageText(namespace, component, key, getDefaultLocaleCode());
093        }
094    
095        /**
096         * @see MessageService#getMessageText(java.lang.String, java.lang.String, java.lang.String)
097         */
098        public String getMessageText(String namespace, String component, String key, String locale) {
099            Message message = getMessage(namespace, component, key, locale);
100            if (message != null) {
101                return message.getText();
102            }
103    
104            return null;
105        }
106    
107        /**
108         * @see MessageService#getMessageText(java.lang.String, java.lang.String, java.lang.String)
109         */
110        public String getMessageText(String key) {
111            return getMessageText(key, getDefaultLocaleCode());
112        }
113    
114        /**
115         * @see MessageService#getMessageText(java.lang.String, java.lang.String, java.lang.String)
116         */
117        public String getMessageText(String key, String locale) {
118            Message message = getMessage(null, null, key, locale);
119            if (message != null) {
120                return message.getText();
121            }
122    
123            return null;
124        }
125    
126        /**
127         * @see MessageService#getAllMessagesForComponent(java.lang.String, java.lang.String)
128         */
129        public Collection<Message> getAllMessagesForComponent(String namespace, String component) {
130            return getAllMessagesForComponent(namespace, component, getDefaultLocaleCode());
131        }
132    
133        /**
134         * @see MessageService#getAllMessagesForComponent(java.lang.String, java.lang.String)
135         */
136        public Collection<Message> getAllMessagesForComponent(String namespace, String component, String locale) {
137            Collection<Message> messages = new ArrayList<Message>();
138    
139            if (StringUtils.isBlank(locale)) {
140                locale = getDefaultLocaleCode();
141            }
142    
143            for (MessageProvider provider : messageProviders) {
144                Collection<Message> providerMessages = provider.getAllMessagesForComponent(namespace, component, locale);
145                mergeMessages(messages, providerMessages);
146            }
147    
148            return messages;
149        }
150    
151        /**
152         * Merges the second collection into the first collection
153         *
154         * <p>
155         * If a message with the same key (namespace, component, and name) is found in both collections, the message
156         * from first collection will remain. That is, the message in the second collection will NOT override
157         * </p>
158         *
159         * @param messages collection to be merged into
160         * @param messagesToMerge collection that will be merged with first
161         */
162        protected void mergeMessages(Collection<Message> messages, Collection<Message> messagesToMerge) {
163            for (Message message : messagesToMerge) {
164                if (!messages.contains(message)) {
165                    messages.add(message);
166                }
167            }
168        }
169    
170        /**
171         * Retrieves the default locale code configured through a system parameter
172         *
173         * @return String configured default locale
174         */
175        protected String getDefaultLocaleCode() {
176            String localeCode = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(
177                    KRADConstants.KNS_NAMESPACE, KRADConstants.DetailTypes.ALL_DETAIL_TYPE,
178                    KRADConstants.ParameterNames.DEFAULT_LOCALE_CODE);
179    
180            // if not configured fall back to english US
181            if (StringUtils.isBlank(localeCode)) {
182                localeCode = "en-US";
183            }
184    
185            return localeCode;
186        }
187    
188        /**
189         * Retrieves the collection of message providers configured with the message service
190         *
191         * @return List<MessageProvider> message provider implementations
192         */
193        protected List<MessageProvider> getMessageProviders() {
194            return messageProviders;
195        }
196    
197        /**
198         * Setter for the collection of message providers that should be used by the message service
199         * implementation
200         *
201         * @param messageProviders
202         */
203        public void setMessageProviders(List<MessageProvider> messageProviders) {
204            this.messageProviders = messageProviders;
205        }
206    }