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 /** 123 * {@inheritDoc} 124 * 125 * @return The URL for the service. The URL will always be encoded when it is returned. 126 */ 127 public ILink getLink(boolean post, Object parameter) 128 { 129 Defense.isAssignable(parameter, ExternalServiceParameter.class, "parameter"); 130 131 ExternalServiceParameter esp = (ExternalServiceParameter) parameter; 132 133 Map parameters = new HashMap(); 134 135 parameters.put(ServiceConstants.PAGE, esp.getPageName()); 136 parameters.put(ServiceConstants.PARAMETER, esp.getServiceParameters()); 137 138 return _linkFactory.constructLink(this, post, parameters, true); 139 } 140 141 public void service(IRequestCycle cycle) throws IOException 142 { 143 String pageName = cycle.getParameter(ServiceConstants.PAGE); 144 IPage rawPage = cycle.getPage(pageName); 145 146 IExternalPage page = null; 147 148 try 149 { 150 page = (IExternalPage) rawPage; 151 } 152 catch (ClassCastException ex) 153 { 154 throw new ApplicationRuntimeException(EngineMessages.pageNotCompatible( 155 rawPage, 156 IExternalPage.class), rawPage, null, ex); 157 } 158 159 Object[] parameters = _linkFactory.extractListenerParameters(cycle); 160 161 cycle.setListenerParameters(parameters); 162 163 cycle.activate(page); 164 165 page.activateExternalPage(parameters, cycle); 166 167 _responseRenderer.renderResponse(cycle); 168 } 169 170 public String getName() 171 { 172 return Tapestry.EXTERNAL_SERVICE; 173 } 174 175 /** @since 4.0 */ 176 177 public void setResponseRenderer(ResponseRenderer responseRenderer) 178 { 179 _responseRenderer = responseRenderer; 180 } 181 182 /** @since 4.0 */ 183 public void setLinkFactory(LinkFactory linkFactory) 184 { 185 _linkFactory = linkFactory; 186 } 187 }