001package votorola.a.position; // Copyright 2010-2013, Michael Allan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE. 002 003import java.io.*; 004import java.net.*; 005import javax.ws.rs.core.UriBuilder; 006import javax.xml.stream.*; 007import votorola.g.*; 008import votorola.g.hold.*; 009import votorola.g.lang.*; 010 011 012/** An implementation of a page revision. 013 */ 014 @SuppressWarnings("overrides")/* overrides equals, but not hashCode*/ 015public @ThreadSafe class PageRevision1 implements PageRevision 016{ 017 018 019 /** Attempts to construct a PageRevision1 from the response to a page query. 020 * 021 * @param _xml a reader for the response to a page query that covers properties 022 * 'info' or (if !_toLatest) 'info|revisions' in which at least one 'page' 023 * element might remain to be read. 024 * @param _toLatest true to read the revision from info 'lastrevid', or false to 025 * read it from the 'revisions' that are included in the query. 026 * 027 * @return the constructed page revision, or null if no 'page' element remains 028 * to be read. 029 * 030 * @throws MediaWiki.NoSuchItem if a requested page or revision does not exist. 031 */ 032 public static PageRevision readPageRevision( final URI wikiScriptURI, XMLStreamReader _xml, 033 boolean _toLatest ) throws IOException, XMLStreamException 034 { 035 return readPageRevision( wikiScriptURI, _xml, _toLatest, 036 wikiScriptURI.toASCIIString() + "/index.php", /*maybeUgly*/true ); 037 } 038 039 040 041 /** @param maybeUgly whether the wiki location might be the standard access location 042 * ending in "index.php" for example, or is definitely a pretty alias per 043 * <code>$wgUsePathInfo</code>. 044 * 045 * @throws MediaWiki.NoSuchItem if a requested page or revision does not exist. 046 */ 047 private static PageRevision readPageRevision( final URI wikiScriptURI, final XMLStreamReader xml, 048 final boolean toLatest, final String wikiLocation, final boolean maybeUgly ) 049 throws IOException, XMLStreamException 050 { 051 while( xml.hasNext() ) 052 { 053 xml.next(); 054 if( !xml.isStartElement() ) continue; 055 056 if( "page".equals( xml.getLocalName() )) 057 { 058 MediaWiki.testPage_missing( xml ); /* when querying by 'titles'; else if 059 querying by 'revids' see 'badrevids' below */ 060 final int pageID = Integer.parseInt( xml.getAttributeValue( /*ns*/null, "pageid" )); 061 final String pageName = xml.getAttributeValue( /*ns*/null, "title" ); 062 final int revLatest = Integer.parseInt( xml.getAttributeValue( /*ns*/null, 063 "lastrevid" )); 064 final int rev; 065 rev: if( toLatest ) rev = revLatest; 066 else 067 { 068 while( xml.hasNext() ) 069 { 070 xml.next(); 071 if( xml.isEndElement() && "page".equals( xml.getLocalName() )) break; 072 073 if( xml.isStartElement() && "rev".equals( xml.getLocalName() )) 074 { 075 rev = Integer.parseInt( xml.getAttributeValue( /*ns*/null, "revid" )); 076 break rev; 077 } 078 } 079 throw new MediaWiki.MalformedResponse( "missing 'rev' element" ); 080 } 081 return new PageRevision1( wikiScriptURI, pageID, pageName, rev, revLatest, 082 wikiLocation, maybeUgly ); 083 } 084 MediaWiki.test_badrevids( xml ); /* when querying by 'revids'; else if 085 querying by 'titles' see testPage_missing above */ 086 MediaWiki.test_error( xml ); 087 } 088 return null; 089 } 090 091 092 093 /** Constructs a PageRevision1. 094 * 095 * @see #wikiScriptURI() 096 * @see #pageID() 097 * @param _pageName it will be normalized. 098 * @see #rev() 099 * @see #revLatest() 100 * @param maybeUgly whether the wiki location might be the standard access 101 * location ending in "index.php" for example, or is definitely a pretty alias 102 * per <code>$wgUsePathInfo</code>. 103 */ 104 protected PageRevision1( URI _wikiScriptURI, int _pageID, String _pageName, int _rev, 105 int _revLatest, final String wikiLocation, final boolean maybeUgly ) 106 { 107 wikiScriptURI = _wikiScriptURI; 108 pageID = _pageID; 109 pageName = MediaWiki.demiDecodedPageName( _pageName ); 110 rev = _rev; 111 revLatest = _revLatest; 112 if( rev < 0 ) throw new IllegalArgumentException(); // test only because -1 used in DiffKey 113 114 pageURI = MediaWiki.encodePageSpecifier( UriBuilder.fromUri(wikiLocation), maybeUgly, 115 _pageName ).build(); 116 try{ revURI = new URI( wikiScriptURI.toASCIIString() + "/index.php?oldid=" + rev ); } 117 catch( URISyntaxException x ) { throw new RuntimeException( x ); } 118 } 119 120 121 122 /** Constructs a PageRevision1 as a copy of another instance of a page revision. 123 */ 124 protected PageRevision1( final PageRevision rP ) 125 { 126 pageID = rP.pageID(); 127 pageName = rP.pageName(); 128 pageURI = rP.pageURI(); 129 rev = rP.rev(); 130 revLatest = rP.revLatest(); 131 revURI = rP.revURI(); 132 wikiScriptURI = rP.wikiScriptURI(); 133 } 134 135 136 137 // - O b j e c t ------------------------------------------------------------------ 138 139 140 /** Returns true iff o is a PageRevision having the same (equals) wiki script location 141 * and revision identifier. 142 * 143 * @see #rev() 144 * @see #wikiScriptURI() 145 */ 146 public final @Override boolean equals( Object o ) 147 { 148 if( !( o instanceof PageRevision )) return false; 149 150 final PageRevision other = (PageRevision)o; 151 return rev == other.rev() && wikiScriptURI.equals( other.wikiScriptURI() ); 152 153 } 154 155 156 157 /** Returns "r.{@linkplain #rev() rev}". 158 */ 159 public @Override String toString() { return "r." + rev(); } 160 161 162 163 // - P a g e - R e v i s i o n -------------------------------------------------------- 164 165 166 public boolean isLatestRevision() { return rev == revLatest; } 167 168 169 170 public final int pageID() { return pageID; } 171 172 173 private final int pageID; 174 175 176 177 public final String pageName() { return pageName; } 178 179 180 private final String pageName; 181 182 183 184 public final URI pageURI() { return pageURI; } 185 186 187 private final URI pageURI; 188 189 190 191 public final int rev() { return rev; } 192 193 194 private final int rev; 195 196 197 198 public final int revLatest() { return revLatest; } 199 200 201 private final int revLatest; 202 203 204 205 public final URI revURI() { return revURI; } 206 207 208 private final URI revURI; 209 210 211 212 public final URI wikiScriptURI() { return wikiScriptURI; } 213 214 215 private final URI wikiScriptURI; 216 217 218}