001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.workplace;
029
030import org.opencms.i18n.A_CmsMessageBundle;
031import org.opencms.i18n.CmsMessages;
032import org.opencms.i18n.CmsMultiMessages;
033import org.opencms.i18n.I_CmsMessageBundle;
034import org.opencms.main.CmsLog;
035import org.opencms.main.OpenCms;
036import org.opencms.util.CmsStringUtil;
037import org.opencms.workplace.explorer.CmsExplorerTypeSettings;
038
039import java.util.ArrayList;
040import java.util.HashSet;
041import java.util.Iterator;
042import java.util.List;
043import java.util.Locale;
044import java.util.ServiceLoader;
045import java.util.Set;
046
047import org.apache.commons.logging.Log;
048
049/**
050 * Provides access to the localized messages for the OpenCms workplace.<p>
051 *
052 * The workplace messages are collected from the workplace resource bundles of all installed modules,
053 * plus all the OpenCms core packages.<p>
054 *
055 * To be recognized as a workplace module resource bundle,
056 * the workplace property file must follow the naming convention <code>${module_package_name}.workplace${locale}.properties</code>,
057 * or <code>${module_package_name}.messages${locale}.properties</code>
058 * for example like <code>com.mycompany.module.workplace_en.properties</code> or
059 * <code>com.mycompany.module.messages_en.properties</code>.<p>
060 *
061 * Workplace messages are cached for faster lookup. If a localized key is contained in more then one module,
062 * it will be used only from the module where it was first found in. The module order is undefined. It is therefore
063 * recommended to ensure the uniqueness of all module keys by placing a special prefix in front of all keys of a module.<p>
064 *
065 * @since 6.0.0
066 */
067public class CmsWorkplaceMessages extends CmsMultiMessages {
068
069    /** The title key prefix used for the "new resource" dialog. */
070    public static final String GUI_NEW_RESOURCE_TITLE_PREFIX = "title.new";
071
072    /** Constant for the <code>".messages"</code> prefix. */
073    public static final String PREFIX_BUNDLE_MESSAGES = ".messages";
074
075    /** Constant for the <code>".workplace"</code> prefix. */
076    public static final String PREFIX_BUNDLE_WORKPLACE = ".workplace";
077
078    /** Constant for the multi bundle name. */
079    public static final String WORKPLACE_BUNDLE_NAME = CmsWorkplaceMessages.class.getName();
080
081    /** The logger for this class. */
082    private static Log LOG = CmsLog.getLog(CmsWorkplaceMessages.class.getName());
083
084    /**
085     * Constructor for creating a new messages object
086     * initialized with the provided locale.<p>
087     *
088     * @param locale the locale to initialize
089     */
090    public CmsWorkplaceMessages(Locale locale) {
091
092        super(locale);
093        setBundleName(WORKPLACE_BUNDLE_NAME);
094        addMessages(collectModuleMessages(locale));
095    }
096
097    /**
098     * Returns the title for the "new resource" dialog.<p>
099     *
100     * It will look up a key with the prefix {@link #GUI_NEW_RESOURCE_TITLE_PREFIX}
101     * and the given name appended (converted to lower case).<p>
102     *
103     * If this key is not found, the value of
104     * {@link org.opencms.workplace.explorer.Messages#GUI_TITLE_NEWFILEOTHER_0} will be returned.<p>
105     *
106     * @param wp an instance of a {@link CmsWorkplace} to resolve the key name with
107     * @param name the type to generate the title for
108     *
109     * @return the title for the "new resource" dialog
110     */
111    public static String getNewResourceTitle(CmsWorkplace wp, String name) {
112
113        // try to find the localized key
114        String title = wp.key(GUI_NEW_RESOURCE_TITLE_PREFIX + name.toLowerCase());
115        if (CmsMessages.isUnknownKey(title)) {
116            // still unknown - use default title
117            title = wp.key(org.opencms.workplace.explorer.Messages.GUI_TITLE_NEWFILEOTHER_0);
118        }
119        return title;
120    }
121
122    /**
123     * Returns the description of the given resource type name.<p>
124     *
125     * If this key is not found, the value of the name input will be returned.<p>
126     *
127     * @param wp an instance of a {@link CmsWorkplace} to resolve the key name with
128     * @param name the resource type name to generate the nice name for
129     *
130     * @return the description of the given resource type name
131     */
132    public static String getResourceTypeDescription(CmsWorkplace wp, String name) {
133
134        // try to find the localized key
135        String key = OpenCms.getWorkplaceManager().getExplorerTypeSetting(name).getInfo();
136        return wp.keyDefault(key, name);
137    }
138
139    /**
140     * Returns the description of the given resource type name.<p>
141     *
142     * If this key is not found, the value of the name input will be returned.<p>
143     *
144     * @param locale the right locale to use
145     * @param name the resource type name to generate the nice name for
146     *
147     * @return the description of the given resource type name
148     */
149    public static String getResourceTypeDescription(Locale locale, String name) {
150
151        CmsExplorerTypeSettings settings = OpenCms.getWorkplaceManager().getExplorerTypeSetting(name);
152        if (settings != null) {
153            // try to find the localized key
154            String key = settings.getInfo();
155            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(key)) {
156                return OpenCms.getWorkplaceManager().getMessages(locale).keyDefault(key, name);
157            }
158        }
159        return "";
160    }
161
162    /**
163     * Returns the localized name of the given resource type name.<p>
164     *
165     * If this key is not found, the value of the name input will be returned.<p>
166     *
167     * @param wp an instance of a {@link CmsWorkplace} to resolve the key name with
168     * @param name the resource type name to generate the nice name for
169     *
170     * @return the localized name of the given resource type name
171     */
172    public static String getResourceTypeName(CmsWorkplace wp, String name) {
173
174        // try to find the localized key
175        CmsExplorerTypeSettings typeSettings = OpenCms.getWorkplaceManager().getExplorerTypeSetting(name);
176        if (typeSettings == null) {
177            return name;
178        }
179        String key = typeSettings.getKey();
180        return wp.keyDefault(key, name);
181    }
182
183    /**
184     * Returns the localized name of the given resource type name.<p>
185     *
186     * If this key is not found, the value of the name input will be returned.<p>
187     *
188     * @param locale the right locale to use
189     * @param name the resource type name to generate the nice name for
190     *
191     * @return the localized name of the given resource type name
192     */
193    public static String getResourceTypeName(Locale locale, String name) {
194
195        // try to find the localized key
196        CmsExplorerTypeSettings typeSettings = OpenCms.getWorkplaceManager().getExplorerTypeSetting(name);
197        if (typeSettings == null) {
198            return name;
199        }
200        String key = typeSettings.getKey();
201        return OpenCms.getWorkplaceManager().getMessages(locale).keyDefault(key, name);
202    }
203
204    /**
205     * Gathers all localization files for the workplace from the different modules.<p>
206     *
207     * For a module named "my.module.name" the locale file must be named
208     * "my.module.name.workplace" or "my.module.name.messages" and
209     * be located in the classpath so that the resource loader can find it.<p>
210     *
211     * @param locale the selected locale
212     *
213     * @return an initialized set of module messages
214     */
215    private static List<CmsMessages> collectModuleMessages(Locale locale) {
216
217        // create a new list and add the base bundle
218        ArrayList<CmsMessages> result = new ArrayList<CmsMessages>();
219
220        //////////// iterate over all registered modules ////////////////
221        Set<String> names = new HashSet<String>();
222        Set<String> modules = OpenCms.getModuleManager().getModuleNames();
223        if (modules != null) {
224            names.addAll(modules);
225        }
226        // use service loader to get additional bundle names
227        Iterator<I_CmsWorkplaceMessageBundleProvider> providers = ServiceLoader.load(
228            I_CmsWorkplaceMessageBundleProvider.class).iterator();
229        while (providers.hasNext()) {
230            try {
231                I_CmsWorkplaceMessageBundleProvider provider = providers.next();
232                names.addAll(provider.getMessageBundleNames());
233            } catch (Throwable t) {
234                LOG.error("Error loading workplace messages bundle names from classpath.", t);
235            }
236        }
237
238        // iterate all module names
239        for (String baseName : names) {
240            //////////// collect the workplace.properties ////////////////
241            // this should result in a name like "my.module.name.workplace"
242            String bundleName = baseName + PREFIX_BUNDLE_WORKPLACE;
243            // try to load a bundle with the module names
244            CmsMessages msg = new CmsMessages(bundleName, locale);
245            // bundle was loaded, add to list of bundles
246            if (msg.isInitialized()) {
247                result.add(msg);
248            }
249            //////////// collect the messages.properties ////////////////
250            // this should result in a name like "my.module.name.messages"
251            bundleName = baseName + PREFIX_BUNDLE_MESSAGES;
252            // try to load a bundle with the module names
253            msg = new CmsMessages(bundleName, locale);
254            // bundle was loaded, add to list of bundles
255            if (msg.isInitialized()) {
256                result.add(msg);
257            }
258        }
259
260        //////////// collect additional core packages ////////////////
261        I_CmsMessageBundle[] coreMsgs = A_CmsMessageBundle.getOpenCmsMessageBundles();
262        for (int i = 0; i < coreMsgs.length; i++) {
263            I_CmsMessageBundle bundle = coreMsgs[i];
264            result.add(bundle.getBundle(locale));
265        }
266
267        /////////// collect bundles configured in module configurations ////////
268        if (OpenCms.getADEManager().isInitialized()) {
269            Set<String> bundleNames = OpenCms.getADEManager().getConfiguredWorkplaceBundles();
270            for (String bundleName : bundleNames) {
271                CmsMessages msg = new CmsMessages(bundleName, locale);
272                if (msg.isInitialized()) {
273                    result.add(msg);
274                }
275            }
276        }
277        return result;
278    }
279
280    /**
281     * @see java.lang.Object#equals(java.lang.Object)
282     */
283    @Override
284    public boolean equals(Object obj) {
285
286        if (obj == this) {
287            return true;
288        }
289        if (obj instanceof CmsWorkplaceMessages) {
290            // workplace messages are equal if the locale is equal (since all bundles are the same)
291            CmsMessages other = (CmsMessages)obj;
292            return other.getLocale().equals(getLocale());
293        }
294        return false;
295    }
296
297    /**
298     * @see org.opencms.i18n.CmsMessages#hashCode()
299     */
300    @Override
301    public int hashCode() {
302
303        return getLocale().hashCode();
304    }
305}