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