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 public Acl getAcl() { 206 return m_accessList; 207 } 208 209 /** 210 * 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; 211 * it merely sets the internal field that stores the Acl. To persist the Acl, callers should invoke 212 * {@link org.apache.wiki.auth.acl.AclManager#setPermissions(Page, org.apache.wiki.api.core.Acl)}. 213 * 214 * @param acl The Acl to set 215 * @deprecated use {@link #setAcl(org.apache.wiki.api.core.Acl)} 216 * @see #setAcl(org.apache.wiki.api.core.Acl) 217 */ 218 @Deprecated 219 public void setAcl( final Acl acl ) { 220 setAcl( ( org.apache.wiki.api.core.Acl )acl ); 221 } 222 223 /** 224 * 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; 225 * it merely sets the internal field that stores the Acl. To persist the Acl, callers should invoke 226 * {@link org.apache.wiki.auth.acl.AclManager#setPermissions(Page, org.apache.wiki.api.core.Acl)}. 227 * 228 * @param acl The Acl to set 229 */ 230 public void setAcl( final org.apache.wiki.api.core.Acl acl ) { 231 m_accessList = ( Acl )acl; 232 } 233 234 /** 235 * Sets the author of the page. Typically called only by the provider. 236 * 237 * @param author The author name. 238 */ 239 @Override 240 public void setAuthor( final String author ) { 241 m_author = author; 242 } 243 244 /** 245 * Returns author name, or null, if no author has been defined. 246 * 247 * @return Author name, or possibly null. 248 */ 249 @Override 250 public String getAuthor() { 251 return m_author; 252 } 253 254 /** 255 * Returns the wiki name for this page 256 * 257 * @return The name of the wiki. 258 */ 259 @Override 260 public String getWiki() { 261 return m_wiki; 262 } 263 264 /** 265 * This method will remove all metadata from the page. 266 */ 267 @Override 268 public void invalidateMetadata() { 269 m_hasMetadata = false; 270 setAcl( null ); 271 m_attributes.clear(); 272 } 273 274 private boolean m_hasMetadata; 275 276 /** 277 * Returns <code>true</code> if the page has valid metadata; that is, it has been parsed. Note that this method is a kludge to 278 * support our pre-3.0 metadata system, and as such will go away with the new API. 279 * 280 * @return true, if the page has metadata. 281 */ 282 @Override 283 public boolean hasMetadata() { 284 return m_hasMetadata; 285 } 286 287 /** 288 * Sets the metadata flag to true. Never call. 289 */ 290 @Override 291 public void setHasMetadata() { 292 m_hasMetadata = true; 293 } 294 295 /** 296 * Returns a debug-suitable version of the page. 297 * 298 * @return A debug string. 299 */ 300 @Override 301 public String toString() { 302 return "WikiPage [" + m_wiki + ":" + m_name + ",ver=" + m_version + ",mod=" + m_lastModified + "]"; 303 } 304 305 /** 306 * Creates a deep clone of a WikiPage. Strings are not cloned, since they're immutable. Attributes are not cloned, only the internal 307 * HashMap (so if you modify the contents of a value of an attribute, these will reflect back to everyone). 308 * 309 * @return A deep clone of the WikiPage 310 */ 311 @Override 312 public WikiPage clone() { 313 final WikiPage p = new WikiPage( m_engine, m_name ); 314 p.m_wiki = m_wiki; 315 p.m_author = m_author; 316 p.m_version = m_version; 317 p.m_lastModified = m_lastModified != null ? (Date)m_lastModified.clone() : null; 318 p.m_fileSize = m_fileSize; 319 p.m_attributes.putAll( m_attributes ); 320 321 if( m_accessList != null ) { 322 p.m_accessList = new AclImpl(); 323 for( final Enumeration< AclEntry > entries = m_accessList.entries(); entries.hasMoreElements(); ) { 324 final AclEntry e = entries.nextElement(); 325 p.m_accessList.addEntry( e ); 326 } 327 } 328 329 return p; 330 } 331 332 /** 333 * Compares a page with another by name using the defined PageNameComparator. If the same name, compares their versions. 334 * 335 * @param page The page to compare against 336 * @return -1, 0 or 1 337 */ 338 @Override 339 public int compareTo( final Page page ) { 340 if( this == page ) { 341 return 0; // the same object 342 } 343 344 int res = m_engine.getManager( PageManager.class ).getPageSorter().compare( this.getName(), page.getName() ); 345 if( res == 0 ) { 346 res = this.getVersion() - page.getVersion(); 347 } 348 return res; 349 } 350 351 /** 352 * A page is equal to another page if its name and version are equal. 353 * 354 * {@inheritDoc} 355 */ 356 public boolean equals( final Object o ) { 357 if( o instanceof WikiPage ) { 358 final WikiPage wp = ( WikiPage )o; 359 if( wp.getName().equals( getName() ) ) { 360 return wp.getVersion() == getVersion(); 361 } 362 } 363 364 return false; 365 } 366 367 /** 368 * {@inheritDoc} 369 */ 370 @Override 371 public int hashCode() { 372 return m_name.hashCode() * m_version; 373 } 374 375}