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}