001/* 002 * Copyright 2013 Anyware Services 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 */ 016package org.ametys.cms.clientsideelement; 017 018import java.util.ArrayList; 019import java.util.Collections; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023 024import org.apache.avalon.framework.component.ComponentException; 025import org.apache.avalon.framework.configuration.Configuration; 026import org.apache.avalon.framework.configuration.ConfigurationException; 027import org.apache.avalon.framework.configuration.DefaultConfiguration; 028import org.apache.avalon.framework.service.ServiceException; 029import org.apache.avalon.framework.service.ServiceManager; 030import org.slf4j.LoggerFactory; 031 032import org.ametys.core.ui.ClientSideElement; 033import org.ametys.core.ui.MenuClientSideElement; 034import org.ametys.core.ui.RibbonControlsManager; 035import org.ametys.core.ui.SimpleMenu; 036import org.ametys.core.ui.StaticClientSideElement; 037import org.ametys.runtime.plugin.component.ThreadSafeComponentManager; 038import org.ametys.runtime.workspace.WorkspaceMatcher; 039 040/** 041 * A smart menu to use for content 042 * 043 */ 044public class SmartContentMenu extends SmartContentClientSideElement implements MenuClientSideElement 045{ 046 /** The client side element component manager for menu items. */ 047 protected ThreadSafeComponentManager<ClientSideElement> _menuItemManager; 048 /** The ribbon control manager */ 049 protected RibbonControlsManager _ribbonControlManager; 050 /** The service manager. */ 051 protected ServiceManager _serviceManager; 052 053 /** The menu items */ 054 protected List<ClientSideElement> _menuItems; 055 /** The primary menu item */ 056 protected ClientSideElement _primaryMenuItem; 057 058 private List<ClientSideElement> _referencedClientSideElement; 059 private List<UnresolvedItem> _unresolvedMenuItems; 060 061 @Override 062 public void service(ServiceManager serviceManager) throws ServiceException 063 { 064 super.service(serviceManager); 065 _serviceManager = serviceManager; 066 _ribbonControlManager = (RibbonControlsManager) serviceManager.lookup(RibbonControlsManager.ROLE); 067 } 068 069 @Override 070 public void configure(Configuration configuration) throws ConfigurationException 071 { 072 _menuItemManager = new ThreadSafeComponentManager<>(); 073 _menuItemManager.setLogger(LoggerFactory.getLogger("cms.plugin.threadsafecomponent")); 074 _menuItemManager.service(_serviceManager); 075 076 super.configure(configuration); 077 078 // Menu items. 079 _referencedClientSideElement = new ArrayList<>(); 080 _unresolvedMenuItems = new ArrayList<>(); 081 _menuItems = new ArrayList<>(); 082 083 _configureItemsMenu(configuration); 084 } 085 086 /** 087 * Configure the items menu 088 * @param configuration the configuration 089 * @throws ConfigurationException If the configuration is not correct. 090 */ 091 protected void _configureItemsMenu(Configuration configuration) throws ConfigurationException 092 { 093 for (Configuration menuItemConfiguration : configuration.getChildren("menu-items")) 094 { 095 for (Configuration itemConfig : menuItemConfiguration.getChildren("item")) 096 { 097 boolean isPrimary = itemConfig.getAttributeAsBoolean("primaryItem", false); 098 099 if (itemConfig.getAttribute("ref", null) != null) 100 { 101 _unresolvedMenuItems.add(new UnresolvedItem(itemConfig.getAttribute("ref"), false, isPrimary)); 102 } 103 else 104 { 105 String id = itemConfig.getAttribute("id"); 106 107 DefaultConfiguration conf = new DefaultConfiguration("extension"); 108 conf.setAttribute("id", id); 109 conf.addChild(itemConfig.getChild("class")); 110 111 if (itemConfig.getChild("menu-items", false) != null || itemConfig.getChild("gallery-item", false) != null) 112 { 113 if (itemConfig.getChild("menu-items", false) != null) 114 { 115 conf.addChild(itemConfig.getChild("menu-items")); 116 } 117 118 if (itemConfig.getChild("gallery-item", false) != null) 119 { 120 conf.addChild(itemConfig.getChild("gallery-item")); 121 } 122 123 _menuItemManager.addComponent(_pluginName, null, id, SimpleMenu.class, conf); 124 } 125 else 126 { 127 _menuItemManager.addComponent(_pluginName, null, id, StaticClientSideElement.class, conf); 128 } 129 _unresolvedMenuItems.add(new UnresolvedItem(id, true, isPrimary)); 130 } 131 } 132 } 133 } 134 135 @Override 136 public List<Script> getScripts(boolean ignoreRights, Map<String, Object> contextParameters) 137 { 138 List<Script> result = new ArrayList<>(); 139 140 try 141 { 142 _resolveMenuItems(); 143 } 144 catch (Exception e) 145 { 146 throw new IllegalStateException("Unable to lookup client side element local components", e); 147 } 148 149 Map<String, Object> parameters = new HashMap<>(); 150 List<ScriptFile> cssFiles = new ArrayList<>(); 151 List<ScriptFile> scriptFiles = new ArrayList<>(); 152 153 // FIXME handle rights for workspace admin, here is a temporary workaround 154 if (ignoreRights 155 || contextParameters != null && "admin".equals(contextParameters.get(WorkspaceMatcher.WORKSPACE_NAME)) 156 || hasRight(getRights(contextParameters))) 157 { 158 List<Script> scripts = super.getScripts(ignoreRights, contextParameters); 159 for (Script script : scripts) 160 { 161 cssFiles.addAll(script.getCSSFiles()); 162 scriptFiles.addAll(script.getScriptFiles()); 163 parameters.putAll(script.getParameters()); 164 } 165 166 if (_primaryMenuItem != null) 167 { 168 for (Script script : _primaryMenuItem.getScripts(ignoreRights, contextParameters)) 169 { 170 Map<String, Object> primaryParameters = script.getParameters(); 171 parameters.put("primary-menu-item-id", script.getId()); 172 for (String paramId : primaryParameters.keySet()) 173 { 174 if (!parameters.containsKey(paramId)) 175 { 176 parameters.put(paramId, primaryParameters.get(paramId)); 177 } 178 } 179 } 180 } 181 182 // Menu items 183 if (_menuItems.size() > 0) 184 { 185 List<String> menuItems = new ArrayList<>(); 186 for (ClientSideElement element : _menuItems) 187 { 188 menuItems.add(element.getId()); 189 } 190 parameters.put("menu-items", menuItems); 191 } 192 193 result.add(new Script(this.getId(), _script.getScriptClassname(), scriptFiles, cssFiles, parameters)); 194 } 195 196 return result; 197 } 198 199 @Override 200 public List<ClientSideElement> getReferencedClientSideElements(Map<String, Object> contextParameters) 201 { 202 if (hasRight(getRights(contextParameters))) 203 { 204 return Collections.unmodifiableList(_referencedClientSideElement); 205 } 206 else 207 { 208 return List.of(); 209 } 210 } 211 212 213 private void _resolveMenuItems() throws Exception 214 { 215 if (_unresolvedMenuItems != null) 216 { 217 _menuItemManager.initialize(); 218 219 for (UnresolvedItem unresolvedItem : _unresolvedMenuItems) 220 { 221 String id = unresolvedItem.getId(); 222 ClientSideElement element; 223 if (unresolvedItem.isLocalItem()) 224 { 225 try 226 { 227 element = _menuItemManager.lookup(id); 228 } 229 catch (ComponentException e) 230 { 231 throw new Exception("Unable to lookup client side element role: '" + id + "'", e); 232 } 233 } 234 else 235 { 236 element = _ribbonControlManager.getExtension(id); 237 } 238 239 if (unresolvedItem.isPrimary()) 240 { 241 _primaryMenuItem = element; 242 } 243 244 _menuItems.add(element); 245 _referencedClientSideElement.add(element); 246 } 247 } 248 249 _unresolvedMenuItems = null; 250 } 251 252 class UnresolvedItem 253 { 254 private String _itemId; 255 private boolean _local; 256 private boolean _primary; 257 258 public UnresolvedItem(String id, boolean local) 259 { 260 _itemId = id; 261 _local = local; 262 _primary = false; 263 } 264 265 public UnresolvedItem(String id, boolean local, boolean primary) 266 { 267 _itemId = id; 268 _local = local; 269 _primary = primary; 270 } 271 272 public String getId () 273 { 274 return _itemId; 275 } 276 277 public boolean isLocalItem () 278 { 279 return _local; 280 } 281 282 public boolean isPrimary () 283 { 284 return _primary; 285 } 286 } 287}