001/* 002 * Copyright 2012 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 */ 016 017package org.ametys.core.util; 018 019import java.util.ArrayList; 020import java.util.Arrays; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.Set; 025 026import org.apache.avalon.framework.context.Context; 027import org.apache.avalon.framework.context.ContextException; 028import org.apache.avalon.framework.context.Contextualizable; 029import org.apache.avalon.framework.service.ServiceException; 030import org.apache.avalon.framework.service.ServiceManager; 031import org.apache.avalon.framework.service.Serviceable; 032import org.apache.cocoon.components.ContextHelper; 033import org.apache.cocoon.environment.Request; 034import org.apache.cocoon.xml.dom.DOMBuilder; 035import org.apache.commons.lang.StringEscapeUtils; 036import org.apache.commons.lang3.StringUtils; 037import org.w3c.dom.Node; 038import org.w3c.dom.NodeList; 039import org.xml.sax.SAXException; 040 041import org.ametys.core.DevMode; 042import org.ametys.core.group.Group; 043import org.ametys.core.group.GroupIdentity; 044import org.ametys.core.group.GroupManager; 045import org.ametys.core.user.CurrentUserProvider; 046import org.ametys.core.user.User; 047import org.ametys.core.user.UserIdentity; 048import org.ametys.core.user.UserManager; 049import org.ametys.core.util.dom.AmetysNodeList; 050import org.ametys.core.util.dom.MapElement; 051import org.ametys.core.util.dom.StringElement; 052import org.ametys.core.version.Version; 053import org.ametys.core.version.VersionsHandler; 054import org.ametys.plugins.core.user.UserHelper; 055import org.ametys.runtime.config.Config; 056import org.ametys.runtime.i18n.I18nizableText; 057import org.ametys.runtime.parameter.ParameterHelper; 058import org.ametys.runtime.servlet.RuntimeConfig; 059import org.ametys.runtime.workspace.WorkspaceManager; 060import org.ametys.runtime.workspace.WorkspaceMatcher; 061 062/** 063 * Helper component to be used from XSL stylesheets. 064 */ 065public class AmetysXSLTHelper implements Contextualizable, Serviceable 066{ 067 /** The i18n utils instance */ 068 protected static I18nUtils _i18nUtils; 069 070 /** The versions handler */ 071 protected static VersionsHandler _versionHandler; 072 073 /** The current user provider */ 074 protected static CurrentUserProvider _currentUserProvider; 075 /** The users manager */ 076 protected static UserManager _userManager; 077 /** The groups manager */ 078 protected static GroupManager _groupManager; 079 /** The user helper */ 080 protected static UserHelper _userHelper; 081 082 private static Context _context; 083 084 @Override 085 public void contextualize(Context context) throws ContextException 086 { 087 _context = context; 088 } 089 090 public void service(ServiceManager manager) throws ServiceException 091 { 092 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 093 _versionHandler = (VersionsHandler) manager.lookup(VersionsHandler.ROLE); 094 095 _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 096 _userManager = (UserManager) manager.lookup(UserManager.ROLE); 097 _groupManager = (GroupManager) manager.lookup(GroupManager.ROLE); 098 _userHelper = (UserHelper) manager.lookup(UserHelper.ROLE); 099 } 100 101 /** 102 * Returns the current URI prefix. 103 * @return the current URI prefix. 104 */ 105 public static String uriPrefix() 106 { 107 return uriPrefix(true); 108 } 109 110 /** 111 * Returns the current URI prefix. 112 * @param withWorkspaceURI true to add the workspace URI (recommended) 113 * @return the current URI prefix. 114 */ 115 public static String uriPrefix(boolean withWorkspaceURI) 116 { 117 return getUriPrefix(withWorkspaceURI); 118 } 119 120 /** 121 * Returns the absolute URI prefix. 122 * @return the absolute URI prefix. 123 */ 124 public static String absoluteUriPrefix() 125 { 126 return absoluteUriPrefix(true); 127 } 128 129 /** 130 * Returns the absolute URI prefix. 131 * @param withWorkspaceURI true to add the workspace URI (recommended) 132 * @return the absolute URI prefix. 133 */ 134 public static String absoluteUriPrefix(boolean withWorkspaceURI) 135 { 136 return getAbsoluteUriPrefix(withWorkspaceURI); 137 } 138 139 /** 140 * Return the current workspace name 141 * @return The workspace name. Cannot be empty. 142 */ 143 public static String workspaceName() 144 { 145 return getWorkspaceName(); 146 } 147 148 /** 149 * Return the current workspace URI 150 * @return The workspace name. Can be empty. 151 */ 152 public static String workspacePrefix() 153 { 154 return getWorkspacePrefix(); 155 } 156 157 /** 158 * Return the current workspace theme name 159 * @return The name 160 */ 161 public static String workspaceTheme() 162 { 163 Request request = ContextHelper.getRequest(_context); 164 return (String) request.getAttribute(WorkspaceMatcher.WORKSPACE_THEME); 165 } 166 167 /** 168 * Return the current workspace theme url 169 * @return The url without any prefix 170 */ 171 public static String workspaceThemeURL() 172 { 173 Request request = ContextHelper.getRequest(_context); 174 175 String workspaceThemeUrl = (String) request.getAttribute(WorkspaceMatcher.WORKSPACE_THEME_URL); 176 if (workspaceThemeUrl == null) 177 { 178 // fallback to the default workspace 179 String workspaceName = RuntimeConfig.getInstance().getDefaultWorkspace(); 180 WorkspaceManager wm = WorkspaceManager.getInstance(); 181 if (wm.getWorkspaceNames().contains(workspaceName)) 182 { 183 workspaceThemeUrl = wm.getWorkspaces().get(workspaceName).getThemeURL(); 184 } 185 } 186 187 return workspaceThemeUrl; 188 } 189 190 /** 191 * Get the application context path. Can be empty if the application 192 * resides in the root context. Use it to create a link beginning with 193 * the application root. 194 * @param withWorkspaceURI true to add the workspace URI (recommended) 195 * @return The application context path with workspace URI 196 * @see Request#getContextPath() 197 */ 198 protected static String getUriPrefix(boolean withWorkspaceURI) 199 { 200 Request request = ContextHelper.getRequest(_context); 201 String workspaceURI = withWorkspaceURI ? getWorkspacePrefix() : ""; 202 203 return request.getContextPath() + workspaceURI; 204 } 205 206 /** 207 * Get the absolutized version of the context path. Use it to create an absolute 208 * link beginning with the application root, for instance when sending a mail 209 * linking to the application. 210 * @param withWorkspaceURI true to add the workspace URI (recommended) 211 * @return The absolute context path. 212 */ 213 protected static String getAbsoluteUriPrefix(boolean withWorkspaceURI) 214 { 215 Request request = ContextHelper.getRequest(_context); 216 217 String uriPrefix = getUriPrefix(withWorkspaceURI); 218 219 if (!uriPrefix.startsWith("http")) 220 { 221 uriPrefix = request.getScheme() + "://" + request.getServerName() + (request.getServerPort() != 80 ? ":" + request.getServerPort() : "") + uriPrefix; 222 } 223 224 return uriPrefix; 225 } 226 227 /** 228 * Return the current workspace name 229 * @return The workspace name. Cannot be empty. 230 */ 231 protected static String getWorkspaceName() 232 { 233 Request request = ContextHelper.getRequest(_context); 234 return (String) request.getAttribute(WorkspaceMatcher.WORKSPACE_NAME); 235 } 236 237 /** 238 * Return the current workspace URI 239 * @return The workspace name. Can be empty for the default workspace. 240 */ 241 protected static String getWorkspacePrefix() 242 { 243 Request request = ContextHelper.getRequest(_context); 244 return (String) request.getAttribute(WorkspaceMatcher.WORKSPACE_URI); 245 } 246 247 /** 248 * Returns the configuration value associated with the given parameter. 249 * @param id the configuration parameter. 250 * @return the configuration value associated with the given parameter. 251 */ 252 public static String config(String id) 253 { 254 if (Config.getInstance() != null) 255 { 256 return Config.getInstance().getValueAsString(id); 257 } 258 else 259 { 260 return null; 261 } 262 } 263 264 /** 265 * Return the value of a request parameter. 266 * @param parameter the parameter name. 267 * @return the request parameter. 268 */ 269 public static String requestParameter(String parameter) 270 { 271 Request request = ContextHelper.getRequest(_context); 272 return request.getParameter(parameter); 273 } 274 275 /** 276 * Translate an i18n key using current user language. 277 * @param key The key to translate. Specify the catalog this way: "catalogue:KEY" 278 * @return The translation or null. 279 */ 280 public static String translate(String key) 281 { 282 return translate(key, null, null); 283 } 284 285 /** 286 * Translate an i18n key 287 * @param key The key to translate. Specify the catalog this way: "catalogue:KEY" 288 * @param lang The language. Can be null to use current user language. 289 * @param parameters The key parameters. Can be empty. 290 * @return The translation or null. 291 */ 292 public static String translate(String key, String lang, String[] parameters) 293 { 294 List<String> parametersAsString = parameters != null ? Arrays.asList(parameters) : null; 295 296 I18nizableText i18nKey = new I18nizableText(null, key, parametersAsString); 297 return _i18nUtils.translate(i18nKey, lang); 298 } 299 300 /** 301 * Escape the given string to be used as JS variable. 302 * @param str the string to escape. 303 * @return the escaped String. 304 */ 305 public static String escapeJS(String str) 306 { 307 return StringEscapeUtils.escapeJavaScript(str); 308 } 309 310 /** 311 * Encode the string to be url compliant 312 * @param url The url to encode 313 * @return The encoded url 314 */ 315 public static String urlEncode(String url) 316 { 317 return URLEncoder.encodePath(url); 318 } 319 320 /** 321 * Split the text. 322 * @param textToSplit the text to split. 323 * @param tokenizers the tokenizer characters. 324 * @param startIndex the minimum number of characters of the result string 325 * @return the split text. 326 */ 327 public static String splitText(String textToSplit, String tokenizers, int startIndex) 328 { 329 String tokenizableText = textToSplit.substring(startIndex != 0 ? startIndex - 1 : 0, textToSplit.length()); 330 331 int tokenPlace = StringUtils.indexOfAny(tokenizableText, tokenizers); 332 333 if (tokenPlace == -1) 334 { 335 return textToSplit; 336 } 337 else 338 { 339 return textToSplit.substring(0, startIndex - 1 + tokenPlace); 340 } 341 } 342 343 /** 344 * Split the text. 345 * @param textToSplit the text to split. 346 * @param tokenizers the tokenizer characters. 347 * @param maxCharacters the maximum number of characters of the result string 348 * @param currentCharactersNumber the current character number. 349 * @return the split text. 350 */ 351 @Deprecated 352 public static String splitText(String textToSplit, String tokenizers, int maxCharacters, int currentCharactersNumber) 353 { 354 int tokenStartIndex = maxCharacters - currentCharactersNumber - 1; 355 String tokenizableText = textToSplit.substring(tokenStartIndex, textToSplit.length()); 356 357 int tokenPlace = StringUtils.indexOfAny(tokenizableText, tokenizers); 358 359 if (tokenPlace == -1) 360 { 361 return textToSplit; 362 } 363 else 364 { 365 return textToSplit.substring(0, tokenStartIndex + tokenPlace); 366 } 367 } 368 369 /** 370 * Get the versions of the application. 371 * Default VersionsHandler impl will return Ametys and Application versions 372 * @return The versions <Version><Version><Name>X</Name><Version>X</Version><Date>X</Date></Version></Versions> (empty tags are removed) 373 */ 374 public static Node versions() 375 { 376 Map<String, Object> versionsMap = new HashMap<>(); 377 378 List<Object> versionList = new ArrayList<>(); 379 380 for (Version version : _versionHandler.getVersions()) 381 { 382 Map<String, Object> versionMap = new HashMap<>(); 383 384 String componentName = version.getName(); 385 String componentVersion = version.getVersion(); 386 String componentDate = ParameterHelper.valueToString(version.getDate()); 387 388 if (StringUtils.isNotEmpty(componentName)) 389 { 390 versionMap.put("Name", componentName); 391 } 392 if (StringUtils.isNotEmpty(componentVersion)) 393 { 394 versionMap.put("Version", componentVersion); 395 } 396 if (StringUtils.isNotEmpty(componentDate)) 397 { 398 versionMap.put("Date", componentDate); 399 } 400 401 versionList.add(versionMap); 402 } 403 404 versionsMap.put("Component", versionList); 405 406 return new MapElement("Versions", versionsMap); 407 } 408 409 /** 410 * Get the current mode of the application for the current user. 411 * @return True if the application is in developer mode, false if in production mode. 412 */ 413 public static boolean isDeveloperMode() 414 { 415 Request request = ContextHelper.getRequest(_context); 416 417 return DevMode.isDeveloperMode(request); 418 } 419 420 /** 421 * Return the user 422 * @return The current connected user object or null 423 * @throws SAXException if a problem occured while getting the user 424 */ 425 public static Node user() throws SAXException 426 { 427 DOMBuilder domBuilder = new DOMBuilder(); 428 429 UserIdentity userIdentity = _currentUserProvider.getUser(); 430 if (userIdentity != null) 431 { 432 User user = _userManager.getUser(userIdentity.getPopulationId(), userIdentity.getLogin()); 433 if (user != null) 434 { 435 _userHelper.saxUser(user, domBuilder); 436 } 437 } 438 439 return domBuilder.getDocument(); 440 } 441 442 /** 443 * Returns the list of the current user's groups. 444 * @return the list of the current user's groups. Can be null if there is no connected user. 445 */ 446 public static NodeList groups() 447 { 448 UserIdentity userIdentity = _currentUserProvider.getUser(); 449 return userIdentity != null ? groups(userIdentity.getLogin(), userIdentity.getPopulationId()) : null; 450 } 451 452 /** 453 * Returns the of the given user's group. 454 * @param login the concerned user's login. 455 * @param populationId the concerned user's population. 456 * @return the of the given user's group. 457 */ 458 public static NodeList groups(String login, String populationId) 459 { 460 ArrayList<Node> groups = new ArrayList<>(); 461 462 Set<GroupIdentity> userGroups = _groupManager.getUserGroups(new UserIdentity(login, populationId)); 463 for (GroupIdentity groupId : userGroups) 464 { 465 Group group = _groupManager.getGroup(groupId); 466 if (group != null) 467 { 468 Map<String, String> attributes = new HashMap<>(); 469 attributes.put("name", groupId.getId()); 470 attributes.put("directory", groupId.getDirectoryId()); 471 groups.add(new StringElement("group", attributes, group.getLabel())); 472 } 473 } 474 475 return new AmetysNodeList(groups); 476 } 477}