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.tobago.renderkit;
21  
22  import org.apache.myfaces.tobago.ajax.AjaxUtils;
23  import org.apache.myfaces.tobago.application.ProjectStage;
24  import org.apache.myfaces.tobago.config.TobagoConfig;
25  import org.apache.myfaces.tobago.context.Capability;
26  import org.apache.myfaces.tobago.internal.webapp.DebugResponseWriterWrapper;
27  import org.apache.myfaces.tobago.internal.webapp.HtmlResponseWriter;
28  import org.apache.myfaces.tobago.internal.webapp.JsonResponseWriter;
29  import org.apache.myfaces.tobago.internal.webapp.XmlResponseWriter;
30  import org.apache.myfaces.tobago.util.FacesVersion;
31  import org.apache.myfaces.tobago.util.VariableResolverUtils;
32  import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
33  import org.slf4j.Logger;
34  import org.slf4j.LoggerFactory;
35  
36  import javax.faces.FactoryFinder;
37  import javax.faces.context.FacesContext;
38  import javax.faces.context.ResponseStream;
39  import javax.faces.context.ResponseWriter;
40  import javax.faces.render.RenderKit;
41  import javax.faces.render.RenderKitFactory;
42  import javax.faces.render.Renderer;
43  import javax.faces.render.ResponseStateManager;
44  import java.io.OutputStream;
45  import java.io.Writer;
46  import java.util.HashMap;
47  import java.util.Map;
48  
49  public class TobagoRenderKit extends RenderKit {
50  
51    private static final Logger LOG = LoggerFactory.getLogger(TobagoRenderKit.class);
52  
53    public static final String RENDER_KIT_ID = "tobago";
54  
55    private ResponseStateManager responseStateManager = new TobagoResponseStateManager();
56  
57    private RenderKit htmlBasicRenderKit;
58  
59    private Map<Key, Renderer> renderers = new HashMap<Key, Renderer>();
60  
61    public TobagoRenderKit() {
62      if (LOG.isDebugEnabled()) {
63        LOG.debug("Creating TobagoRenderKit");
64      }
65    }
66  
67    @Override
68    public Renderer getRenderer(String family, String rendererType) {
69      Renderer renderer = renderers.get(new Key(family, rendererType));
70      if (renderer == null) {
71        RenderKit renderKit = getHtmlBasicRenderKit();
72        renderer = renderKit.getRenderer(family, rendererType);
73        if (renderer != null) {
74          renderer = new RendererBaseWrapper(renderer);
75        }
76      }
77  
78      if (renderer == null) {
79        LOG.error("The class which was found by the ResourceManager cannot be "
80            + "found or instantiated: classname='" + rendererType + "'");
81      }
82  
83      return renderer;
84    }
85  
86    private RenderKit getHtmlBasicRenderKit() {
87      if (htmlBasicRenderKit == null) {
88        RenderKitFactory rkFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
89        htmlBasicRenderKit =
90            rkFactory.getRenderKit(FacesContext.getCurrentInstance(), RenderKitFactory.HTML_BASIC_RENDER_KIT);
91      }
92      return htmlBasicRenderKit;
93    }
94  
95    @Override
96    public ResponseWriter createResponseWriter(
97        Writer writer, String contentTypeList, String characterEncoding) {
98      String contentType;
99      FacesContext facesContext = FacesContext.getCurrentInstance();
100     if (AjaxUtils.isAjaxRequest(facesContext)) {
101       return new JsonResponseWriter(writer, "application/json", characterEncoding);
102     }
103     if (contentTypeList == null) {
104       contentType = "text/html";
105     } else if (contentTypeList.indexOf("text/html") > -1) {
106       contentType = "text/html";
107       LOG.warn("patching content type from " + contentTypeList + " to " + contentType + "'");
108     } else if (contentTypeList.indexOf("text/fo") > -1) {
109       contentType = "text/fo";
110       LOG.warn("patching content type from " + contentTypeList + " to " + contentType + "'");
111     } else if (contentTypeList.indexOf("application/json") > -1) {
112       return new JsonResponseWriter(writer, "application/json", characterEncoding);
113     } else {
114       contentType = "text/html";
115       LOG.warn("Content-Type '" + contentTypeList + "' not supported! Using text/html");
116     }
117 
118 // XXX enable xhtml here, by hand:
119 //    contentType = "application/xhtml+xml";
120 
121     boolean xml = false;
122     if ("application/xhtml+xml".equals(contentType)
123         || "application/xhtml".equals(contentType)
124         || "application/xml".equals(contentType)
125         || "text/xml".equals(contentType)) {
126       xml = true;
127     }
128 
129     // content type xhtml is not supported in every browser... e. g. IE 6, 7, 8
130     if (!VariableResolverUtils.resolveClientProperties(FacesContext.getCurrentInstance())
131         .getUserAgent().hasCapability(Capability.CONTENT_TYPE_XHTML)) {
132       contentType = "text/html";
133     }
134 
135     TobagoResponseWriter responseWriter;
136     if (xml) {
137       responseWriter = new XmlResponseWriter(writer, contentType, characterEncoding);
138     } else {
139       responseWriter = new HtmlResponseWriter(writer, contentType, characterEncoding);
140     }
141     if (TobagoConfig.getInstance(facesContext).getProjectStage() == ProjectStage.Development) {
142       responseWriter = new DebugResponseWriterWrapper(responseWriter);
143     }
144     return responseWriter;
145   }
146 
147   @Override
148   public void addRenderer(String family, String rendererType, Renderer renderer) {
149     renderers.put(new Key(family, rendererType), renderer);
150   }
151 
152   @Override
153   public ResponseStateManager getResponseStateManager() {
154     if (FacesVersion.supports12() && FacesVersion.isMyfaces()
155         || FacesVersion.supports20() && FacesVersion.isMojarra()) {
156       return getHtmlBasicRenderKit().getResponseStateManager();
157     } else {
158       return responseStateManager;
159     }
160   }
161 
162   @Override
163   public ResponseStream createResponseStream(OutputStream outputStream) {
164     return getHtmlBasicRenderKit().createResponseStream(outputStream);
165   }
166 
167   private static final class Key {
168     private final String family;
169     private final String rendererType;
170 
171     private Key(String family, String rendererType) {
172       this.family = family;
173       this.rendererType = rendererType;
174     }
175 
176     public boolean equals(Object o) {
177       if (this == o) {
178         return true;
179       }
180       if (o == null || getClass() != o.getClass()) {
181         return false;
182       }
183 
184       Key key = (Key) o;
185 
186       if (!family.equals(key.family)) {
187         return false;
188       }
189       if (!rendererType.equals(key.rendererType)) {
190         return false;
191       }
192 
193       return true;
194     }
195 
196     public int hashCode() {
197       int result;
198       result = family.hashCode();
199       result = 31 * result + rendererType.hashCode();
200       return result;
201     }
202   }
203 }