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    
020    package org.apache.wiki;
021    
022    import java.util.Arrays;
023    import java.util.Collections;
024    import java.util.Comparator;
025    import java.util.List;
026    import java.util.Properties;
027    
028    import org.apache.log4j.Logger;
029    import org.apache.wiki.util.ClassUtil;
030    import 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     */
038    public 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    }