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