001/* 002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Anahide Tchertchian 018 */ 019package org.nuxeo.ecm.web.resources.jsf.handler; 020 021import java.io.IOException; 022import java.util.ArrayList; 023import java.util.Arrays; 024import java.util.Collection; 025import java.util.List; 026 027import javax.faces.component.UIComponent; 028import javax.faces.view.facelets.ComponentConfig; 029import javax.faces.view.facelets.FaceletContext; 030import javax.faces.view.facelets.FaceletHandler; 031import javax.faces.view.facelets.TagAttribute; 032import javax.faces.view.facelets.TagConfig; 033 034import org.apache.commons.lang.StringUtils; 035import org.apache.commons.logging.Log; 036import org.apache.commons.logging.LogFactory; 037import org.nuxeo.ecm.platform.ui.web.tag.handler.LeafFaceletHandler; 038import org.nuxeo.ecm.web.resources.api.Resource; 039import org.nuxeo.ecm.web.resources.api.ResourceType; 040import org.nuxeo.ecm.web.resources.api.service.WebResourceManager; 041import org.nuxeo.runtime.api.Framework; 042 043import com.sun.faces.facelets.tag.jsf.html.ScriptResourceHandler; 044import com.sun.faces.facelets.tag.jsf.html.StylesheetResourceHandler; 045 046/** 047 * Tag handler for resource bundles, resolving early resources that need to be included at build time (e.g JSF and XHTML 048 * resources for now). 049 * 050 * @since 7.4 051 */ 052public class ResourceBundleHandler extends PageResourceHandler { 053 054 private static final Log log = LogFactory.getLog(ResourceBundleHandler.class); 055 056 protected final TagAttribute items; 057 058 public ResourceBundleHandler(TagConfig config) { 059 super(config); 060 items = getAttribute("items"); 061 } 062 063 @SuppressWarnings("unchecked") 064 @Override 065 public void apply(FaceletContext ctx, UIComponent parent) throws IOException { 066 String typeValue = null; 067 if (type != null) { 068 typeValue = type.getValue(ctx); 069 } 070 ResourceType rtype = resolveType(typeValue); 071 if (rtype == null) { 072 log.error("Unsupported type '" + typeValue + "' on tag nxr:resourceBundle at " + tag.getLocation()); 073 return; 074 } 075 076 List<String> bundles = new ArrayList<String>(); 077 if (name != null) { 078 String bundleName = name.getValue(ctx); 079 if (!StringUtils.isBlank(bundleName)) { 080 bundles.add(bundleName); 081 } 082 } 083 if (items != null) { 084 Object itemsValue = items.getObject(ctx); 085 if (itemsValue instanceof Collection) { 086 bundles.addAll((Collection<String>) itemsValue); 087 } else if (itemsValue instanceof Object[]) { 088 bundles.addAll(Arrays.asList((String[]) itemsValue)); 089 } else if (itemsValue instanceof String) { 090 bundles.add((String) itemsValue); 091 } else { 092 log.error(String.format("Unsupported value '%s' for attribute 'items' on tag nxr:resourceBundle at %s", 093 itemsValue, tag.getLocation())); 094 } 095 } 096 097 if (bundles.isEmpty()) { 098 return; 099 } 100 101 String flavorValue = null; 102 if (flavor != null) { 103 flavorValue = flavor.getValue(ctx); 104 } 105 106 String targetValue = null; 107 if (target != null) { 108 targetValue = target.getValue(ctx); 109 } 110 111 String includeTimestampValue = null; 112 if (includeTimestamp != null) { 113 includeTimestampValue = includeTimestamp.getValue(ctx); 114 } 115 116 WebResourceManager wrm = Framework.getService(WebResourceManager.class); 117 LeafFaceletHandler leaf = new LeafFaceletHandler(); 118 if (rtype == ResourceType.any) { 119 String cssTarget = targetValue; 120 String jsTarget = targetValue; 121 String htmlTarget = targetValue; 122 if (vars != null) { 123 for (TagAttribute var : vars) { 124 if ("target_css".equalsIgnoreCase(var.getLocalName())) { 125 String val = resolveAttribute(ctx, var); 126 if (val != null) { 127 cssTarget = val; 128 } 129 } else if ("target_js".equalsIgnoreCase(var.getLocalName())) { 130 String val = resolveAttribute(ctx, var); 131 if (val != null) { 132 jsTarget = val; 133 } 134 } else if ("target_html".equalsIgnoreCase(var.getLocalName())) { 135 String val = resolveAttribute(ctx, var); 136 if (val != null) { 137 htmlTarget = val; 138 } 139 } 140 } 141 } 142 for (String bundle : bundles) { 143 // first include handlers that match JSF resources 144 applyBundle(ctx, parent, wrm, bundle, ResourceType.jsfcss, flavorValue, cssTarget, 145 includeTimestampValue, leaf); 146 applyBundle(ctx, parent, wrm, bundle, ResourceType.jsfjs, flavorValue, jsTarget, includeTimestampValue, 147 leaf); 148 // then include xhtmlfirst templates 149 applyBundle(ctx, parent, wrm, bundle, ResourceType.xhtmlfirst, flavorValue, null, includeTimestampValue, 150 leaf); 151 // then let other resources (css, js, html) be processed by the component at render time 152 applyBundle(ctx, parent, wrm, bundle, ResourceType.css, flavorValue, cssTarget, includeTimestampValue, 153 nextHandler); 154 applyBundle(ctx, parent, wrm, bundle, ResourceType.js, flavorValue, jsTarget, includeTimestampValue, 155 nextHandler); 156 applyBundle(ctx, parent, wrm, bundle, ResourceType.html, flavorValue, htmlTarget, includeTimestampValue, 157 nextHandler); 158 // then include xhtml templates 159 applyBundle(ctx, parent, wrm, bundle, ResourceType.xhtml, flavorValue, null, includeTimestampValue, 160 leaf); 161 } 162 } else { 163 for (String bundle : bundles) { 164 applyBundle(ctx, parent, wrm, bundle, rtype, flavorValue, targetValue, includeTimestampValue, leaf); 165 } 166 } 167 } 168 169 protected void applyBundle(FaceletContext ctx, UIComponent parent, WebResourceManager wrm, String bundle, 170 ResourceType type, String flavor, String targetValue, String includeTimestamp, FaceletHandler nextHandler) 171 throws IOException { 172 switch (type) { 173 case jsfjs: 174 for (Resource r : retrieveResources(wrm, bundle, type)) { 175 String rtarget = r.getTarget(); 176 ComponentConfig config = getJSFResourceComponentConfig(r, "javax.faces.resource.Script", 177 rtarget == null ? targetValue : rtarget, includeTimestamp, nextHandler); 178 new ScriptResourceHandler(config).apply(ctx, parent); 179 } 180 break; 181 case jsfcss: 182 for (Resource r : retrieveResources(wrm, bundle, type)) { 183 String rtarget = r.getTarget(); 184 ComponentConfig config = getJSFResourceComponentConfig(r, "javax.faces.resource.Stylesheet", 185 rtarget == null ? targetValue : rtarget, includeTimestamp, nextHandler); 186 new StylesheetResourceHandler(config).apply(ctx, parent); 187 } 188 break; 189 case xhtmlfirst: 190 includeXHTML(ctx, parent, retrieveResources(wrm, bundle, type), nextHandler); 191 break; 192 case xhtml: 193 includeXHTML(ctx, parent, retrieveResources(wrm, bundle, type), nextHandler); 194 break; 195 case js: 196 includeResourceBundle(ctx, parent, bundle, type, flavor, targetValue, includeTimestamp, nextHandler); 197 break; 198 case css: 199 includeResourceBundle(ctx, parent, bundle, type, flavor, targetValue, includeTimestamp, nextHandler); 200 break; 201 case html: 202 includeResourceBundle(ctx, parent, bundle, type, flavor, targetValue, includeTimestamp, nextHandler); 203 break; 204 default: 205 break; 206 } 207 } 208 209}