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