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