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