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