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.Collection; 021import java.util.Date; 022import java.util.HashMap; 023import java.util.List; 024import java.util.Map; 025import java.util.Set; 026 027import org.apache.avalon.framework.context.Context; 028import org.apache.avalon.framework.context.ContextException; 029import org.apache.avalon.framework.context.Contextualizable; 030import org.apache.avalon.framework.service.ServiceException; 031import org.apache.avalon.framework.service.ServiceManager; 032import org.apache.avalon.framework.service.Serviceable; 033import org.apache.cocoon.components.ContextHelper; 034import org.apache.cocoon.environment.Request; 035import org.apache.cocoon.xml.dom.DOMBuilder; 036import org.apache.commons.lang.StringEscapeUtils; 037import org.apache.commons.lang3.StringUtils; 038import org.slf4j.Logger; 039import org.slf4j.LoggerFactory; 040import org.w3c.dom.Node; 041import org.w3c.dom.NodeList; 042import org.xml.sax.SAXException; 043 044import org.ametys.core.DevMode; 045import org.ametys.core.DevMode.DEVMODE; 046import org.ametys.core.group.Group; 047import org.ametys.core.group.GroupIdentity; 048import org.ametys.core.group.GroupManager; 049import org.ametys.core.right.RightManager; 050import org.ametys.core.right.RightManager.RightResult; 051import org.ametys.core.user.CurrentUserProvider; 052import org.ametys.core.user.User; 053import org.ametys.core.user.UserIdentity; 054import org.ametys.core.util.dom.AmetysNodeList; 055import org.ametys.core.util.dom.MapElement; 056import org.ametys.core.util.dom.StringElement; 057import org.ametys.core.version.Version; 058import org.ametys.core.version.VersionsHandler; 059import org.ametys.plugins.core.user.UserHelper; 060import org.ametys.runtime.config.Config; 061import org.ametys.runtime.i18n.I18nizableText; 062import org.ametys.runtime.servlet.RuntimeConfig; 063import org.ametys.runtime.workspace.WorkspaceManager; 064import org.ametys.runtime.workspace.WorkspaceMatcher; 065 066/** 067 * Helper component to be used from XSL stylesheets. 068 */ 069public class AmetysXSLTHelper implements Contextualizable, Serviceable 070{ 071 /** The logger */ 072 protected static final Logger _LOGGER = LoggerFactory.getLogger(AmetysXSLTHelper.class.getName()); 073 074 /** The i18n utils instance */ 075 protected static I18nUtils _i18nUtils; 076 077 /** The versions handler */ 078 protected static VersionsHandler _versionHandler; 079 080 /** The current user provider */ 081 protected static CurrentUserProvider _currentUserProvider; 082 /** The groups manager */ 083 protected static GroupManager _groupManager; 084 /** The user helper */ 085 protected static UserHelper _userHelper; 086 /** The json utils */ 087 protected static JSONUtils _jsonUtils; 088 /** The right manager */ 089 protected static RightManager _rightManager; 090 091 private static Context _context; 092 093 @Override 094 public void contextualize(Context context) throws ContextException 095 { 096 _context = context; 097 } 098 099 public void service(ServiceManager manager) throws ServiceException 100 { 101 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 102 _versionHandler = (VersionsHandler) manager.lookup(VersionsHandler.ROLE); 103 104 _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 105 _groupManager = (GroupManager) manager.lookup(GroupManager.ROLE); 106 _userHelper = (UserHelper) manager.lookup(UserHelper.ROLE); 107 _jsonUtils = (JSONUtils) manager.lookup(JSONUtils.ROLE); 108 _rightManager = (RightManager) manager.lookup(RightManager.ROLE); 109 } 110 111 /** 112 * Returns the current URI prefix. 113 * @return the current URI prefix. 114 */ 115 public static String uriPrefix() 116 { 117 return uriPrefix(true); 118 } 119 120 /** 121 * Returns the current URI prefix. 122 * @param withWorkspaceURI true to add the workspace URI (recommended) 123 * @return the current URI prefix. 124 */ 125 public static String uriPrefix(boolean withWorkspaceURI) 126 { 127 return getUriPrefix(withWorkspaceURI); 128 } 129 130 /** 131 * Returns the absolute URI prefix. 132 * @return the absolute URI prefix. 133 */ 134 public static String absoluteUriPrefix() 135 { 136 return absoluteUriPrefix(true); 137 } 138 139 /** 140 * Returns the absolute URI prefix. 141 * @param withWorkspaceURI true to add the workspace URI (recommended) 142 * @return the absolute URI prefix. 143 */ 144 public static String absoluteUriPrefix(boolean withWorkspaceURI) 145 { 146 return getAbsoluteUriPrefix(withWorkspaceURI); 147 } 148 149 /** 150 * Return the current workspace name 151 * @return The workspace name. Cannot be empty. 152 */ 153 public static String workspaceName() 154 { 155 return getWorkspaceName(); 156 } 157 158 /** 159 * Return the current workspace URI 160 * @return The workspace name. Can be empty. 161 */ 162 public static String workspacePrefix() 163 { 164 return getWorkspacePrefix(); 165 } 166 167 /** 168 * Return the current workspace theme name 169 * @return The name 170 */ 171 public static String workspaceTheme() 172 { 173 Request request = ContextHelper.getRequest(_context); 174 return (String) request.getAttribute(WorkspaceMatcher.WORKSPACE_THEME); 175 } 176 177 /** 178 * Return the current workspace theme url 179 * @return The url without any prefix 180 */ 181 public static String workspaceThemeURL() 182 { 183 Request request = ContextHelper.getRequest(_context); 184 185 String workspaceThemeUrl = (String) request.getAttribute(WorkspaceMatcher.WORKSPACE_THEME_URL); 186 if (workspaceThemeUrl == null) 187 { 188 // fallback to the default workspace 189 String workspaceName = RuntimeConfig.getInstance().getDefaultWorkspace(); 190 WorkspaceManager wm = WorkspaceManager.getInstance(); 191 if (wm.getWorkspaceNames().contains(workspaceName)) 192 { 193 workspaceThemeUrl = wm.getWorkspaces().get(workspaceName).getThemeURL(); 194 } 195 } 196 197 return workspaceThemeUrl; 198 } 199 200 /** 201 * Get the application context path. Can be empty if the application 202 * resides in the root context. Use it to create a link beginning with 203 * the application root. 204 * @param withWorkspaceURI true to add the workspace URI (recommended) 205 * @return The application context path with workspace URI 206 * @see Request#getContextPath() 207 */ 208 protected static String getUriPrefix(boolean withWorkspaceURI) 209 { 210 Request request = ContextHelper.getRequest(_context); 211 String workspaceURI = withWorkspaceURI ? getWorkspacePrefix() : ""; 212 213 return request.getContextPath() + workspaceURI; 214 } 215 216 /** 217 * Get the absolutized version of the context path. Use it to create an absolute 218 * link beginning with the application root, for instance when sending a mail 219 * linking to the application. 220 * @param withWorkspaceURI true to add the workspace URI (recommended) 221 * @return The absolute context path. 222 */ 223 protected static String getAbsoluteUriPrefix(boolean withWorkspaceURI) 224 { 225 Request request = ContextHelper.getRequest(_context); 226 227 String uriPrefix = getUriPrefix(withWorkspaceURI); 228 229 if (!uriPrefix.startsWith("http")) 230 { 231 uriPrefix = request.getScheme() + "://" + request.getServerName() + (request.getServerPort() != 80 ? ":" + request.getServerPort() : "") + uriPrefix; 232 } 233 234 return uriPrefix; 235 } 236 237 /** 238 * Return the current workspace name 239 * @return The workspace name. Cannot be empty. 240 */ 241 protected static String getWorkspaceName() 242 { 243 Request request = ContextHelper.getRequest(_context); 244 return (String) request.getAttribute(WorkspaceMatcher.WORKSPACE_NAME); 245 } 246 247 /** 248 * Return the current workspace URI 249 * @return The workspace name. Can be empty for the default workspace. 250 */ 251 protected static String getWorkspacePrefix() 252 { 253 Request request = ContextHelper.getRequest(_context); 254 return (String) request.getAttribute(WorkspaceMatcher.WORKSPACE_URI); 255 } 256 257 /** 258 * Returns the configuration value associated with the given parameter. 259 * @param id the configuration parameter. 260 * @return the configuration value associated with the given parameter. 261 */ 262 public static Object config(String id) 263 { 264 if (Config.getInstance() != null) 265 { 266 return Config.getInstance().getValue(id); 267 } 268 else 269 { 270 return null; 271 } 272 } 273 274 /** 275 * Return the value of a request parameter. 276 * @param parameter the parameter name. 277 * @return the request parameter. 278 */ 279 public static String requestParameter(String parameter) 280 { 281 Request request = ContextHelper.getRequest(_context); 282 return request.getParameter(parameter); 283 } 284 285 /** 286 * Translate an i18n key using current user language. 287 * @param key The key to translate. Specify the catalog this way: "catalogue:KEY" 288 * @return The translation or null. 289 */ 290 public static String translate(String key) 291 { 292 return translate(key, null, null); 293 } 294 295 /** 296 * Translate an i18n key 297 * @param key The key to translate. Specify the catalog this way: "catalogue:KEY" 298 * @param lang The language. Can be null to use current user language. 299 * @param parameters The key parameters. Can be empty. 300 * @return The translation or null. 301 */ 302 public static String translate(String key, String lang, NodeList parameters) 303 { 304 List<String> i18nparams = new ArrayList<>(); 305 if (parameters != null && parameters.getLength() == 1) 306 { 307 NodeList childNodes = parameters.item(0).getChildNodes(); 308 for (int i = 0; i < childNodes.getLength(); i++) 309 { 310 i18nparams.add(childNodes.item(i).getTextContent()); 311 } 312 } 313 314 I18nizableText i18nKey = new I18nizableText(null, key, i18nparams); 315 return _i18nUtils.translate(i18nKey, lang); 316 } 317 318 /** 319 * Escape the given string to be used as JS variable. 320 * @param str the string to escape. 321 * @return the escaped String. 322 */ 323 public static String escapeJS(String str) 324 { 325 return StringEscapeUtils.escapeJavaScript(str); 326 } 327 328 /** 329 * Encode the string to be url compliant 330 * @param url The url to encode 331 * @return The encoded url 332 */ 333 public static String urlEncode(String url) 334 { 335 return URLEncoder.encodePath(url); 336 } 337 338 /** 339 * Split the text. 340 * @param textToSplit the text to split. 341 * @param tokenizers the tokenizer characters. 342 * @param startIndex the minimum number of characters of the result string 343 * @return the split text. 344 */ 345 public static String splitText(String textToSplit, String tokenizers, int startIndex) 346 { 347 String tokenizableText = textToSplit.substring(startIndex != 0 ? startIndex - 1 : 0, textToSplit.length()); 348 349 int tokenPlace = StringUtils.indexOfAny(tokenizableText, tokenizers); 350 351 if (tokenPlace == -1) 352 { 353 return textToSplit; 354 } 355 else 356 { 357 return textToSplit.substring(0, startIndex - 1 + tokenPlace); 358 } 359 } 360 361 /** 362 * Split the text. 363 * @param textToSplit the text to split. 364 * @param tokenizers the tokenizer characters. 365 * @param maxCharacters the maximum number of characters of the result string 366 * @param currentCharactersNumber the current character number. 367 * @return the split text. 368 */ 369 @Deprecated 370 public static String splitText(String textToSplit, String tokenizers, int maxCharacters, int currentCharactersNumber) 371 { 372 int tokenStartIndex = maxCharacters - currentCharactersNumber - 1; 373 String tokenizableText = textToSplit.substring(tokenStartIndex, textToSplit.length()); 374 375 int tokenPlace = StringUtils.indexOfAny(tokenizableText, tokenizers); 376 377 if (tokenPlace == -1) 378 { 379 return textToSplit; 380 } 381 else 382 { 383 return textToSplit.substring(0, tokenStartIndex + tokenPlace); 384 } 385 } 386 387 /** 388 * Get the versions of the application. 389 * Default VersionsHandler impl will return Ametys and Application versions 390 * @return The versions <Version><Version><Name>X</Name><Version>X</Version><Date>X</Date></Version></Versions> (empty tags are removed) 391 */ 392 public static Node versions() 393 { 394 Map<String, Object> versionsMap = new HashMap<>(); 395 396 List<Object> versionList = new ArrayList<>(); 397 398 for (Version version : _versionHandler.getVersions()) 399 { 400 Map<String, Object> versionMap = new HashMap<>(); 401 402 String componentName = version.getName(); 403 String componentVersion = version.getVersion(); 404 String componentDate = DateUtils.dateToString(version.getDate()); 405 406 if (StringUtils.isNotEmpty(componentName)) 407 { 408 versionMap.put("Name", componentName); 409 } 410 if (StringUtils.isNotEmpty(componentVersion)) 411 { 412 versionMap.put("Version", componentVersion); 413 } 414 if (StringUtils.isNotEmpty(componentDate)) 415 { 416 versionMap.put("Date", componentDate); 417 } 418 419 versionList.add(versionMap); 420 } 421 422 versionsMap.put("Component", versionList); 423 424 return new MapElement("Versions", versionsMap); 425 } 426 427 /** 428 * Get the current mode of the application for the current user. 429 * @return True if the application is in developer mode, false if in production mode. 430 */ 431 public static boolean isDeveloperMode() 432 { 433 Request request = ContextHelper.getRequest(_context); 434 435 DEVMODE developerMode = DevMode.getDeveloperMode(request); 436 return developerMode == DEVMODE.DEVELOPMENT 437 || developerMode == DEVMODE.SUPER_DEVELOPPMENT; 438 } 439 440 /** 441 * Return the user 442 * @return The current connected user object or null 443 * @throws SAXException if a problem occured while getting the user 444 */ 445 public static Node user() throws SAXException 446 { 447 UserIdentity userIdentity = _currentUserProvider.getUser(); 448 if (userIdentity != null) 449 { 450 return user(userIdentity.getLogin(), userIdentity.getPopulationId()); 451 } 452 453 return null; 454 } 455 456 /** 457 * Return the given user 458 * @param userIdentity the concerned user's login + population 459 * @return The informations about the given user 460 * @throws SAXException If an error occurred while saxing the user 461 */ 462 public static Node user(String userIdentity) throws SAXException 463 { 464 UserIdentity userIdentityObject = UserIdentity.stringToUserIdentity(userIdentity); 465 if (userIdentityObject == null) 466 { 467 return null; 468 } 469 else 470 { 471 return user(userIdentityObject.getLogin(), userIdentityObject.getPopulationId()); 472 } 473 } 474 475 /** 476 * Return the given user 477 * @param login the concerned user's login 478 * @param populationId the concerned user's population id 479 * @return The informations about the given user 480 * @throws SAXException If an error occurred while saxing the user 481 */ 482 public static Node user(String login, String populationId) throws SAXException 483 { 484 DOMBuilder domBuilder = new DOMBuilder(); 485 486 UserIdentity userIdentity = new UserIdentity(login, populationId); 487 _userHelper.saxUserIdentity(userIdentity, domBuilder); 488 489 return domBuilder.getDocument(); 490 } 491 492 /** 493 * Return the given user 494 * @param email the concerned user's email 495 * @param populationId the concerned user's population id 496 * @return The informations about the given user 497 * @throws SAXException If an error occurred while saxing the user 498 */ 499 public static Node userByMail(String email, String populationId) throws SAXException 500 { 501 User user = _userHelper.getUserByEmail(populationId, email); 502 if (user != null) 503 { 504 return user(UserIdentity.userIdentityToString(user.getIdentity())); 505 } 506 return null; 507 } 508 509 /** 510 * Returns the list of the current user's groups. 511 * @return the list of the current user's groups. Can be null if there is no connected user. 512 */ 513 public static NodeList groups() 514 { 515 UserIdentity userIdentity = _currentUserProvider.getUser(); 516 return userIdentity != null ? groups(userIdentity.getLogin(), userIdentity.getPopulationId()) : null; 517 } 518 519 /** 520 * Returns the of the given user's group. 521 * @param userIdentity the concerned user's login + population 522 * @return the of the given user's group. 523 */ 524 public static NodeList groups(String userIdentity) 525 { 526 UserIdentity userIdentityObject = UserIdentity.stringToUserIdentity(userIdentity); 527 if (userIdentityObject == null) 528 { 529 return null; 530 } 531 else 532 { 533 return groups(userIdentityObject.getLogin(), userIdentityObject.getPopulationId()); 534 } 535 } 536 537 /** 538 * Returns the of the given user's group. 539 * @param login the concerned user's login. 540 * @param populationId the concerned user's population. 541 * @return the of the given user's group. 542 */ 543 public static NodeList groups(String login, String populationId) 544 { 545 ArrayList<Node> groups = new ArrayList<>(); 546 547 Set<GroupIdentity> userGroups = _groupManager.getUserGroups(new UserIdentity(login, populationId)); 548 for (GroupIdentity groupId : userGroups) 549 { 550 Group group = _groupManager.getGroup(groupId); 551 if (group != null) 552 { 553 Map<String, String> attributes = new HashMap<>(); 554 attributes.put("name", groupId.getId()); 555 attributes.put("directory", groupId.getDirectoryId()); 556 groups.add(new StringElement("group", attributes, group.getLabel())); 557 } 558 } 559 560 return new AmetysNodeList(groups); 561 } 562 563 /** 564 * Parse a JSON string as a Map and return the value with the desired key 565 * @param jsonString the JSON representation of the object. 566 * @param key name of the value to return 567 * @return the value as a String, or empty string if an error occurred or the key was not found. 568 */ 569 public static String getValueFromJsonObject(String jsonString, String key) 570 { 571 try 572 { 573 Map<String, Object> jsonMap = _jsonUtils.convertJsonToMap(jsonString); 574 if (jsonMap.containsKey(key)) 575 { 576 Object value = jsonMap.get(key); 577 if (value instanceof Map || value instanceof Collection) 578 { 579 _LOGGER.warn("Unable to get string value for key '{}' from json object {}: the value can not be a map nor collection", key, jsonString); 580 } 581 else if (value instanceof Date) 582 { 583 return DateUtils.dateToString((Date) value); 584 } 585 else 586 { 587 return value.toString(); 588 } 589 } 590 } 591 catch (Exception e) 592 { 593 _LOGGER.warn("Unable to parse json object {}", jsonString, e); 594 } 595 596 return ""; 597 } 598 599 /** 600 * Determines if the current logged user has right on a String context 601 * @param rightId The id of right 602 * @param objectCtx the context. Can be null to search on any context. 603 * @return true if the current user is allowed, false otherwise 604 */ 605 public static boolean hasRight(String rightId, String objectCtx) 606 { 607 return _rightManager.currentUserHasRight(rightId, objectCtx) == RightResult.RIGHT_ALLOW; 608 } 609}