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