001 // Copyright 2004, 2005 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 015 package org.apache.tapestry.engine; 016 017 import java.io.IOException; 018 import java.util.HashMap; 019 import java.util.Map; 020 021 import org.apache.hivemind.ApplicationRuntimeException; 022 import org.apache.hivemind.util.Defense; 023 import org.apache.tapestry.IExternalPage; 024 import org.apache.tapestry.IPage; 025 import org.apache.tapestry.IRequestCycle; 026 import org.apache.tapestry.Tapestry; 027 import org.apache.tapestry.services.LinkFactory; 028 import org.apache.tapestry.services.ResponseRenderer; 029 import org.apache.tapestry.services.ServiceConstants; 030 031 /** 032 * The external service enables external applications to reference Tapestry pages via a URL. Pages 033 * which can be referenced by the external service must implement the {@link IExternalPage} 034 * interface. The external service enables the bookmarking of pages. 035 * <p> 036 * The external service may also be used by the Tapestry JSP taglibrary ( 037 * {@link org.apache.tapestry.jsp.ExternalURLTag}and {@link org.apache.tapestry.jsp.ExternalTag}). 038 * <p> 039 * You can try and second guess the URL format used by Tapestry. The default URL format for the 040 * external service is: <blockquote> 041 * <tt>http://localhost/app?service=external/<i>[Page Name]</i>&sp=[Param 0]&sp=[Param 1]...</tt> 042 * </blockquote> For example to view the "ViewCustomer" page the service parameters 5056 (customer 043 * ID) and 309 (company ID) the external service URL would be: <blockquote> 044 * <tt>http://localhost/myapp?service=external&context=<b>ViewCustomer</b>&sp=<b>5056</b>&sp=<b>302</b></tt> 045 * </blockquote> In this example external service will get a "ViewCustomer" page and invoke the 046 * {@link IExternalPage#activateExternalPage(Object[], IRequestCycle)}method with the parameters: 047 * Object[] { new Integer(5056), new Integer(302) }. 048 * <p> 049 * Note service parameters (sp) need to be prefixed by valid 050 * {@link org.apache.tapestry.util.io.DataSqueezerImpl}adaptor char. These adaptor chars are 051 * automatically provided in URL's created by the <tt>buildGesture()</tt> method. However if you 052 * hand coded an external service URL you will need to ensure valid prefix chars are present. 053 * <p> 054 * <table border="1" cellpadding="2"> 055 * <tr> 056 * <th>Prefix char(s)</th> 057 * <th>Mapped Java Type</th> 058 * </tr> 059 * <tr> 060 * <td> TF</td> 061 * <td> boolean</td> 062 * </tr> 063 * <tr> 064 * <td> b</td> 065 * <td> byte</td> 066 * </tr> 067 * <tr> 068 * <td> c</td> 069 * <td> char</td> 070 * </tr> 071 * <tr> 072 * <td> d</td> 073 * <td> double</td> 074 * </tr> 075 * <tr> 076 * <td> -0123456789</td> 077 * <td> integer</td> 078 * </tr> 079 * <tr> 080 * <td> l</td> 081 * <td> long</td> 082 * </tr> 083 * <tr> 084 * <td> S</td> 085 * <td> String</td> 086 * </tr> 087 * <tr> 088 * <td> s</td> 089 * <td> short</td> 090 * </tr> 091 * <tr> 092 * <td> other chars</td> 093 * <td> <tt>String</tt> without truncation of first char</td> 094 * </tr> 095 * <table> 096 * <p> 097 * <p> 098 * A good rule of thumb is to keep the information encoded in the URL short and simple, and restrict 099 * it to just Strings and Integers. Integers can be encoded as-is. Prefixing all Strings with the 100 * letter 'S' will ensure that they are decoded properly. Again, this is only relevant if an 101 * {@link org.apache.tapestry.IExternalPage}is being referenced from static HTML or JSP and the URL 102 * must be assembled in user code ... when the URL is generated by Tapestry, it is automatically 103 * created with the correct prefixes and encodings (as with any other service). 104 * 105 * @see org.apache.tapestry.IExternalPage 106 * @see org.apache.tapestry.jsp.ExternalTag 107 * @see org.apache.tapestry.jsp.ExternalURLTag 108 * @author Howard Lewis Ship 109 * @author Malcolm Edgar 110 * @since 2.2 111 */ 112 113 public class ExternalService implements IEngineService 114 { 115 /** @since 4.0 */ 116 117 private ResponseRenderer _responseRenderer; 118 119 /** @since 4.0 */ 120 private LinkFactory _linkFactory; 121 122 public ILink getLink(boolean post, Object parameter) 123 { 124 Defense.isAssignable(parameter, ExternalServiceParameter.class, "parameter"); 125 126 ExternalServiceParameter esp = (ExternalServiceParameter) parameter; 127 128 Map parameters = new HashMap(); 129 130 parameters.put(ServiceConstants.PAGE, esp.getPageName()); 131 parameters.put(ServiceConstants.PARAMETER, esp.getServiceParameters()); 132 133 return _linkFactory.constructLink(this, post, parameters, true); 134 } 135 136 public void service(IRequestCycle cycle) throws IOException 137 { 138 String pageName = cycle.getParameter(ServiceConstants.PAGE); 139 IPage rawPage = cycle.getPage(pageName); 140 141 IExternalPage page = null; 142 143 try 144 { 145 page = (IExternalPage) rawPage; 146 } 147 catch (ClassCastException ex) 148 { 149 throw new ApplicationRuntimeException(EngineMessages.pageNotCompatible( 150 rawPage, 151 IExternalPage.class), rawPage, null, ex); 152 } 153 154 Object[] parameters = _linkFactory.extractListenerParameters(cycle); 155 156 cycle.setListenerParameters(parameters); 157 158 cycle.activate(page); 159 160 page.activateExternalPage(parameters, cycle); 161 162 _responseRenderer.renderResponse(cycle); 163 } 164 165 public String getName() 166 { 167 return Tapestry.EXTERNAL_SERVICE; 168 } 169 170 /** @since 4.0 */ 171 172 public void setResponseRenderer(ResponseRenderer responseRenderer) 173 { 174 _responseRenderer = responseRenderer; 175 } 176 177 /** @since 4.0 */ 178 public void setLinkFactory(LinkFactory linkFactory) 179 { 180 _linkFactory = linkFactory; 181 } 182 }