View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.custom.outputlinkdynamic;
21  
22  import java.io.IOException;
23  import java.io.OutputStream;
24  import java.util.HashMap;
25  import java.util.Iterator;
26  import java.util.Map;
27  
28  import javax.faces.FacesException;
29  import javax.faces.FactoryFinder;
30  import javax.faces.component.UIComponent;
31  import javax.faces.component.UIParameter;
32  import javax.faces.context.ExternalContext;
33  import javax.faces.context.FacesContext;
34  import javax.faces.context.FacesContextFactory;
35  import javax.faces.context.ResponseStream;
36  import javax.faces.context.ResponseWriter;
37  import javax.faces.lifecycle.Lifecycle;
38  import javax.faces.lifecycle.LifecycleFactory;
39  import javax.faces.webapp.FacesServlet;
40  import javax.servlet.ServletContext;
41  import javax.servlet.http.HttpServletRequest;
42  import javax.servlet.http.HttpServletResponse;
43  
44  import org.apache.myfaces.component.html.util.ParameterResourceHandler;
45  import org.apache.myfaces.custom.dynamicResources.ResourceContext;
46  import org.apache.myfaces.custom.dynamicResources.ResourceRenderer;
47  import org.apache.myfaces.custom.dynamicResources.SimpleResourceContext;
48  import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
49  import org.apache.myfaces.renderkit.html.util.AddResource;
50  import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
51  import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils;
52  import org.apache.myfaces.renderkit.html.ext.HtmlLinkRenderer;
53  import org.apache.myfaces.renderkit.html.util.AddResourceFactory;
54  import org.apache.myfaces.renderkit.html.util.ResourceLoader;
55  import org.apache.myfaces.shared_tomahawk.util.ClassUtils;
56  
57  /**
58   * 
59   * @JSFRenderer
60   *   renderKitId = "HTML_BASIC" 
61   *   family = "javax.faces.Output"
62   *   type = "org.apache.myfaces.OutputLinkDynamicRenderer"
63   *
64   * @author Sylvain Vieujot
65   * @version $Revision: 659874 $ $Date: 2008-05-24 15:59:15 -0500 (Sat, 24 May 2008) $
66   */
67  public class OutputLinkDynamicRenderer extends HtmlLinkRenderer implements ResourceLoader
68  {
69      public static final String RENDERER_TYPE = "org.apache.myfaces.OutputLinkDynamicRenderer";
70  
71      private static final class ResourceResponseStream extends ResponseStream
72      {
73          private final OutputStream _out;
74  
75          private ResourceResponseStream(OutputStream out)
76          {
77              _out = out;
78          }
79  
80          public void close() throws IOException
81          {
82              _out.flush();
83              _out.close();
84          }
85  
86          public void flush() throws IOException
87          {
88              _out.flush();
89          }
90  
91          public void write(byte[] b, int off, int len) throws IOException
92          {
93              _out.write(b, off, len);
94          }
95  
96          public void write(byte[] b) throws IOException
97          {
98              _out.write(b);
99          }
100 
101         public void write(int b) throws IOException
102         {
103             _out.write(b);
104         }
105     }
106 
107     private static final String RENDERER_PARAM = "_renderer";
108 
109     public void encodeBegin(FacesContext context, UIComponent component) throws IOException
110     {
111         RendererUtils.checkParamValidity(context, component, OutputLinkDynamic.class);
112 
113         OutputLinkDynamic outputLinkDynamic = (OutputLinkDynamic) component;
114         ResponseWriter writer = context.getResponseWriter();
115 
116         writer.startElement(HTML.ANCHOR_ELEM, outputLinkDynamic);
117         HtmlRendererUtils.writeIdIfNecessary(writer, outputLinkDynamic, context);
118         HtmlRendererUtils.renderHTMLAttributes(writer, outputLinkDynamic,
119                                                HTML.ANCHOR_PASSTHROUGH_ATTRIBUTES);
120 
121         Map params = getParameterMap(context, component);
122 
123         Class resourceRendererClass = outputLinkDynamic.getResourceRendererClass();
124         if (resourceRendererClass == null)
125         {
126             throw new FacesException("No resourceRendererClass defined for component "
127                                      + component.getId());
128         }
129         params.put(RENDERER_PARAM, resourceRendererClass.getName());
130 
131         AddResource addResource = AddResourceFactory.getInstance(context);
132         String url = addResource.getResourceUri(context, new ParameterResourceHandler(this
133                 .getClass(), params));
134         writer.writeAttribute(HTML.HREF_ATTR, url, null);
135     }
136 
137     public void encodeEnd(FacesContext facesContext, UIComponent component) throws IOException
138     {
139             ResponseWriter writer = facesContext.getResponseWriter();
140         // force separate end tag
141         writer.writeText("", null);
142         writer.endElement(HTML.ANCHOR_ELEM);
143     }
144 
145     protected Map getParameterMap(FacesContext context, UIComponent component)
146     {
147         Map result = new HashMap();
148         for (Iterator iter = component.getChildren().iterator(); iter.hasNext();)
149         {
150             UIComponent child = (UIComponent) iter.next();
151             if (child instanceof UIParameter)
152             {
153                 UIParameter uiparam = (UIParameter) child;
154                 Object value = uiparam.getValue();
155                 if (value != null)
156                 {
157                     result.put(uiparam.getName(), value);
158                 }
159             }
160         }
161         return result;
162     }
163 
164     public void decode(FacesContext facesContext, UIComponent component)
165     {
166         super.decode(facesContext, component);
167     }
168 
169     /**
170      * @throws IOException
171      * @see org.apache.myfaces.renderkit.html.util.ResourceLoader#serveResource(javax.servlet.ServletContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.String)
172      */
173     public void serveResource(ServletContext context, HttpServletRequest request,
174                               HttpServletResponse response, String resourceUri) throws IOException
175     {
176         FacesContextFactory facesContextFactory = (FacesContextFactory) FactoryFinder
177                 .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
178         LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder
179                 .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
180         Lifecycle lifecycle = lifecycleFactory.getLifecycle(getLifecycleId(context));
181         FacesContext facesContext = facesContextFactory.getFacesContext(context, request, response,
182                                                                         lifecycle);
183         facesContext.setResponseStream(new ResourceResponseStream(response.getOutputStream()));
184         try
185         {
186             Map requestMap = facesContext.getExternalContext().getRequestParameterMap();
187             Object rendererValue = requestMap.get(RENDERER_PARAM);
188             if (rendererValue == null)
189             {
190                 throw new FacesException("no resource renderer defined.");
191             }
192             try
193             {
194                 Class rendererClass = ClassUtils.classForName(rendererValue.toString());
195                 if (!ResourceRenderer.class.isAssignableFrom(rendererClass))
196                 {
197                     throw new FacesException("Resource renderer class [" + rendererValue
198                                              + "] does not implement " + ResourceRenderer.class.getName());
199                 }
200                 try
201                 {
202                     ResourceRenderer resourceRenderer = (ResourceRenderer) rendererClass.newInstance();
203                     renderResource(resourceRenderer, facesContext);
204                 }
205                 catch (InstantiationException e)
206                 {
207                     throw new FacesException("could not instantiate resource renderer class "
208                                              + rendererValue + " : " + e.getMessage(), e);
209                 }
210                 catch (IllegalAccessException e)
211                 {
212                     throw new FacesException("could not instantiate resource renderer class "
213                                              + rendererValue + " : " + e.getMessage(), e);
214                 }
215                 catch (Exception e)
216                 {
217                     throw new FacesException("could not renderer resource "
218                                              + rendererValue + " : " + e.getMessage(), e);
219                 }
220             }
221             catch (ClassNotFoundException e)
222             {
223                 throw new FacesException("image renderer class not found: " + e.getMessage(), e);
224             }
225             facesContext.getResponseStream().close();
226         }
227         finally
228         {
229             facesContext.release();
230         }
231     }
232 
233     protected void renderResource(ResourceRenderer resourceRenderer, FacesContext facesContext)
234             throws Exception
235     {
236             ResourceContext resourceContext = createResourceContext(facesContext);
237 
238             resourceRenderer.setContext(facesContext, resourceContext);
239 
240         HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext()
241                 .getResponse();
242 
243 
244         int contentLength = resourceRenderer.getContentLength();
245         if( contentLength >0 )
246         {
247             response.setContentLength(contentLength);
248         }
249 
250         String contentType = resourceRenderer.getContentType();
251         if (contentType != null && contentType.length() > 0 )
252         {
253             response.setContentType(contentType);
254         }
255 
256         ResponseStream out = facesContext.getResponseStream();
257         try
258         {
259                 resourceRenderer.renderResource( out );
260         }
261         finally
262         {
263             out.close();
264             facesContext.responseComplete();
265         }
266     }
267 
268     protected ResourceContext createResourceContext(FacesContext facesContext)
269     {
270         ExternalContext externalContext = facesContext.getExternalContext();
271         final Map requestMap = externalContext.getRequestParameterMap();
272         return new SimpleResourceContext(requestMap);
273     }
274 
275     private String getLifecycleId(ServletContext context)
276     {
277         String lifecycleId = context.getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR);
278         return lifecycleId != null ? lifecycleId : LifecycleFactory.DEFAULT_LIFECYCLE;
279     }
280 }