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