001    package org.apache.myfaces.tobago.renderkit;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one or more
005     * contributor license agreements.  See the NOTICE file distributed with
006     * this work for additional information regarding copyright ownership.
007     * The ASF licenses this file to You under the Apache License, Version 2.0
008     * (the "License"); you may not use this file except in compliance with
009     * the License.  You may obtain a copy of the License at
010     *
011     *      http://www.apache.org/licenses/LICENSE-2.0
012     *
013     * Unless required by applicable law or agreed to in writing, software
014     * distributed under the License is distributed on an "AS IS" BASIS,
015     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016     * See the License for the specific language governing permissions and
017     * limitations under the License.
018     */
019    
020    import org.slf4j.Logger;
021    import org.slf4j.LoggerFactory;
022    import org.apache.myfaces.tobago.application.ProjectStage;
023    import org.apache.myfaces.tobago.config.TobagoConfig;
024    import org.apache.myfaces.tobago.internal.webapp.DebugTobagoResponseWriterWrapper;
025    import org.apache.myfaces.tobago.internal.webapp.TobagoResponseJsonWriterImpl;
026    import org.apache.myfaces.tobago.internal.webapp.TobagoResponseWriterImpl;
027    import org.apache.myfaces.tobago.internal.webapp.TobagoResponseXmlWriterImpl;
028    import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
029    
030    import javax.faces.FactoryFinder;
031    import javax.faces.context.FacesContext;
032    import javax.faces.context.ResponseStream;
033    import javax.faces.context.ResponseWriter;
034    import javax.faces.render.RenderKit;
035    import javax.faces.render.RenderKitFactory;
036    import javax.faces.render.Renderer;
037    import javax.faces.render.ResponseStateManager;
038    import java.io.OutputStream;
039    import java.io.Writer;
040    import java.util.HashMap;
041    import java.util.Map;
042    
043    public class TobagoRenderKit extends RenderKit {
044    
045      private static final Logger LOG = LoggerFactory.getLogger(TobagoRenderKit.class);
046    
047      public static final String RENDER_KIT_ID = "tobago";
048    
049      private ResponseStateManager responseStateManager = new TobagoResponseStateManager();
050    
051      private RenderKit htmlBasicRenderKit;
052    
053      private Map<Key, Renderer> renderers = new HashMap<Key, Renderer>();
054    
055      @Override
056      public Renderer getRenderer(String family, String rendererType) {
057        if (LOG.isDebugEnabled()) {
058          LOG.debug("family = '" + family + "'");
059        }
060        Renderer renderer = renderers.get(new Key(family, rendererType));
061        if (renderer == null) {
062          RenderKit renderKit = getHtmlBasicRenderKit();
063          renderer = renderKit.getRenderer(family, rendererType);
064          if (renderer != null) {
065            renderer = new RendererBaseWrapper(renderer);
066          }
067        }
068    
069        if (renderer == null) {
070          LOG.error("The class which was found by the ResourceManager cannot be "
071              + "found or instantiated: classname='" + rendererType + "'");
072        }
073    
074        return renderer;
075      }
076    
077      private RenderKit getHtmlBasicRenderKit() {
078        if (htmlBasicRenderKit == null) {
079          RenderKitFactory rkFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
080          htmlBasicRenderKit =
081              rkFactory.getRenderKit(FacesContext.getCurrentInstance(), RenderKitFactory.HTML_BASIC_RENDER_KIT);
082        }
083        return htmlBasicRenderKit;
084      }
085    
086      @Override
087      public ResponseWriter createResponseWriter(
088          Writer writer, String contentTypeList, String characterEncoding) {
089        String contentType;
090        if (contentTypeList == null) {
091          contentType = "text/html";
092        } else if (contentTypeList.indexOf("text/html") > -1) {
093          contentType = "text/html";
094          LOG.warn("patching content type from " + contentTypeList + " to " + contentType + "'");
095        } else if (contentTypeList.indexOf("text/fo") > -1) {
096          contentType = "text/fo";
097          LOG.warn("patching content type from " + contentTypeList + " to " + contentType + "'");
098        } else if (contentTypeList.indexOf("application/json") > -1) {
099          return new TobagoResponseJsonWriterImpl(writer, "application/json", characterEncoding);
100        } else {
101          contentType = "text/html";
102          LOG.warn("Content-Type '" + contentTypeList + "' not supported! Using text/html");
103        }
104    
105        boolean xml = false;
106        if ("application/xhtml".equals(contentType)
107            || "application/xml".equals(contentType)
108            || "text/xml".equals(contentType)) {
109          xml = true;
110        }
111        // XXX for XHTML 1.0 the content type must be set to "text/html" for IE6
112        // XXX so at this time we can't differ ...
113    //    xml = true;
114        TobagoResponseWriter responseWriter;
115        if (xml) {
116          responseWriter = new TobagoResponseXmlWriterImpl(writer, contentType, characterEncoding);
117        } else {
118          responseWriter = new TobagoResponseWriterImpl(writer, contentType, characterEncoding);
119        }
120        if (TobagoConfig.getInstance(FacesContext.getCurrentInstance()).getProjectStage() == ProjectStage.Development) {
121          return new DebugTobagoResponseWriterWrapper(responseWriter);
122        }
123        return responseWriter;
124      }
125    
126      @Override
127      public void addRenderer(String family, String rendererType, Renderer renderer) {
128        renderers.put(new Key(family, rendererType), renderer);
129      }
130    
131      @Override
132      public ResponseStateManager getResponseStateManager() {
133        //return getHtmlBasicRenderKit().getResponseStateManager();
134        return responseStateManager;
135      }
136    
137      @Override
138      public ResponseStream createResponseStream(OutputStream outputStream) {
139        return getHtmlBasicRenderKit().createResponseStream(outputStream);
140      }
141    
142      private static final class Key {
143        private final String family;
144        private final String rendererType;
145    
146        private Key(String family, String rendererType) {
147          this.family = family;
148          this.rendererType = rendererType;
149        }
150    
151        public boolean equals(Object o) {
152          if (this == o) {
153            return true;
154          }
155          if (o == null || getClass() != o.getClass()) {
156            return false;
157          }
158    
159          Key key = (Key) o;
160    
161          if (!family.equals(key.family)) {
162            return false;
163          }
164          if (!rendererType.equals(key.rendererType)) {
165            return false;
166          }
167    
168          return true;
169        }
170    
171        public int hashCode() {
172          int result;
173          result = family.hashCode();
174          result = 31 * result + rendererType.hashCode();
175          return result;
176        }
177      }
178    }