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 WebResourceManager wrm = Framework.getService(WebResourceManager.class); 112 LeafFaceletHandler leaf = new LeafFaceletHandler(); 113 if (rtype == ResourceType.any) { 114 String cssTarget = targetValue; 115 String jsTarget = targetValue; 116 String htmlTarget = targetValue; 117 if (vars != null) { 118 for (TagAttribute var : vars) { 119 if ("target_css".equalsIgnoreCase(var.getLocalName())) { 120 String val = resolveAttribute(ctx, var); 121 if (val != null) { 122 cssTarget = val; 123 } 124 } else if ("target_js".equalsIgnoreCase(var.getLocalName())) { 125 String val = resolveAttribute(ctx, var); 126 if (val != null) { 127 jsTarget = val; 128 } 129 } else if ("target_html".equalsIgnoreCase(var.getLocalName())) { 130 String val = resolveAttribute(ctx, var); 131 if (val != null) { 132 htmlTarget = val; 133 } 134 } 135 } 136 } 137 for (String bundle : bundles) { 138 // first include handlers that match JSF resources 139 applyBundle(ctx, parent, wrm, bundle, ResourceType.jsfcss, flavorValue, cssTarget, leaf); 140 applyBundle(ctx, parent, wrm, bundle, ResourceType.jsfjs, flavorValue, jsTarget, leaf); 141 // then include xhtmlfirst templates 142 applyBundle(ctx, parent, wrm, bundle, ResourceType.xhtmlfirst, flavorValue, null, leaf); 143 // then let other resources (css, js, html) be processed by the component at render time 144 applyBundle(ctx, parent, wrm, bundle, ResourceType.css, flavorValue, cssTarget, nextHandler); 145 applyBundle(ctx, parent, wrm, bundle, ResourceType.js, flavorValue, jsTarget, nextHandler); 146 applyBundle(ctx, parent, wrm, bundle, ResourceType.html, flavorValue, htmlTarget, nextHandler); 147 // then include xhtml templates 148 applyBundle(ctx, parent, wrm, bundle, ResourceType.xhtml, flavorValue, null, leaf); 149 } 150 } else { 151 for (String bundle : bundles) { 152 applyBundle(ctx, parent, wrm, bundle, rtype, flavorValue, targetValue, leaf); 153 } 154 } 155 } 156 157 protected void applyBundle(FaceletContext ctx, UIComponent parent, WebResourceManager wrm, String bundle, 158 ResourceType type, String flavor, String targetValue, FaceletHandler nextHandler) throws IOException { 159 switch (type) { 160 case jsfjs: 161 for (Resource r : retrieveResources(wrm, bundle, type)) { 162 String rtarget = r.getTarget(); 163 ComponentConfig config = getJSFResourceComponentConfig(r, "javax.faces.resource.Script", 164 rtarget == null ? targetValue : rtarget, nextHandler); 165 new ScriptResourceHandler(config).apply(ctx, parent); 166 } 167 break; 168 case jsfcss: 169 for (Resource r : retrieveResources(wrm, bundle, type)) { 170 String rtarget = r.getTarget(); 171 ComponentConfig config = getJSFResourceComponentConfig(r, "javax.faces.resource.Stylesheet", 172 rtarget == null ? targetValue : rtarget, nextHandler); 173 new StylesheetResourceHandler(config).apply(ctx, parent); 174 } 175 break; 176 case xhtmlfirst: 177 includeXHTML(ctx, parent, retrieveResources(wrm, bundle, type), nextHandler); 178 break; 179 case xhtml: 180 includeXHTML(ctx, parent, retrieveResources(wrm, bundle, type), nextHandler); 181 break; 182 case js: 183 includeResourceBundle(ctx, parent, bundle, type, flavor, targetValue, nextHandler); 184 break; 185 case css: 186 includeResourceBundle(ctx, parent, bundle, type, flavor, targetValue, nextHandler); 187 break; 188 case html: 189 includeResourceBundle(ctx, parent, bundle, type, flavor, targetValue, nextHandler); 190 break; 191 default: 192 break; 193 } 194 } 195 196}