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