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 }