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    package org.apache.wiki;
020    
021    import java.util.Date;
022    import java.util.Enumeration;
023    import java.util.HashMap;
024    import java.util.Map;
025    
026    import org.apache.wiki.auth.acl.Acl;
027    import org.apache.wiki.auth.acl.AclEntry;
028    import org.apache.wiki.auth.acl.AclImpl;
029    import org.apache.wiki.providers.WikiPageProvider;
030    
031    /**
032     *  Simple wrapper class for the Wiki page attributes.  The Wiki page
033     *  content is moved around in Strings, though.
034     */
035    
036    // FIXME: We need to rethink how metadata is being used - probably the 
037    //        author, date, etc. should also be part of the metadata.  We also
038    //        need to figure out the metadata lifecycle.
039    
040    public class WikiPage
041        implements Cloneable,
042                   Comparable
043    {
044        private static final long serialVersionUID = 1L;
045    
046        private       String     m_name;
047        private       WikiEngine m_engine;
048        private       String     m_wiki;
049        private Date             m_lastModified;
050        private long             m_fileSize = -1;
051        private int              m_version = WikiPageProvider.LATEST_VERSION;
052        private String           m_author = null;
053        private final HashMap<String,Object> m_attributes = new HashMap<String,Object>();
054    
055        /**
056         *  "Summary" is a short summary of the page.  It is a String.
057         */
058        public static final String DESCRIPTION = "summary";
059    
060        /** A special variable name for storing a page alias. */
061        public static final String ALIAS = "alias";
062        
063        /** A special variable name for storing a redirect note */
064        public static final String REDIRECT = "redirect";
065    
066        /** A special variable name for storing a changenote. */
067        public static final String CHANGENOTE = "changenote";
068        
069        private Acl m_accessList = null;
070        
071        /**
072         *  Create a new WikiPage using a given engine and name.
073         *  
074         *  @param engine The WikiEngine that owns this page.
075         *  @param name   The name of the page.
076         */
077        public WikiPage( WikiEngine engine, String name )
078        {
079            m_engine = engine;
080            m_name = name;
081            m_wiki = engine.getApplicationName();
082        }
083    
084        /**
085         *  Returns the name of the page.
086         *  
087         *  @return The page name.
088         */
089        public String getName()
090        {
091            return m_name;
092        }
093    
094        /**
095         *  A WikiPage may have a number of attributes, which might or might not be 
096         *  available.  Typically attributes are things that do not need to be stored
097         *  with the wiki page to the page repository, but are generated
098         *  on-the-fly.  A provider is not required to save them, but they
099         *  can do that if they really want.
100         *
101         *  @param key The key using which the attribute is fetched
102         *  @return The attribute.  If the attribute has not been set, returns null.
103         */
104        public Object getAttribute( String key )
105        {
106            return m_attributes.get( key );
107        }
108    
109        /**
110         *  Sets an metadata attribute.
111         *  
112         *  @see #getAttribute(String)
113         *  @param key The key for the attribute used to fetch the attribute later on.
114         *  @param attribute The attribute value
115         */
116        public void setAttribute( String key, Object attribute )
117        {
118            m_attributes.put( key, attribute );
119        }
120    
121        /**
122         * Returns the full attributes Map, in case external code needs
123         * to iterate through the attributes.
124         * 
125         * @return The attribute Map.  Please note that this is a direct
126         *         reference, not a copy.
127         */
128        public Map getAttributes() 
129        {
130            return m_attributes;
131        }
132    
133        /**
134         *  Removes an attribute from the page, if it exists.
135         *  
136         *  @param  key The key for the attribute
137         *  @return If the attribute existed, returns the object.
138         *  @since 2.1.111
139         */
140        public Object removeAttribute( String key )
141        {
142            return m_attributes.remove( key );
143        }
144    
145        /**
146         *  Returns the date when this page was last modified.
147         *  
148         *  @return The last modification date
149         */
150        public Date getLastModified()
151        {
152            return m_lastModified;
153        }
154    
155        /**
156         *  Sets the last modification date.  In general, this is only
157         *  changed by the provider.
158         *  
159         *  @param date The date
160         */
161        public void setLastModified( Date date )
162        {
163            m_lastModified = date;
164        }
165    
166        /**
167         *  Sets the page version.  In general, this is only changed
168         *  by the provider.
169         *  
170         *  @param version The version number
171         */
172        public void setVersion( int version )
173        {
174            m_version = version;
175        }
176    
177        /**
178         *  Returns the version that this WikiPage instance represents.
179         *  
180         *  @return the version number of this page.
181         */
182        public int getVersion()
183        {
184            return m_version;
185        }
186    
187        /**
188         *  Returns the size of the page.
189         *  
190         *  @return the size of the page. 
191         *  @since 2.1.109
192         */
193        public long getSize()
194        {
195            return m_fileSize;
196        }
197    
198        /**
199         *  Sets the size.  Typically called by the provider only.
200         *  
201         *  @param size The size of the page.
202         *  @since 2.1.109
203         */
204        public void setSize( long size )
205        {
206            m_fileSize = size;
207        }
208    
209        /**
210         *  Returns the Acl for this page.  May return <code>null</code>, 
211         *  in case there is no Acl defined, or it has not
212         *  yet been set by {@link #setAcl(Acl)}.
213         *  
214         *  @return The access control list.  May return null, if there is 
215         *          no acl.
216         */
217        public Acl getAcl()
218        {
219            return m_accessList;
220        }
221    
222        /**
223         * Sets the Acl for this page. Note that method does <em>not</em>
224         * persist the Acl itself to back-end storage or in page markup;
225         * it merely sets the internal field that stores the Acl. To
226         * persist the Acl, callers should invoke 
227         * {@link org.apache.wiki.auth.acl.AclManager#setPermissions(WikiPage, Acl)}.
228         * @param acl The Acl to set
229         */
230        public void setAcl( Acl acl )
231        {
232            m_accessList = acl;
233        }
234    
235        /**
236         *  Sets the author of the page.  Typically called only by the provider.
237         *  
238         *  @param author The author name.
239         */
240        public void setAuthor( String author )
241        {
242            m_author = author;
243        }
244    
245        /**
246         *  Returns author name, or null, if no author has been defined.
247         *  
248         *  @return Author name, or possibly null.
249         */
250        public String getAuthor()
251        {
252            return m_author;
253        }
254        
255        /**
256         *  Returns the wiki nanme for this page
257         *  
258         *  @return The name of the wiki.
259         */
260        public String getWiki()
261        {
262            return m_wiki;
263        }
264    
265        /**
266         *  This method will remove all metadata from the page.
267         */
268        public void invalidateMetadata()
269        {        
270            m_hasMetadata = false;
271            setAcl( null );
272            m_attributes.clear();
273        }
274    
275        private boolean m_hasMetadata = false;
276    
277        /**
278         *  Returns <code>true</code> if the page has valid metadata; that is, it has been parsed.
279         *  Note that this method is a kludge to support our pre-3.0 metadata system, and as such
280         *  will go away with the new API.
281         *  
282         *  @return true, if the page has metadata.
283         */
284        public boolean hasMetadata()
285        {
286            return m_hasMetadata;
287        }
288    
289        /**
290         *  Sets the metadata flag to true.  Never call.
291         */
292        public void setHasMetadata()
293        {
294            m_hasMetadata = true;
295        }
296    
297        /**
298         *  Returns a debug-suitable version of the page.
299         *  
300         *  @return A debug string.
301         */
302        public String toString()
303        {
304            return "WikiPage ["+m_wiki+":"+m_name+",ver="+m_version+",mod="+m_lastModified+"]";
305        }
306    
307        /**
308         *  Creates a deep clone of a WikiPage.  Strings are not cloned, since
309         *  they're immutable.  Attributes are not cloned, only the internal
310         *  HashMap (so if you modify the contents of a value of an attribute,
311         *  these will reflect back to everyone).
312         *  
313         *  @return A deep clone of the WikiPage
314         */
315        public Object clone()
316        {
317            WikiPage p = new WikiPage( m_engine, m_name );
318           
319            p.m_wiki         = m_wiki;
320                
321            p.m_author       = m_author;
322            p.m_version      = m_version;
323            p.m_lastModified = m_lastModified != null ? (Date)m_lastModified.clone() : null;
324    
325            p.m_fileSize     = m_fileSize;
326    
327            for( Map.Entry<String,Object> entry : m_attributes.entrySet() )
328            {
329                p.m_attributes.put( entry.getKey(), 
330                                    entry.getValue() );
331            }
332    
333            if( m_accessList != null )
334            {
335                p.m_accessList = new AclImpl();
336                
337                for( Enumeration< AclEntry > entries = m_accessList.entries(); entries.hasMoreElements(); )
338                {
339                    AclEntry e = entries.nextElement();
340                
341                    p.m_accessList.addEntry( e );
342                }
343            }
344                
345            return p;
346        }
347        
348        /**
349         *  Compares a page with another using the defined PageNameComparator.  See org.apache.wiki.util.PageSorter.
350         *  
351         *  @param page The object to compare against
352         *  @return -1, 0 or 1
353         */
354        public int compareTo( Object page )
355        {
356            return m_engine.getPageSorter().compare( this, (WikiPage) page );
357        }
358        
359        /**
360         *  A page is equal to another page if its name and version are equal.
361         *  
362         *  {@inheritDoc}
363         */
364        // TODO: I have a suspicion that defining this method causes some problems
365        //       with page attributes and caching.  So as of 2.7.32, it's disabled.
366        /*
367        public boolean equals( Object o )
368        {
369            if( o != null && o instanceof WikiPage )
370            {
371                WikiPage oo = (WikiPage) o;
372            
373                if( oo.getName().equals( getName() ) )
374                {
375                    if( oo.getVersion() == getVersion() )
376                    {
377                        return true;
378                    }
379                }
380            }
381            
382            return false;
383        }
384        */
385        /**
386         *  {@inheritDoc}
387         */
388        public int hashCode()
389        {
390            return m_name.hashCode() * m_version;
391        }
392    }