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