001// Copyright 2006-2013 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007// http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry5.internal.services;
016
017import org.apache.tapestry5.SymbolConstants;
018import org.apache.tapestry5.ioc.Messages;
019import org.apache.tapestry5.ioc.Resource;
020import org.apache.tapestry5.ioc.annotations.PostInjection;
021import org.apache.tapestry5.ioc.annotations.Symbol;
022import org.apache.tapestry5.ioc.internal.util.URLChangeTracker;
023import org.apache.tapestry5.ioc.services.ClasspathURLConverter;
024import org.apache.tapestry5.model.ComponentModel;
025import org.apache.tapestry5.services.InvalidationEventHub;
026import org.apache.tapestry5.services.UpdateListener;
027import org.apache.tapestry5.services.messages.ComponentMessagesSource;
028import org.apache.tapestry5.services.messages.PropertiesFileParser;
029import org.apache.tapestry5.services.pageload.ComponentResourceLocator;
030import org.apache.tapestry5.services.pageload.ComponentResourceSelector;
031
032import java.util.Arrays;
033import java.util.List;
034import java.util.Locale;
035
036public class ComponentMessagesSourceImpl implements ComponentMessagesSource, UpdateListener
037{
038    private final MessagesSourceImpl messagesSource;
039
040    private final MessagesBundle appCatalogBundle;
041
042    private class ComponentModelBundle implements MessagesBundle
043    {
044        private final ComponentModel model;
045
046        public ComponentModelBundle(ComponentModel model)
047        {
048            this.model = model;
049        }
050
051        public Resource getBaseResource()
052        {
053            return model.getBaseResource();
054        }
055
056        public Object getId()
057        {
058            return model.getComponentClassName();
059        }
060
061        public MessagesBundle getParent()
062        {
063            ComponentModel parentModel = model.getParentModel();
064
065            if (parentModel == null)
066                return appCatalogBundle;
067
068            return new ComponentModelBundle(parentModel);
069        }
070    }
071
072    public ComponentMessagesSourceImpl(@Symbol(SymbolConstants.PRODUCTION_MODE)
073                                       boolean productionMode, List<Resource> appCatalogResources, PropertiesFileParser parser,
074                                       ComponentResourceLocator resourceLocator, ClasspathURLConverter classpathURLConverter)
075    {
076        this(productionMode, appCatalogResources, resourceLocator, parser, new URLChangeTracker(classpathURLConverter));
077    }
078
079    ComponentMessagesSourceImpl(boolean productionMode, Resource appCatalogResource,
080                                ComponentResourceLocator resourceLocator, PropertiesFileParser parser, URLChangeTracker tracker)
081    {
082        this(productionMode, Arrays.asList(appCatalogResource), resourceLocator, parser, tracker);
083    }
084
085    ComponentMessagesSourceImpl(boolean productionMode, List<Resource> appCatalogResources,
086                                ComponentResourceLocator resourceLocator, PropertiesFileParser parser, URLChangeTracker tracker)
087    {
088        messagesSource = new MessagesSourceImpl(productionMode, productionMode ? null : tracker, resourceLocator,
089                parser);
090
091        appCatalogBundle = createAppCatalogBundle(appCatalogResources);
092    }
093
094    @PostInjection
095    public void setupReload(ReloadHelper reloadHelper)
096    {
097        reloadHelper.addReloadCallback(new Runnable()
098        {
099            public void run()
100            {
101                messagesSource.invalidate();
102            }
103        });
104    }
105
106    public void checkForUpdates()
107    {
108        messagesSource.checkForUpdates();
109    }
110
111    public Messages getMessages(ComponentModel componentModel, Locale locale)
112    {
113        return getMessages(componentModel, new ComponentResourceSelector(locale));
114    }
115
116    public Messages getMessages(ComponentModel componentModel, ComponentResourceSelector selector)
117    {
118        MessagesBundle bundle = new ComponentModelBundle(componentModel);
119
120        return messagesSource.getMessages(bundle, selector);
121    }
122
123    public Messages getApplicationCatalog(Locale locale)
124    {
125        return messagesSource.getMessages(appCatalogBundle, new ComponentResourceSelector(locale));
126    }
127
128    private MessagesBundle createAppCatalogBundle(List<Resource> resources)
129    {
130        MessagesBundle current = null;
131
132        for (Resource r : resources)
133        {
134            current = createMessagesBundle(r, current);
135        }
136
137        return current;
138    }
139
140    private MessagesBundle createMessagesBundle(final Resource resource, final MessagesBundle parent)
141    {
142        return new MessagesBundle()
143        {
144            public Resource getBaseResource()
145            {
146                return resource;
147            }
148
149            public Object getId()
150            {
151                return resource.getPath();
152            }
153
154            public MessagesBundle getParent()
155            {
156                return parent;
157            }
158        };
159    }
160
161    public InvalidationEventHub getInvalidationEventHub()
162    {
163        return messagesSource;
164    }
165}