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.apache.myfaces.tobago.ajax.AjaxUtils; 021 import org.apache.myfaces.tobago.application.ProjectStage; 022 import org.apache.myfaces.tobago.config.TobagoConfig; 023 import org.apache.myfaces.tobago.context.Capability; 024 import org.apache.myfaces.tobago.internal.webapp.DebugResponseWriterWrapper; 025 import org.apache.myfaces.tobago.internal.webapp.HtmlResponseWriter; 026 import org.apache.myfaces.tobago.internal.webapp.JsonResponseWriter; 027 import org.apache.myfaces.tobago.internal.webapp.XmlResponseWriter; 028 import org.apache.myfaces.tobago.util.VariableResolverUtils; 029 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter; 030 import org.slf4j.Logger; 031 import org.slf4j.LoggerFactory; 032 033 import javax.faces.FactoryFinder; 034 import javax.faces.context.FacesContext; 035 import javax.faces.context.ResponseStream; 036 import javax.faces.context.ResponseWriter; 037 import javax.faces.render.RenderKit; 038 import javax.faces.render.RenderKitFactory; 039 import javax.faces.render.Renderer; 040 import javax.faces.render.ResponseStateManager; 041 import java.io.OutputStream; 042 import java.io.Writer; 043 import java.util.HashMap; 044 import java.util.Map; 045 046 public class TobagoRenderKit extends RenderKit { 047 048 private static final Logger LOG = LoggerFactory.getLogger(TobagoRenderKit.class); 049 050 public static final String RENDER_KIT_ID = "tobago"; 051 052 private ResponseStateManager responseStateManager = new TobagoResponseStateManager(); 053 054 private RenderKit htmlBasicRenderKit; 055 056 private Map<Key, Renderer> renderers = new HashMap<Key, Renderer>(); 057 058 @Override 059 public Renderer getRenderer(String family, String rendererType) { 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 FacesContext facesContext = FacesContext.getCurrentInstance(); 091 if (AjaxUtils.isAjaxRequest(facesContext)) { 092 return new JsonResponseWriter(writer, "application/json", characterEncoding); 093 } 094 if (contentTypeList == null) { 095 contentType = "text/html"; 096 } else if (contentTypeList.indexOf("text/html") > -1) { 097 contentType = "text/html"; 098 LOG.warn("patching content type from " + contentTypeList + " to " + contentType + "'"); 099 } else if (contentTypeList.indexOf("text/fo") > -1) { 100 contentType = "text/fo"; 101 LOG.warn("patching content type from " + contentTypeList + " to " + contentType + "'"); 102 } else if (contentTypeList.indexOf("application/json") > -1) { 103 return new JsonResponseWriter(writer, "application/json", characterEncoding); 104 } else { 105 contentType = "text/html"; 106 LOG.warn("Content-Type '" + contentTypeList + "' not supported! Using text/html"); 107 } 108 109 // XXX enable xhtml here, by hand: 110 // contentType = "application/xhtml+xml"; 111 112 boolean xml = false; 113 if ("application/xhtml+xml".equals(contentType) 114 || "application/xhtml".equals(contentType) 115 || "application/xml".equals(contentType) 116 || "text/xml".equals(contentType)) { 117 xml = true; 118 } 119 120 // content type xhtml is not supported in every browser... e. g. IE 6, 7, 8 121 if (!VariableResolverUtils.resolveClientProperties(FacesContext.getCurrentInstance()) 122 .getUserAgent().hasCapability(Capability.CONTENT_TYPE_XHTML)) { 123 contentType = "text/html"; 124 } 125 126 TobagoResponseWriter responseWriter; 127 if (xml) { 128 responseWriter = new XmlResponseWriter(writer, contentType, characterEncoding); 129 } else { 130 responseWriter = new HtmlResponseWriter(writer, contentType, characterEncoding); 131 } 132 if (TobagoConfig.getInstance(facesContext).getProjectStage() == ProjectStage.Development) { 133 responseWriter = new DebugResponseWriterWrapper(responseWriter); 134 } 135 return responseWriter; 136 } 137 138 @Override 139 public void addRenderer(String family, String rendererType, Renderer renderer) { 140 renderers.put(new Key(family, rendererType), renderer); 141 } 142 143 @Override 144 public ResponseStateManager getResponseStateManager() { 145 //return getHtmlBasicRenderKit().getResponseStateManager(); 146 return responseStateManager; 147 } 148 149 @Override 150 public ResponseStream createResponseStream(OutputStream outputStream) { 151 return getHtmlBasicRenderKit().createResponseStream(outputStream); 152 } 153 154 private static final class Key { 155 private final String family; 156 private final String rendererType; 157 158 private Key(String family, String rendererType) { 159 this.family = family; 160 this.rendererType = rendererType; 161 } 162 163 public boolean equals(Object o) { 164 if (this == o) { 165 return true; 166 } 167 if (o == null || getClass() != o.getClass()) { 168 return false; 169 } 170 171 Key key = (Key) o; 172 173 if (!family.equals(key.family)) { 174 return false; 175 } 176 if (!rendererType.equals(key.rendererType)) { 177 return false; 178 } 179 180 return true; 181 } 182 183 public int hashCode() { 184 int result; 185 result = family.hashCode(); 186 result = 31 * result + rendererType.hashCode(); 187 return result; 188 } 189 } 190 }