fr.gouv.culture.thesaurus.util.template.ThesaurusSorter.java Source code

Java tutorial

Introduction

Here is the source code for fr.gouv.culture.thesaurus.util.template.ThesaurusSorter.java

Source

/*
* This software is governed by the CeCILL-B license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/or redistribute the software under the terms of the CeCILL-B
* license as circulated by CEA, CNRS and INRIA at the following URL
* "http://www.cecill.info".
*
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided only
* with a limited warranty and the software's author, the holder of the
* economic rights, and the successive licensors have only limited
* liability.
*
* In this respect, the user's attention is drawn to the risks associated
* with loading, using, modifying and/or developing or reproducing the
* software by the user in light of its specific status of free software,
* that may mean that it is complicated to manipulate, and that also
* therefore means that it is reserved for developers and experienced
* professionals having in-depth computer knowledge. Users are therefore
* encouraged to load and test the software's suitability as regards their
* requirements in conditions enabling the security of their systems and/or
* data to be ensured and, more generally, to use and operate it in the
* same conditions as regards security.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-B license and that you accept its terms.
*/

package fr.gouv.culture.thesaurus.util.template;

import java.text.Collator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.collections.map.LRUMap;

import fr.gouv.culture.thesaurus.service.rdf.Entry;
import fr.gouv.culture.thesaurus.service.rdf.LocalizedString;
import fr.gouv.culture.thesaurus.util.LangUtils;

/**
 * Classe utilitaire pour Apache Velocity permettant de trier des objets de
 * Thsaurus W, notamment les chanes de caractres rgionalises.
 * <p>
 * Cette implmentation diffre du trieur de valeurs par dfaut de Velocity car
 * il permet de trier les objets complexes que sont les chanes de caractres
 * rgionalises, en prenant en compte diffrents aspects tels que :
 * <ul>
 * <li>Le tri par rapport  la langue, en prenant en compte des langues
 * prioritaires</li>
 * <li>La prise en compte des parties numriques des libells</li>
 * </ul>
 * 
 * @author tle
 */
public final class ThesaurusSorter {

    /**
     * Locales dj chargs.
     */
    @SuppressWarnings("unchecked")
    private final Map<String, Locale> locales = new LRUMap();

    /**
     * Tri des ressources par leur libell.
     * 
     * @param entries
     *            Ressources  trier par libell (ou <code>null</code>)
     * @param prioritizedLanguages
     *            Langues prioritaires (la valeur <code>null</code> reprsente
     *            la langue neutre)
     * @return Ressources tries par libell, ou <code>null</code> si la liste
     *         des ressources en entre est <code>null</code>
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public Collection sortEntriesByLabel(final Collection entries, final List prioritizedLanguages) {
        return sortEntriesByLabel(entries, (Locale[]) prioritizedLanguages.toArray(new Locale[0]));
    }

    /**
     * Tri des ressources par leur libell.
     * 
     * @param entries
     *            Ressources  trier par libell (ou <code>null</code>)
     * @param prioritizedLanguages
     *            Langues prioritaires (la valeur <code>null</code> reprsente
     *            la langue neutre)
     * @return Ressources tries par libell, ou <code>null</code> si la liste
     *         des ressources en entre est <code>null</code>
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public Collection sortEntriesByLabel(final Collection entries, final List prioritizedLanguages,
            final boolean prioritized) {
        return sortEntriesByLabel(entries, (Locale[]) prioritizedLanguages.toArray(new Locale[0]), prioritized);
    }

    /**
     * Tri des ressources par leur libell. Les valeurs <code>null</code> sont
     * conserves et mises en tte de la collection.
     * 
     * @param entries
     *            Ressources  trier par libell (ou <code>null</code>)
     * @param prioritizedLanguages
     *            Langues prioritaires (la valeur <code>null</code> reprsente
     *            la langue neutre)
     * @return Ressources tries par libell, ou <code>null</code> si la liste
     *         des ressources en entre est <code>null</code>
     */
    public <T extends Entry> Collection<T> sortEntriesByLabel(final Collection<T> entries,
            final Locale[] prioritizedLanguages) {
        return sortEntriesByLabel(entries, prioritizedLanguages, true);
    }

    /**
     * Tri des ressources par leur libell. Les valeurs <code>null</code> sont
     * conserves et mises en tte de la collection.
     * 
     * @param entries
     *            Ressources  trier par libell (ou <code>null</code>)
     * @param prioritizedLanguages
     *            Langues prioritaires (la valeur <code>null</code> reprsente
     *            la langue neutre)
     * @return Ressources tries par libell, ou <code>null</code> si la liste
     *         des ressources en entre est <code>null</code>
     */
    public <T extends Entry> Collection<T> sortEntriesByLabel(final Collection<T> entries,
            final Locale[] prioritizedLanguages, final boolean prioritized) {
        Collection<T> sortedEntries;

        if (entries == null) {
            sortedEntries = null;
        } else {
            int nullEntries = 0;
            final List<SortItemWrapper<T>> wrappers = new ArrayList<SortItemWrapper<T>>(entries.size());
            final Iterator<T> iterator = entries.iterator();

            while (iterator.hasNext()) {
                final T entry = iterator.next();

                if (entry == null) {
                    nullEntries++;
                } else {
                    final LocalizedString label = getEntryLabel(entry, prioritizedLanguages);
                    final String language = label.getLanguage();

                    final Collator collator = language == null ? null : Collator.getInstance(getLocale(language));

                    wrappers.add(new SortItemWrapper<T>(entry, label, collator,
                            prioritized ? LangUtils.convertLocalesToString(LangUtils.expand(prioritizedLanguages))
                                    : null));
                }
            }

            Collections.sort(wrappers);

            sortedEntries = new ArrayList<T>(wrappers.size() + nullEntries);
            while (nullEntries-- > 0) {
                sortedEntries.add(null);
            }
            for (final SortItemWrapper<T> wrapper : wrappers) {
                sortedEntries.add(wrapper.getData());
            }
        }

        return sortedEntries;
    }

    /**
     * Tri les chanes rgionalises par langue, puis par libell.
     * 
     * @param strings
     *            Chanes rgionalises  trier (ou <code>null</code>)
     * @param prioritizedLanguages
     *            Langues prioritaires (la valeur <code>null</code> reprsente
     *            la langue neutre)
     * @return Chanes rgionalises tries, ou <code>null</code> si les chanes
     *         en entres sont <code>null</code>
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public Collection sortStrings(final Collection strings, final List prioritizedLanguages) {
        return sortStrings(strings, LangUtils
                .convertLocalesToString(LangUtils.expand((Locale[]) prioritizedLanguages.toArray(new Locale[0]))));
    }

    /**
     * Tri les chanes rgionalises par langue, puis par libell.
     * 
     * @param strings
     *            Chanes rgionalises  trier (ou <code>null</code>)
     * @param prioritizedLanguages
     *            Langues prioritaires (la valeur <code>null</code> reprsente
     *            la langue neutre)
     * @return Chanes rgionalises tries, ou <code>null</code> si les chanes
     *         en entres sont <code>null</code>
     */
    public Collection<LocalizedString> sortStrings(final Collection<LocalizedString> strings,
            final String[] prioritizedLanguages) {
        Collection<LocalizedString> sortedStrings;

        if (strings == null) {
            sortedStrings = null;
        } else {
            final List<SortItemWrapper<LocalizedString>> wrappers = new ArrayList<SortItemWrapper<LocalizedString>>(
                    strings.size());
            final Iterator<LocalizedString> iterator = strings.iterator();

            for (int wrapperId = 0; iterator.hasNext(); wrapperId++) {
                final LocalizedString localizedString = iterator.next();
                final String language = localizedString.getLanguage();

                final Collator collator = language == null ? null : Collator.getInstance(getLocale(language));

                wrappers.add(wrapperId, new SortItemWrapper<LocalizedString>(localizedString, localizedString,
                        collator, prioritizedLanguages));
            }

            Collections.sort(wrappers);

            sortedStrings = new ArrayList<LocalizedString>(wrappers.size());
            for (final SortItemWrapper<LocalizedString> wrapper : wrappers) {
                sortedStrings.add(wrapper.getData());
            }
        }

        return sortedStrings;
    }

    /**
     * Charge une locale et la met en cache (si tel n'est pas dj le cas).
     * 
     * @param language
     *            Langage  charger
     * @return Locale correspondante
     */
    private Locale getLocale(final String language) {
        Locale locale = locales.get(language);
        if (locale == null) {
            locale = new Locale(language);
            locales.put(language, locale);
        }
        return locale;
    }

    /**
     * Renvoie le libell de l'entre. Si la priorit du choix de langages peut
     * tre respecte, alors la premire langue disponible dans l'entre sera
     * utilise. Sinon, l'URI de l'entre sera utilise.
     * 
     * @param entry
     *            Entre dont on souhaite rcuprer le libell
     * @param prioritizedLanguages
     *            Ordre de priorit des langues souhaites
     * @return Libell de l'entre, ou son URI si aucun libell n'a t trouv
     */
    private LocalizedString getEntryLabel(Entry entry, Locale[] prioritizedLanguages) {
        LocalizedString label = null;
        for (int currentLanguageId = 0; label == null
                && currentLanguageId < prioritizedLanguages.length; currentLanguageId++) {
            label = entry.getLabel(prioritizedLanguages[currentLanguageId]);
        }

        if (label == null) {
            label = new LocalizedString(entry.getUri(), null);
        }

        return label;
    }

}