001/* 
002    Licensed to the Apache Software Foundation (ASF) under one
003    or more contributor license agreements.  See the NOTICE file
004    distributed with this work for additional information
005    regarding copyright ownership.  The ASF licenses this file
006    to you under the Apache License, Version 2.0 (the
007    "License"); you may not use this file except in compliance
008    with the License.  You may obtain a copy of the License at
009
010       http://www.apache.org/licenses/LICENSE-2.0
011
012    Unless required by applicable law or agreed to in writing,
013    software distributed under the License is distributed on an
014    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015    KIND, either express or implied.  See the License for the
016    specific language governing permissions and limitations
017    under the License.  
018 */
019
020package org.apache.wiki;
021
022import java.util.Arrays;
023import java.util.Collections;
024import java.util.Comparator;
025import java.util.List;
026import java.util.Properties;
027
028import org.apache.log4j.Logger;
029import org.apache.wiki.util.ClassUtil;
030import org.apache.wiki.util.comparators.JavaNaturalComparator;
031
032/**
033 * Wrapper class for managing and using the PageNameComparator.
034 * <p>
035 * <b>Note</b> - this class is deliberately not null safe. Never call any of the
036 * methods with a null argument!
037 */
038public class PageSorter implements Comparator
039{
040    private static Logger log = Logger.getLogger( PageSorter.class );
041
042    // The name of the property that specifies the desired page name comparator
043    protected static final String PROP_PAGE_NAME_COMPARATOR = "jspwiki.pageNameComparator.class";
044
045    private Comparator<String> m_comparator;
046
047    /**
048     * Default constructor uses Java "natural" ordering.
049     */
050    public PageSorter()
051    {
052        m_comparator = JavaNaturalComparator.DEFAULT_JAVA_COMPARATOR;
053    }
054
055    /**
056     * Construct with a particular comparator.
057     * 
058     * @param comparator the Comparator to use
059     */
060    public PageSorter( Comparator<String> comparator )
061    {
062        m_comparator = comparator;
063    }
064
065    /**
066     * Compare two page names (Object version). Arguments must be either String
067     * or WikiPage.
068     * 
069     * @throws IllegalArgumentException if incorrect argument types.
070     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
071     */
072    public int compare( Object o1, Object o2 )
073    {
074        if( o1 instanceof String )
075        {
076            if( o2 instanceof String )
077                return m_comparator.compare( (String) o1, (String) o2 );
078            if( o2 instanceof WikiPage )
079                return m_comparator.compare( (String) o1, ((WikiPage) o2).getName() );
080        }
081        else if( o1 instanceof WikiPage )
082        {
083            if( o2 instanceof WikiPage )
084                return m_comparator.compare( ((WikiPage) o1).getName(), ((WikiPage) o2).getName() );
085            if( o2 instanceof String )
086                return m_comparator.compare( ((WikiPage) o1).getName(), (String) o2 );
087        }
088
089        throw new IllegalArgumentException( "Can only compare String or WikiPage" );
090    }
091
092    /**
093     * Compare two page names (String version).
094     * 
095     * @param pageName1 the first page name
096     * @param pageName2 the second page name
097     * @return see java.util.Comparator
098     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
099     */
100    public int compare( String pageName1, String pageName2 )
101    {
102        return m_comparator.compare( pageName1, pageName2 );
103    }
104
105    /**
106     * Compare two pages (WikiPage version). Compares them by name first. If the
107     * same name, compares their versions.
108     * 
109     * @param page1 the first page
110     * @param page2 the second page
111     * @return see java.util.Comparator
112     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
113     */
114    public int compare( WikiPage page1, WikiPage page2 )
115    {
116        if( page1 == page2 )
117            return 0; // the same object
118
119        int res = m_comparator.compare( page1.getName(), page2.getName() );
120        if( res == 0 )
121            res = page1.getVersion() - page2.getVersion();
122        return res;
123    }
124
125    @Override
126    public boolean equals( Object o )
127    {
128        if( !(o instanceof PageSorter) )
129            return false; // Definitely not equal
130
131        PageSorter that = (PageSorter) o;
132        if( this == that || m_comparator == that.m_comparator )
133            return true; // Essentially the same object
134        return m_comparator.equals( that.m_comparator );
135    }
136
137    /**
138     * Called by WikiEngine to initialise this instance. Tries to use class
139     * given by the PROP_PAGE_NAME_COMPARATOR property as the page name
140     * comparator. Uses a default comparator if this property is not set or
141     * there is any problem loading the specified class.
142     * 
143     * @param props this WikiEngine's properties.
144     */
145    @SuppressWarnings( "unchecked" )
146    public void initialize( Properties props )
147    {
148        // Default is Java natural order
149        m_comparator = JavaNaturalComparator.DEFAULT_JAVA_COMPARATOR;
150        String className = props.getProperty( PROP_PAGE_NAME_COMPARATOR );
151        if( className != null && className.length() > 0 )
152            try
153            {
154                m_comparator = (Comparator<String>) ClassUtil.findClass( "org.apache.wiki.util.comparators", className )
155                    .newInstance();
156            }
157            catch( Exception e )
158            {
159                log.error( "Falling back to default \"natural\" comparator", e );
160            }
161    }
162
163    /**
164     * Sorts the specified list into ascending order based on the
165     * PageNameComparator. The actual sort is done using
166     * <code>Collections.sort()</code>.
167     * 
168     * @param nameList the page names to be sorted
169     */
170    public void sort( List<String> nameList )
171    {
172        Collections.sort( nameList, m_comparator );
173    }
174
175    /**
176     * Sorts the specified array into ascending order based on the
177     * PageNameComparator. The actual sort is done using
178     * <code>Arrays.sort()</code>.
179     * 
180     * @param nameArray the page names to be sorted
181     */
182    public void sort( String[] nameArray )
183    {
184        Arrays.sort( nameArray, m_comparator );
185    }
186
187    /**
188     * Sorts the specified list into ascending order based on the
189     * PageNameComparator. The actual sort is done using
190     * <code>Collections.sort()</code>.
191     * 
192     * @param pageList the pages to be sorted
193     */
194    @SuppressWarnings( "unchecked" )
195    public void sortPages( List<Object> pageList )
196    {
197        Collections.sort( pageList, this );
198    }
199
200    /**
201     * Sorts the specified array into ascending order based on the
202     * PageNameComparator. The actual sort is done using
203     * <code>Arrays.sort()</code>.
204     * 
205     * @param pageArray the pages to be sorted
206     */
207    @SuppressWarnings( "unchecked" )
208    public void sortPages( Object[] pageArray )
209    {
210        Arrays.sort( pageArray, this );
211    }
212}