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}