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 public boolean equals( final Object o ) { 359 if( o instanceof WikiPage ) { 360 final WikiPage wp = ( WikiPage )o; 361 if( wp.getName().equals( getName() ) ) { 362 return wp.getVersion() == getVersion(); 363 } 364 } 365 366 return false; 367 } 368 369 /** 370 * {@inheritDoc} 371 */ 372 @Override 373 public int hashCode() { 374 return m_name.hashCode() * m_version; 375 } 376 377}