001/* 002 * Copyright 2010 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.plugins.core.ui; 017 018import java.io.IOException; 019import java.util.Date; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023 024import org.apache.avalon.framework.context.Context; 025import org.apache.avalon.framework.context.ContextException; 026import org.apache.avalon.framework.context.Contextualizable; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.cocoon.Constants; 030import org.apache.cocoon.ProcessingException; 031import org.apache.cocoon.environment.ObjectModelHelper; 032import org.apache.cocoon.environment.Request; 033import org.apache.cocoon.generation.ServiceableGenerator; 034import org.apache.cocoon.xml.AttributesImpl; 035import org.apache.cocoon.xml.XMLUtils; 036import org.apache.commons.lang3.StringUtils; 037import org.apache.excalibur.source.Source; 038import org.apache.excalibur.source.SourceResolver; 039import org.xml.sax.SAXException; 040 041import org.ametys.core.ui.ClientSideElement; 042import org.ametys.core.ui.ClientSideElementDependenciesManager; 043import org.ametys.core.ui.MessageTargetFactoriesManager; 044import org.ametys.core.ui.RelationsManager; 045import org.ametys.core.ui.RibbonConfigurationManager; 046import org.ametys.core.ui.RibbonControlsManager; 047import org.ametys.core.ui.RibbonImportManager; 048import org.ametys.core.ui.RibbonManager; 049import org.ametys.core.ui.RibbonManagerCache; 050import org.ametys.core.ui.RibbonTabsManager; 051import org.ametys.core.ui.SAXClientSideElementHelper; 052import org.ametys.core.ui.StaticFileImportsManager; 053import org.ametys.core.ui.UIToolsConfigurationManager; 054import org.ametys.core.ui.UIToolsFactoriesManager; 055import org.ametys.core.ui.ribbonconfiguration.RibbonConfigurationSource; 056import org.ametys.core.ui.widgets.ClientSideWidget; 057import org.ametys.core.ui.widgets.WidgetsManager; 058import org.ametys.core.user.CurrentUserProvider; 059import org.ametys.core.user.UserIdentity; 060import org.ametys.core.util.JSONUtils; 061import org.ametys.plugins.core.user.UserHelper; 062import org.ametys.runtime.plugin.PluginsManager; 063import org.ametys.runtime.workspace.WorkspaceMatcher; 064 065/** 066 * Generates the uitools factories definition using the component associated 067 */ 068public class WorkspaceGenerator extends ServiceableGenerator implements Contextualizable 069{ 070 /** The ribbon control manager */ 071 protected RibbonControlsManager _ribbonControlManager; 072 /** The ribbon tab manager */ 073 protected RibbonTabsManager _ribbonTabManager; 074 /** The list of existing message target factories */ 075 protected MessageTargetFactoriesManager _messageTargetFactoriesManager; 076 /** The ui tools factories manager */ 077 protected UIToolsFactoriesManager _uitoolsFactoriesManager; 078 /** The relations manager */ 079 protected RelationsManager _relationsManager; 080 /** The widgets manager */ 081 protected WidgetsManager _widgetsManager; 082 /** The sax clientside element helper */ 083 protected SAXClientSideElementHelper _saxClientSideElementHelper; 084 /** The static files import manager */ 085 protected StaticFileImportsManager _fileImportsManager; 086 /** The Excalibur source resolver */ 087 protected SourceResolver _resolver; 088 /** Cocoon context */ 089 protected org.apache.cocoon.environment.Context _cocoonContext; 090 /** The current user provider component */ 091 protected CurrentUserProvider _currentUserProvider; 092 /** The json utils component */ 093 protected JSONUtils _jsonUtils; 094 /** The User Helper */ 095 protected UserHelper _userHelper; 096 /** The ribbon manager cache helper */ 097 protected RibbonManagerCache _ribbonManagerCache; 098 /** The ribbon import manager */ 099 protected RibbonImportManager _ribbonImportManager; 100 101 @Override 102 public void service(ServiceManager smanager) throws ServiceException 103 { 104 super.service(smanager); 105 _messageTargetFactoriesManager = (MessageTargetFactoriesManager) smanager.lookup(MessageTargetFactoriesManager.ROLE); 106 _uitoolsFactoriesManager = (UIToolsFactoriesManager) smanager.lookup(UIToolsFactoriesManager.ROLE); 107 _ribbonTabManager = (RibbonTabsManager) smanager.lookup(RibbonTabsManager.ROLE); 108 _ribbonControlManager = (RibbonControlsManager) smanager.lookup(RibbonControlsManager.ROLE); 109 _relationsManager = (RelationsManager) smanager.lookup(RelationsManager.ROLE); 110 _widgetsManager = (WidgetsManager) smanager.lookup(WidgetsManager.ROLE); 111 _saxClientSideElementHelper = (SAXClientSideElementHelper) smanager.lookup(SAXClientSideElementHelper.ROLE); 112 _fileImportsManager = (StaticFileImportsManager) smanager.lookup(StaticFileImportsManager.ROLE); 113 _resolver = (SourceResolver) smanager.lookup(SourceResolver.ROLE); 114 _currentUserProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE); 115 _jsonUtils = (JSONUtils) smanager.lookup(JSONUtils.ROLE); 116 _userHelper = (UserHelper) smanager.lookup(UserHelper.ROLE); 117 _ribbonManagerCache = (RibbonManagerCache) smanager.lookup(RibbonManagerCache.ROLE); 118 _ribbonImportManager = (RibbonImportManager) smanager.lookup(RibbonImportManager.ROLE); 119 } 120 121 @Override 122 public void contextualize(Context context) throws ContextException 123 { 124 _cocoonContext = (org.apache.cocoon.environment.Context) context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT); 125 } 126 127 @Override 128 public void generate() throws IOException, SAXException, ProcessingException 129 { 130 doGenerate(getContextualParameters()); 131 } 132 133 /** 134 * Get the contextual parameters 135 * @return The contextual parameters 136 */ 137 protected Map<String, Object> getContextualParameters() 138 { 139 Request request = ObjectModelHelper.getRequest(objectModel); 140 String workspaceName = (String) request.getAttribute(WorkspaceMatcher.WORKSPACE_NAME); 141 142 Map<String, Object> contextParameters = new HashMap<>(); 143 contextParameters.put(WorkspaceMatcher.WORKSPACE_NAME, workspaceName); 144 145 return contextParameters; 146 } 147 148 /** 149 * Generates the UI factories definitions, with parameters 150 * @param contextParameters context parameters. 151 * @throws IOException if an error occurred 152 * @throws SAXException if an error occurred 153 * @throws ProcessingException if an error occurred 154 */ 155 protected void doGenerate(Map<String, Object> contextParameters) throws IOException, SAXException, ProcessingException 156 { 157 long startTime = new Date().getTime(); 158 159 contentHandler.startDocument(); 160 XMLUtils.startElement(contentHandler, "workspace"); 161 162 UserIdentity currentUser = _currentUserProvider.getUser(); 163 if (currentUser != null) 164 { 165 String login = currentUser.getLogin(); 166 String userPopulationId = currentUser.getPopulationId(); 167 if (StringUtils.isNotBlank(login)) 168 { 169 UserIdentity userIdentity = new UserIdentity(login, userPopulationId); 170 _userHelper.saxUserIdentity(userIdentity, contentHandler); 171 } 172 } 173 174 ClientSideElementDependenciesManager dependenciesManager = new ClientSideElementDependenciesManager(this.manager); 175 176 RibbonConfigurationSource ribbonConfig = getRibbonConfiguration(); 177 Map<String, List<ClientSideElement>> elementsToSax; 178 RibbonManager ribbonManager = null; 179 try 180 { 181 ribbonManager = _ribbonManagerCache.getManager(ribbonConfig.getUri()); 182 String workspaceName = (String) ObjectModelHelper.getRequest(objectModel).getAttribute("workspaceName"); 183 RibbonConfigurationManager ribbonConfigurationManager = new RibbonConfigurationManager(); 184 ribbonConfigurationManager.setup(_ribbonControlManager, _ribbonTabManager, _ribbonImportManager, _saxClientSideElementHelper, _resolver, _ribbonManagerCache); 185 ribbonConfigurationManager.configure(ribbonManager, dependenciesManager, ribbonConfig, workspaceName); 186 ribbonConfigurationManager.saxRibbonDefinition(contentHandler, contextParameters); 187 elementsToSax = getElementsToSax(dependenciesManager, ribbonConfigurationManager, contextParameters); 188 } 189 catch (Exception e) 190 { 191 throw new ProcessingException("Unable to get or create a ribbon manager for ribbon specific components", e); 192 } 193 finally 194 { 195 _ribbonManagerCache.dispose(ribbonManager); 196 } 197 198 saxUITools(contextParameters, elementsToSax.get(UIToolsFactoriesManager.ROLE)); 199 saxMessageTargetFactories(contextParameters, elementsToSax.get(MessageTargetFactoriesManager.ROLE)); 200 saxRelationsHandlers(contextParameters, elementsToSax.get(RelationsManager.ROLE)); 201 saxWidgets(contextParameters); 202 saxStaticFileImports (contextParameters, elementsToSax.get(StaticFileImportsManager.ROLE)); 203 saxAdditionnalInfo(contextParameters); 204 205 XMLUtils.endElement(contentHandler, "workspace"); 206 contentHandler.endDocument(); 207 208 209 long endTime = new Date().getTime(); 210 getLogger().debug("Workspace generated in " + (endTime - startTime) + " ms"); 211 } 212 213 /** 214 * Retrieve the list of elements to generate the Workspace 215 * @param dependenciesManager The dependencies manager 216 * @param ribbonManager The ribbon manager for this workspace 217 * @param contextParameters Contextuals parameters transmitted by the environment. 218 * @return The list of elements, mapped by extension points. 219 * @throws SAXException If an error occurs 220 */ 221 protected Map<String, List<ClientSideElement>> getElementsToSax(ClientSideElementDependenciesManager dependenciesManager, RibbonConfigurationManager ribbonManager, Map<String, Object> contextParameters) throws SAXException 222 { 223 List<ClientSideElement> ribbonControls = ribbonManager.getControls(contextParameters); 224 for (ClientSideElement control : ribbonControls) 225 { 226 dependenciesManager.register(control); 227 } 228 List<ClientSideElement> ribbonTabs = ribbonManager.getTabs(); 229 for (ClientSideElement control : ribbonTabs) 230 { 231 dependenciesManager.register(control); 232 } 233 234 for (String extensionId: _widgetsManager.getExtensionsIds()) 235 { 236 ClientSideWidget element = _widgetsManager.getExtension(extensionId); 237 dependenciesManager.register(element); 238 } 239 240 try 241 { 242 return dependenciesManager.computeDependencies(); 243 } 244 catch (ServiceException e) 245 { 246 throw new SAXException("Unable to compute dependencies", e); 247 } 248 } 249 250 /** 251 * SAX the UI Tools 252 * @param contextParameters the context parameters 253 * @param elements The list of elements to sax 254 * @throws IOException if an error occurred 255 * @throws SAXException if an error occurred 256 */ 257 protected void saxUITools(Map<String, Object> contextParameters, List<ClientSideElement> elements) throws IOException, SAXException 258 { 259 Source configSource = getUIToolsConfiguration(); 260 UIToolsConfigurationManager uitoolsManager = new UIToolsConfigurationManager(_uitoolsFactoriesManager, _saxClientSideElementHelper, configSource, ObjectModelHelper.getRequest(objectModel)); 261 uitoolsManager.saxDefaultState(contentHandler, contextParameters, elements); 262 } 263 264 /** 265 * Get the ribbon configuration 266 * @return the ribbon configuration 267 * @throws IOException if an errors occurs getting the ribbon configuration 268 */ 269 protected RibbonConfigurationSource getRibbonConfiguration() throws IOException 270 { 271 String ribbonFileName = parameters.getParameter("ribbonFileName", "ribbon"); 272 String mode = parameters.getParameter("mode", null); 273 return RibbonConfigurationSource.createFromUri("context://WEB-INF/param/" + ribbonFileName + (mode != null ? "-" + mode : "") + ".xml", _resolver); 274 } 275 276 /** 277 * Get the UI tools configuration 278 * @return the UI tools configuration 279 * @throws IOException if an errors occurs getting the UI tools configuration 280 */ 281 protected Source getUIToolsConfiguration() throws IOException 282 { 283 String toolsFileName = parameters.getParameter("toolsFileName", "uitools"); 284 String mode = parameters.getParameter("mode", null); 285 return _resolver.resolveURI("context://WEB-INF/param/" + toolsFileName + (mode != null ? "-" + mode : "") + ".xml"); 286 } 287 288 /** 289 * SAX the message target factories 290 * @param contextParameters the context parameters 291 * @param elements The list of elements for the message target factories 292 * @throws SAXException if an error occurred 293 */ 294 protected void saxMessageTargetFactories(Map<String, Object> contextParameters, List<ClientSideElement> elements) throws SAXException 295 { 296 contentHandler.startPrefixMapping("i18n", "http://apache.org/cocoon/i18n/2.1"); 297 XMLUtils.startElement(contentHandler, "messagetarget-factories"); 298 299 if (elements != null) 300 { 301 for (ClientSideElement element : elements) 302 { 303 _saxClientSideElementHelper.saxDefinition("messagetarget-factory", element, MessageTargetFactoriesManager.ROLE, contentHandler, contextParameters); 304 } 305 } 306 307 XMLUtils.endElement(contentHandler, "messagetarget-factories"); 308 contentHandler.endPrefixMapping("i18n"); 309 } 310 311 /** 312 * SAX the relations handlers 313 * @param contextParameters the context parameters 314 * @param elements The list of relation handlers 315 * @throws SAXException if an error occurred 316 */ 317 protected void saxRelationsHandlers(Map<String, Object> contextParameters, List<ClientSideElement> elements) throws SAXException 318 { 319 contentHandler.startPrefixMapping("i18n", "http://apache.org/cocoon/i18n/2.1"); 320 XMLUtils.startElement(contentHandler, "relations-handlers"); 321 322 if (elements != null) 323 { 324 for (ClientSideElement element: elements) 325 { 326 _saxClientSideElementHelper.saxDefinition("relation-handler", element, RelationsManager.ROLE, contentHandler, contextParameters); 327 } 328 } 329 330 XMLUtils.endElement(contentHandler, "relations-handlers"); 331 contentHandler.endPrefixMapping("i18n"); 332 } 333 334 /** 335 * SAX the widgets 336 * @param contextParameters the context parameters 337 * @throws SAXException if an error occurred 338 */ 339 protected void saxWidgets(Map<String, Object> contextParameters) throws SAXException 340 { 341 contentHandler.startPrefixMapping("i18n", "http://apache.org/cocoon/i18n/2.1"); 342 343 Map<String, Map<String, Map<String, String>>> defaultWidgets = _widgetsManager.getDefaultWidgets(); 344 AttributesImpl wattrs = new AttributesImpl(); 345 wattrs.addCDATAAttribute("default-widgets", _jsonUtils.convertObjectToJson(defaultWidgets)); 346 347 XMLUtils.startElement(contentHandler, "widgets", wattrs); 348 349 for (String extensionId: _widgetsManager.getExtensionsIds()) 350 { 351 ClientSideWidget element = _widgetsManager.getExtension(extensionId); 352 353 AttributesImpl attrs = new AttributesImpl(); 354 attrs.addCDATAAttribute("ftypes", StringUtils.join(element.getFormTypes(contextParameters), ",")); 355 attrs.addCDATAAttribute("supports-enumerated", Boolean.toString(element.supportsEnumerated(contextParameters))); 356 attrs.addCDATAAttribute("supports-non-enumerated", Boolean.toString(element.supportsNonEnumerated(contextParameters))); 357 attrs.addCDATAAttribute("supports-multiple", Boolean.toString(element.supportsMultiple(contextParameters))); 358 attrs.addCDATAAttribute("supports-non-multiple", Boolean.toString(element.supportsNonMultiple(contextParameters))); 359 360 XMLUtils.startElement(contentHandler, "widget-wrapper", attrs); 361 _saxClientSideElementHelper.saxDefinition("widget", element, WidgetsManager.ROLE, contentHandler, contextParameters); 362 XMLUtils.endElement(contentHandler, "widget-wrapper"); 363 } 364 365 XMLUtils.endElement(contentHandler, "widgets"); 366 contentHandler.endPrefixMapping("i18n"); 367 } 368 369 /** 370 * SAX the static file imports 371 * @param contextParameters the context parameters 372 * @param elements The list of static file imports elements 373 * @throws SAXException if an error occurred 374 */ 375 protected void saxStaticFileImports (Map<String, Object> contextParameters, List<ClientSideElement> elements) throws SAXException 376 { 377 XMLUtils.startElement(contentHandler, "static-imports"); 378 if (elements != null) 379 { 380 for (ClientSideElement element : elements) 381 { 382 _saxClientSideElementHelper.saxDefinition("import", element, StaticFileImportsManager.ROLE, contentHandler, contextParameters); 383 } 384 } 385 XMLUtils.endElement(contentHandler, "static-imports"); 386 } 387 388 /** 389 * Use this method when inheriting the WorkspaceGenerator to sax additional data 390 * @param contextParameters the context parameters 391 * @throws SAXException if an error occurred 392 */ 393 protected void saxAdditionnalInfo(Map<String, Object> contextParameters) throws SAXException 394 { 395 if (PluginsManager.getInstance().isSafeMode()) 396 { 397 XMLUtils.createElement(contentHandler, "safe-mode", PluginsManager.getInstance().getStatus().toString()); 398 } 399 } 400}