2009/05/20 - Apache Shale has been retired.
For more information, please explore the Attic.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shale.remoting;
19
20 import java.beans.Beans;
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.ResourceBundle;
26 import javax.faces.component.UIComponent;
27 import javax.faces.context.FacesContext;
28 import javax.faces.context.ResponseWriter;
29 import org.apache.shale.remoting.faces.MappingsHelper;
30
31 /***
32 * <p>Helper bean for rendering links to download resources commonly used
33 * in HTML and XHTML pages. The specified resource identifier is automatically
34 * mapped based upon the Shale Remoting configuration that this application
35 * is using, as well as adapting to the servlet mapping for the JavaServer
36 * Faces controller servlet. A given resource identifier will only be linked
37 * once for a given request.</p>
38 *
39 * <p>Instances of this class are stateless and have no side effects.</p>
40 */
41 public class XhtmlHelper {
42
43
44
45
46
47 /***
48 * <p>The prefix to the request attributes that we will use to keep track
49 * of whether a particular resource has been linked already.</p>
50 */
51 protected static final String PREFIX = "org.apache.shale.remoting.LINKED";
52
53
54
55
56
57 /***
58 * <p>Helper to retrieve the {@link Mappings} instance for this application.</p>
59 */
60 private MappingsHelper helper = new MappingsHelper();
61
62
63
64
65
66 /***
67 * <p>Render a link to a JavaScript resource at the specified resource
68 * identifier.</p>
69 *
70 * @param context <code>FacesContext</code> for the current request
71 * @param component <code>UIComponent</code> being rendered
72 * @param writer <code>ResponseWriter</code> to render output to
73 * @param mechanism Mechanism used to retrieve the specified resource
74 * (used to select the appropriate {@link Processor}
75 * @param resourceId Resource identifier used to retrieve the requested
76 * JavaScript resource
77 *
78 * @exception IllegalArgumentException if <code>mechanism</code> or
79 * <code>resourceId</code> is <code>null</code>
80 * @exception IllegalStateException if a configuration error prevents
81 * the mapping of this resource identifier to a corresponding URI
82 * @exception IOException if an input/output error occurs
83 */
84 public void linkJavascript(FacesContext context, UIComponent component,
85 ResponseWriter writer,
86 Mechanism mechanism, String resourceId)
87 throws IOException {
88
89 linkJavascript(context, component, writer,
90 mechanism, resourceId, "text/javascript");
91
92 }
93
94
95 /***
96 * <p>Render a link to a JavaScript resource at the specified resource
97 * identifier.</p>
98 *
99 * @param context <code>FacesContext</code> for the current request
100 * @param component <code>UIComponent</code> being rendered
101 * @param writer <code>ResponseWriter</code> to render output to
102 * @param mechanism Mechanism used to retrieve the specified resource
103 * (used to select the appropriate {@link Processor}
104 * @param resourceId Resource identifier used to retrieve the requested
105 * JavaScript resource
106 * @param contentType Content type to specify (for pulling specific
107 * versions of JavaScript resources)
108 *
109 * @exception IllegalArgumentException if <code>mechanism</code> or
110 * <code>resourceId</code> is <code>null</code>
111 * @exception IllegalStateException if a configuration error prevents
112 * the mapping of this resource identifier to a corresponding URI
113 * @exception IOException if an input/output error occurs
114 */
115 public void linkJavascript(FacesContext context, UIComponent component,
116 ResponseWriter writer,
117 Mechanism mechanism, String resourceId,
118 String contentType) throws IOException {
119
120 if (linked(context, resourceId)) {
121 return;
122 }
123
124 writer.startElement("script", component);
125 writer.writeAttribute("type", contentType, null);
126 writer.writeURIAttribute("src", mapResourceId(context, mechanism, resourceId), null);
127 writer.endElement("script");
128 writer.write("\n");
129
130 link(context, resourceId);
131
132 }
133
134
135 /***
136 * <p>Render a link to a CSS stylesheet at the specified resource
137 * identifier.</p>
138 *
139 * @param context <code>FacesContext</code> for the current request
140 * @param component <code>UIComponent</code> being rendered
141 * @param writer <code>ResponseWriter</code> to render output to
142 * @param mechanism Mechanism used to retrieve the specified resource
143 * (used to select the appropriate {@link Processor}
144 * @param resourceId Resource identifier used to retrieve the requested
145 * stylesheet resource
146 *
147 * @exception IllegalArgumentException if <code>mechanism</code> or
148 * <code>resourceId</code> is <code>null</code>
149 * @exception IllegalStateException if a configuration error prevents
150 * the mapping of this resource identifier to a corresponding URI
151 * @exception IOException if an input/output error occurs
152 */
153 public void linkStylesheet(FacesContext context, UIComponent component,
154 ResponseWriter writer,
155 Mechanism mechanism, String resourceId)
156 throws IOException {
157
158 if (linked(context, resourceId)) {
159 return;
160 }
161
162 writer.startElement("link", component);
163 writer.writeAttribute("type", "text/css", null);
164 writer.writeAttribute("rel", "stylesheet", null);
165 writer.writeURIAttribute("href", mapResourceId(context, mechanism, resourceId), null);
166 writer.endElement("link");
167 writer.write("\n");
168
169 link(context, resourceId);
170
171 }
172
173
174
175 /***
176 * <p>Map the specified resource identifier to a request URL, taking into
177 * account the mappings for the specified mechanism and the servlet mapping
178 * for the JavaServer Faces controller servlet.</p>
179 *
180 * @param context <code>FacesContext</code> for the current request
181 * @param mechanism Requested mechanism
182 * @param resourceId Resource identifier to be mapped
183 *
184 * @exception IllegalArgumentException if <code>mechanism</code> or
185 * <code>resourceId</code> is <code>null</code>
186 * @exception IllegalStateException if a configuration error prevents
187 * the mapping of this resource identifier to a corresponding URI
188 */
189 public String mapResourceId(FacesContext context, Mechanism mechanism,
190 String resourceId) {
191
192
193 if (resourceId == null) {
194 throw new IllegalArgumentException
195 (resourceBundle(context).getString("xhtml.noResourceId"));
196 }
197 if (mechanism == null) {
198 throw new IllegalArgumentException
199 (resourceBundle(context).getString("xhtml.noMechanism"));
200 }
201
202
203
204
205
206 if (Beans.isDesignTime()) {
207 return resourceId;
208 }
209
210
211 Mappings mappings = helper.getMappings(context);
212 if (mappings == null) {
213 throw new IllegalStateException
214 (resourceBundle(context).getString("xhtml.noMappings"));
215 }
216
217
218 List list = mappings.getMappings();
219 if (list == null) {
220 list = new ArrayList();
221 }
222 Iterator instances = list.iterator();
223 Mapping mapping = null;
224 while (instances.hasNext()) {
225 Mapping instance = (Mapping) instances.next();
226 if (mechanism == instance.getMechanism()) {
227 mapping = instance;
228 break;
229 }
230 }
231 if (mapping == null) {
232 throw new IllegalArgumentException(mechanism.toString());
233 }
234
235
236 return mapping.mapResourceId(context, resourceId);
237
238 }
239
240
241
242
243
244 /***
245 * <p>Mark the specified resource identifier as having already been
246 * linked in the current request.</p>
247 *
248 * @param context <code>FacesContext</code> for the current request
249 * @param resourceId Resource identifier to mark as having been linked
250 */
251 protected void link(FacesContext context, String resourceId) {
252
253 context.getExternalContext().getRequestMap().
254 put(PREFIX + resourceId, Boolean.TRUE);
255
256 }
257
258
259 /***
260 * <p>Return <code>true</code> if the specified resource identifier has
261 * already been linked in the current request, and should therefore not
262 * be linked again.</p>
263 *
264 * @param context <code>FacesContext</code> for the current request
265 * @param resourceId Resource identifier to check for prior linking
266 */
267 protected boolean linked(FacesContext context, String resourceId) {
268
269 return context.getExternalContext().getRequestMap().
270 containsKey(PREFIX + resourceId);
271
272 }
273
274
275 /***
276 * <p>Return the localized resource bundle we should use to generate
277 * exception or log messages for this request.</p>
278 *
279 * @param context <code>FacesContext</code> for this request
280 */
281 protected ResourceBundle resourceBundle(FacesContext context) {
282
283 return ResourceBundle.getBundle("org.apache.shale.remoting.Bundle",
284 context.getViewRoot().getLocale(),
285 Thread.currentThread().getContextClassLoader());
286
287 }
288
289
290 }