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.xmlrpc;
020
021import java.util.Calendar;
022import java.util.Collection;
023import java.util.Date;
024import java.util.Hashtable;
025import java.util.Iterator;
026import java.util.Vector;
027
028import org.apache.wiki.LinkCollector;
029import org.apache.wiki.WikiContext;
030import org.apache.wiki.WikiEngine;
031import org.apache.wiki.WikiPage;
032import org.apache.wiki.attachment.Attachment;
033import org.apache.wiki.auth.permissions.PagePermission;
034import org.apache.wiki.auth.permissions.PermissionFactory;
035import org.apache.xmlrpc.XmlRpcException;
036
037/**
038 *  Provides handlers for all RPC routines.  These routines are used by
039 *  the UTF-8 interface.
040 *
041 *  @since 1.6.13
042 */
043
044public class RPCHandlerUTF8
045    extends AbstractRPCHandler
046{
047    public String getApplicationName()
048    {
049        checkPermission( PagePermission.VIEW );
050
051        return m_engine.getApplicationName();
052    }
053
054    public Vector getAllPages()
055    {
056        checkPermission( PagePermission.VIEW );
057
058        Collection< WikiPage > pages = m_engine.getRecentChanges();
059        Vector<String> result = new Vector<String>();
060
061        for( WikiPage p : pages )
062        {
063            if( !(p instanceof Attachment) )
064            {
065                result.add( p.getName() );
066            }
067        }
068
069        return result;
070    }
071
072    /**
073     *  Encodes a single wiki page info into a Hashtable.
074     */
075    protected Hashtable<String, Object> encodeWikiPage( WikiPage page )
076    {
077        Hashtable<String, Object> ht = new Hashtable<String, Object>();
078
079        ht.put( "name", page.getName() );
080
081        Date d = page.getLastModified();
082
083        //
084        //  Here we reset the DST and TIMEZONE offsets of the
085        //  calendar.  Unfortunately, I haven't thought of a better
086        //  way to ensure that we're getting the proper date
087        //  from the XML-RPC thingy, except to manually adjust the date.
088        //
089
090        Calendar cal = Calendar.getInstance();
091        cal.setTime( d );
092        cal.add( Calendar.MILLISECOND,
093                 - (cal.get( Calendar.ZONE_OFFSET ) +
094                    (cal.getTimeZone().inDaylightTime( d ) ? cal.get( Calendar.DST_OFFSET ) : 0 )) );
095
096        ht.put( "lastModified", cal.getTime() );
097        ht.put( "version", page.getVersion() );
098
099        if( page.getAuthor() != null )
100        {
101            ht.put( "author", page.getAuthor() );
102        }
103
104        return ht;
105    }
106
107    public Vector getRecentChanges( Date since )
108    {
109        checkPermission( PagePermission.VIEW );
110
111        Collection< WikiPage > pages = m_engine.getRecentChanges();
112        Vector<Hashtable<String, Object>> result = new Vector<Hashtable<String, Object>>();
113
114        Calendar cal = Calendar.getInstance();
115        cal.setTime( since );
116
117        //
118        //  Convert UTC to our time.
119        //
120        cal.add( Calendar.MILLISECOND,
121                 (cal.get( Calendar.ZONE_OFFSET ) +
122                  (cal.getTimeZone().inDaylightTime(since) ? cal.get( Calendar.DST_OFFSET ) : 0 ) ) );
123        since = cal.getTime();
124
125        for( WikiPage page : pages )
126        {
127            if( page.getLastModified().after( since ) && !(page instanceof Attachment) )
128            {
129                result.add( encodeWikiPage( page ) );
130            }
131        }
132
133        return result;
134    }
135
136    /**
137     *  Simple helper method, turns the incoming page name into
138     *  normal Java string, then checks page condition.
139     *
140     *  @param pagename Page Name as an RPC string (URL-encoded UTF-8)
141     *  @return Real page name, as Java string.
142     *  @throws XmlRpcException, if there is something wrong with the page.
143     */
144    private String parsePageCheckCondition( String pagename )
145        throws XmlRpcException
146    {
147        if( !m_engine.pageExists(pagename) )
148        {
149            throw new XmlRpcException( ERR_NOPAGE, "No such page '"+pagename+"' found, o master." );
150        }
151
152        WikiPage p = m_engine.getPage( pagename );
153
154        checkPermission( PermissionFactory.getPagePermission( p, PagePermission.VIEW_ACTION ) );
155        return pagename;
156    }
157
158    public Hashtable getPageInfo( String pagename )
159        throws XmlRpcException
160    {
161        pagename = parsePageCheckCondition( pagename );
162
163        return encodeWikiPage( m_engine.getPage(pagename) );
164    }
165
166    public Hashtable getPageInfoVersion( String pagename, int version )
167        throws XmlRpcException
168    {
169        pagename = parsePageCheckCondition( pagename );
170
171        return encodeWikiPage( m_engine.getPage( pagename, version ) );
172    }
173
174    public String getPage( String pagename )
175        throws XmlRpcException
176    {
177        pagename = parsePageCheckCondition( pagename );
178
179        String text = m_engine.getPureText( pagename, -1 );
180
181        return text;
182    }
183
184    public String getPageVersion( String pagename, int version )
185        throws XmlRpcException
186    {
187        pagename = parsePageCheckCondition( pagename );
188
189        return m_engine.getPureText( pagename, version );
190    }
191
192    public String getPageHTML( String pagename )
193        throws XmlRpcException
194    {
195        pagename = parsePageCheckCondition( pagename );
196
197        return m_engine.getHTML( pagename );
198    }
199
200    public String getPageHTMLVersion( String pagename, int version )
201        throws XmlRpcException
202    {
203        pagename = parsePageCheckCondition( pagename );
204
205        return m_engine.getHTML( pagename, version );
206    }
207
208    public Vector listLinks( String pagename )
209        throws XmlRpcException
210    {
211        pagename = parsePageCheckCondition( pagename );
212
213        WikiPage page = m_engine.getPage( pagename );
214        String pagedata = m_engine.getPureText( page );
215
216        LinkCollector localCollector = new LinkCollector();
217        LinkCollector extCollector   = new LinkCollector();
218        LinkCollector attCollector   = new LinkCollector();
219
220        WikiContext context = new WikiContext( m_engine, page );
221        context.setVariable( WikiEngine.PROP_REFSTYLE, "absolute" );
222
223        m_engine.textToHTML( context,
224                             pagedata,
225                             localCollector,
226                             extCollector,
227                             attCollector );
228
229        Vector<Hashtable<String, String>> result = new Vector<Hashtable<String, String>>();
230
231        // FIXME: Contains far too much common with RPCHandler.  Refactor!
232
233        //
234        //  Add local links.
235        //
236        for( Iterator< String > i = localCollector.getLinks().iterator(); i.hasNext(); )
237        {
238            String link = i.next();
239            Hashtable< String, String > ht = new Hashtable< String, String >();
240            ht.put( "page", link );
241            ht.put( "type", LINK_LOCAL );
242
243            if( m_engine.pageExists(link) )
244            {
245                ht.put( "href", context.getViewURL(link) );
246            }
247            else
248            {
249                ht.put( "href", context.getURL(WikiContext.EDIT,link) );
250            }
251
252            result.add( ht );
253        }
254
255        //
256        // Add links to inline attachments
257        //
258        for( String link : attCollector.getLinks() )
259        {
260            Hashtable<String, String> ht = new Hashtable<String, String>();
261
262            ht.put( "page", link );
263            ht.put( "type", LINK_LOCAL );
264            ht.put( "href", context.getURL(WikiContext.ATTACH,link) );
265
266            result.add( ht );
267        }
268
269        //
270        // External links don't need to be changed into XML-RPC strings,
271        // simply because URLs are by definition ASCII.
272        //
273
274        for( String link : extCollector.getLinks() )
275        {
276            Hashtable<String, String> ht = new Hashtable<String, String>();
277
278            ht.put( "page", link );
279            ht.put( "type", LINK_EXTERNAL );
280            ht.put( "href", link );
281
282            result.add( ht );
283        }
284
285        return result;
286    }
287}