001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.workplace.tools; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsProperty; 032import org.opencms.file.CmsResource; 033import org.opencms.i18n.CmsEncoder; 034import org.opencms.jsp.CmsJspActionElement; 035import org.opencms.main.CmsException; 036import org.opencms.main.CmsLog; 037import org.opencms.util.CmsRequestUtil; 038import org.opencms.util.CmsStringUtil; 039import org.opencms.workplace.CmsDialog; 040import org.opencms.workplace.CmsWorkplace; 041 042import java.io.IOException; 043import java.util.ArrayList; 044import java.util.HashMap; 045import java.util.Iterator; 046import java.util.List; 047import java.util.Map; 048 049import javax.servlet.ServletException; 050 051import org.apache.commons.logging.Log; 052 053/** 054 * Manages the registered tools, actualizing its state every time the workplace is reinitialize.<p> 055 * 056 * Manages also the configuration settings for the administration view, and provides 057 * several tool related methods.<p> 058 * 059 * @since 6.0.0 060 */ 061public class CmsToolManager { 062 063 /** Root location of the administration view. */ 064 public static final String ADMINVIEW_ROOT_LOCATION = CmsWorkplace.PATH_WORKPLACE + "views/admin"; 065 066 /** Property definition name to look for. */ 067 public static final String HANDLERCLASS_PROPERTY = "admintoolhandler-class"; 068 069 /** Navigation bar separator (html code). */ 070 public static final String NAVBAR_SEPARATOR = "\n > \n"; 071 072 /** Tool root separator. */ 073 public static final String ROOT_SEPARATOR = ":"; 074 075 /** Key for the default tool root, if there is no configured root with this a key, a new one will be configured. */ 076 public static final String ROOTKEY_DEFAULT = "admin"; 077 078 /** Tool path separator. */ 079 public static final String TOOLPATH_SEPARATOR = "/"; 080 081 /** Location of the default admin view jsp page. */ 082 public static final String VIEW_JSPPAGE_LOCATION = ADMINVIEW_ROOT_LOCATION + "/admin-main.jsp"; 083 084 /** The static log object for this class. */ 085 private static final Log LOG = CmsLog.getLog(CmsToolManager.class); 086 087 /** List of all available roots. */ 088 private final CmsIdentifiableObjectContainer<CmsToolRootHandler> m_roots; 089 090 /** List of all available tools. */ 091 private final CmsIdentifiableObjectContainer<CmsTool> m_tools; 092 093 /** List of all available urls and related tool paths. */ 094 private final CmsIdentifiableObjectContainer<String> m_urls; 095 096 /** 097 * Default constructor.<p> 098 */ 099 public CmsToolManager() { 100 101 m_roots = new CmsIdentifiableObjectContainer<CmsToolRootHandler>(true, false); 102 m_tools = new CmsIdentifiableObjectContainer<CmsTool>(true, false); 103 m_urls = new CmsIdentifiableObjectContainer<String>(false, false); 104 } 105 106 /** 107 * Returns the OpenCms link for the given tool path which requires no parameters.<p> 108 * 109 * @param jsp the jsp action element 110 * @param toolPath the tool path 111 * 112 * @return the OpenCms link for the given tool path which requires parameters 113 */ 114 public static String linkForToolPath(CmsJspActionElement jsp, String toolPath) { 115 116 StringBuffer result = new StringBuffer(); 117 result.append(jsp.link(VIEW_JSPPAGE_LOCATION)); 118 result.append('?'); 119 result.append(CmsToolDialog.PARAM_PATH); 120 result.append('='); 121 result.append(CmsEncoder.encode(toolPath)); 122 return result.toString(); 123 } 124 125 /** 126 * Returns the OpenCms link for the given tool path which requires parameters.<p> 127 * 128 * Please note: Don't overuse the parameter map because this will likely introduce issues 129 * with encoding. If possible, don't pass parameters at all, or only very simple parameters 130 * with no special chars that can easily be parsed.<p> 131 * 132 * @param jsp the jsp action element 133 * @param toolPath the tool path 134 * @param params the map of required tool parameters 135 * 136 * @return the OpenCms link for the given tool path which requires parameters 137 */ 138 public static String linkForToolPath(CmsJspActionElement jsp, String toolPath, Map<String, String[]> params) { 139 140 if (params == null) { 141 // no parameters - take the shortcut 142 return linkForToolPath(jsp, toolPath); 143 } 144 params.put(CmsToolDialog.PARAM_PATH, new String[] {toolPath}); 145 return CmsRequestUtil.appendParameters(jsp.link(VIEW_JSPPAGE_LOCATION), params, true); 146 } 147 148 /** 149 * Adds a new tool root to the tool manager.<p> 150 * 151 * @param toolRoot the tool root to add 152 */ 153 public void addToolRoot(CmsToolRootHandler toolRoot) { 154 155 m_roots.addIdentifiableObject(toolRoot.getKey(), toolRoot); 156 } 157 158 /** 159 * Called by the <code>{@link org.opencms.workplace.CmsWorkplaceManager#initialize(CmsObject)}</code> method.<p> 160 * 161 * @param cms the admin cms context 162 */ 163 public void configure(CmsObject cms) { 164 165 if (CmsLog.INIT.isInfoEnabled()) { 166 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_TOOLMANAGER_CREATED_0)); 167 } 168 if (m_roots.getObject(ROOTKEY_DEFAULT) == null) { 169 CmsToolRootHandler defToolRoot = new CmsToolRootHandler(); 170 defToolRoot.setKey(ROOTKEY_DEFAULT); 171 defToolRoot.setUri(CmsWorkplace.PATH_WORKPLACE + "admin/"); 172 defToolRoot.setName("${key." + Messages.GUI_ADMIN_VIEW_ROOT_NAME_0 + "}"); 173 defToolRoot.setHelpText("${key." + Messages.GUI_ADMIN_VIEW_ROOT_HELP_0 + "}"); 174 addToolRoot(defToolRoot); 175 } 176 m_tools.clear(); 177 m_urls.clear(); 178 Iterator<CmsToolRootHandler> it = getToolRoots().iterator(); 179 while (it.hasNext()) { 180 CmsToolRootHandler toolRoot = it.next(); 181 if (!cms.existsResource(toolRoot.getUri())) { 182 if (CmsLog.INIT.isInfoEnabled()) { 183 CmsLog.INIT.info( 184 Messages.get().getBundle().key( 185 Messages.INIT_TOOLMANAGER_ROOT_SKIPPED_2, 186 toolRoot.getKey(), 187 toolRoot.getUri())); 188 } 189 continue; 190 } 191 try { 192 toolRoot.setup(cms, null, toolRoot.getUri()); 193 configureToolRoot(cms, toolRoot); 194 // log info 195 if (CmsLog.INIT.isInfoEnabled()) { 196 CmsLog.INIT.info( 197 Messages.get().getBundle().key(Messages.INIT_TOOLMANAGER_SETUP_1, toolRoot.getKey())); 198 } 199 } catch (CmsException e) { 200 // log failure 201 if (CmsLog.INIT.isWarnEnabled()) { 202 CmsLog.INIT.warn( 203 Messages.get().getBundle().key(Messages.INIT_TOOLMANAGER_SETUP_ERROR_1, toolRoot.getKey()), 204 e); 205 } 206 } 207 } 208 } 209 210 /** 211 * Returns the navigation bar html code for the given tool path.<p> 212 * 213 * @param toolPath the path 214 * @param wp the jsp page 215 * 216 * @return the html code 217 */ 218 public String generateNavBar(String toolPath, CmsWorkplace wp) { 219 220 if (toolPath.equals(getBaseToolPath(wp))) { 221 return "<div class='pathbar'> </div>\n"; 222 } 223 CmsTool adminTool = resolveAdminTool(getCurrentRoot(wp).getKey(), toolPath); 224 String html = A_CmsHtmlIconButton.defaultButtonHtml( 225 CmsHtmlIconButtonStyleEnum.SMALL_ICON_TEXT, 226 "nav" + adminTool.getId(), 227 adminTool.getHandler().getName(), 228 null, 229 false, 230 null, 231 null, 232 null); 233 String parent = toolPath; 234 while (!parent.equals(getBaseToolPath(wp))) { 235 parent = getParent(wp, parent); 236 adminTool = resolveAdminTool(getCurrentRoot(wp).getKey(), parent); 237 if (adminTool == null) { 238 break; 239 } 240 String id = "nav" + adminTool.getId(); 241 String link = linkForToolPath(wp.getJsp(), parent, adminTool.getHandler().getParameters(wp)); 242 String onClic = "openPage('" + link + "');"; 243 String buttonHtml = A_CmsHtmlIconButton.defaultButtonHtml( 244 CmsHtmlIconButtonStyleEnum.SMALL_ICON_TEXT, 245 id, 246 adminTool.getHandler().getName(), 247 adminTool.getHandler().getHelpText(), 248 true, 249 null, 250 null, 251 onClic); 252 html = "<span>" + buttonHtml + NAVBAR_SEPARATOR + "</span>" + html; 253 } 254 html = CmsToolMacroResolver.resolveMacros(html, wp); 255 html = CmsEncoder.decode(html); 256 html = CmsToolMacroResolver.resolveMacros(html, wp); 257 html = "<div class='pathbar'>\n" + html + "</div>\n"; 258 return html; 259 } 260 261 /** 262 * Returns the base tool path for the active user.<p> 263 * 264 * @param wp the workplace object 265 * 266 * @return the base tool path for the active user 267 */ 268 public String getBaseToolPath(CmsWorkplace wp) { 269 270 CmsToolUserData userData = getUserData(wp); 271 String path = TOOLPATH_SEPARATOR; 272 if (userData != null) { 273 path = userData.getBaseTool(getCurrentRoot(wp).getKey()); 274 } 275 return path; 276 } 277 278 /** 279 * Returns the current user's root handler.<p> 280 * 281 * @param wp the workplace context 282 * 283 * @return the current user's root handler 284 */ 285 public CmsToolRootHandler getCurrentRoot(CmsWorkplace wp) { 286 287 CmsToolUserData userData = getUserData(wp); 288 String root = ROOTKEY_DEFAULT; 289 if (userData != null) { 290 if (m_roots.getObject(userData.getRootKey()) != null) { 291 root = userData.getRootKey(); 292 } else { 293 if (LOG.isErrorEnabled()) { 294 LOG.error( 295 Messages.get().getBundle().key(Messages.ERR_NOT_CONFIGURED_ROOT_1, userData.getRootKey())); 296 } 297 } 298 } 299 return m_roots.getObject(root); 300 } 301 302 /** 303 * Returns the current tool.<p> 304 * 305 * @param wp the workplace object 306 * 307 * @return the current tool 308 */ 309 public CmsTool getCurrentTool(CmsWorkplace wp) { 310 311 return resolveAdminTool(getCurrentRoot(wp).getKey(), getCurrentToolPath(wp)); 312 } 313 314 /** 315 * Returns the current tool path.<p> 316 * 317 * @param wp the workplace object 318 * 319 * @return the current tool path 320 */ 321 public String getCurrentToolPath(CmsWorkplace wp) { 322 323 CmsToolUserData userData = getUserData(wp); 324 String path = getBaseToolPath(wp); 325 if (userData != null) { 326 path = userData.getCurrentToolPath(getCurrentRoot(wp).getKey()); 327 } 328 return path; 329 } 330 331 /** 332 * Returns the path to the parent of the tool identified by the given tool path.<p> 333 * 334 * The parent of the root is the same root.<p> 335 * 336 * @param wp the workplace object 337 * @param toolPath the abstract tool path 338 * 339 * @return his parent 340 */ 341 public String getParent(CmsWorkplace wp, String toolPath) { 342 343 if (toolPath.equals(getBaseToolPath(wp))) { 344 return toolPath; 345 } 346 int pos = toolPath.lastIndexOf(TOOLPATH_SEPARATOR); 347 return pos <= 0 ? TOOLPATH_SEPARATOR : toolPath.substring(0, pos); 348 } 349 350 /** 351 * Returns a list with all registered tools.<p> 352 * 353 * @return list if <code>{@link CmsTool}</code> 354 */ 355 public List<CmsTool> getToolHandlers() { 356 357 return m_tools.elementList(); 358 } 359 360 /** 361 * Returns a list of tool roots.<p> 362 * 363 * @return a list of {@link CmsToolRootHandler} objects 364 */ 365 public List<CmsToolRootHandler> getToolRoots() { 366 367 return m_roots.elementList(); 368 } 369 370 /** 371 * Returns a list of all tools in the given path.<p> 372 * 373 * @param wp the workplace context 374 * @param baseTool the path 375 * @param includeSubtools if the tools in subfolders should be also returned 376 * 377 * @return a list of {@link CmsTool} objects 378 */ 379 public List<CmsTool> getToolsForPath(CmsWorkplace wp, String baseTool, boolean includeSubtools) { 380 381 List<CmsTool> toolList = new ArrayList<CmsTool>(); 382 String rootKey = getCurrentRoot(wp).getKey(); 383 Iterator<CmsTool> itTools = m_tools.elementList().iterator(); 384 while (itTools.hasNext()) { 385 CmsTool tool = itTools.next(); 386 String path = tool.getHandler().getPath(); 387 if (resolveAdminTool(rootKey, path) != tool) { 388 continue; 389 } 390 if (path.equals(TOOLPATH_SEPARATOR)) { 391 continue; 392 } 393 // leave out everything above the base 394 if (!path.startsWith(baseTool)) { 395 continue; 396 } 397 // filter for path 398 if (baseTool.equals(TOOLPATH_SEPARATOR) || path.startsWith(baseTool + TOOLPATH_SEPARATOR)) { 399 // filter sub tree 400 if (includeSubtools || (path.indexOf(TOOLPATH_SEPARATOR, baseTool.length() + 1) < 0)) { 401 toolList.add(tool); 402 } 403 } 404 } 405 return toolList; 406 } 407 408 /** 409 * Returns the <code>{@link CmsToolUserData}</code> object for a given user.<p> 410 * 411 * @param wp the workplace object 412 * 413 * @return the current user data 414 */ 415 public CmsToolUserData getUserData(CmsWorkplace wp) { 416 417 CmsToolUserData userData = wp.getSettings().getToolUserData(); 418 if (userData == null) { 419 userData = new CmsToolUserData(); 420 userData.setRootKey(ROOTKEY_DEFAULT); 421 Iterator<CmsToolRootHandler> it = getToolRoots().iterator(); 422 while (it.hasNext()) { 423 CmsToolRootHandler root = it.next(); 424 userData.setCurrentToolPath(root.getKey(), TOOLPATH_SEPARATOR); 425 userData.setBaseTool(root.getKey(), TOOLPATH_SEPARATOR); 426 } 427 wp.getSettings().setToolUserData(userData); 428 } 429 return userData; 430 } 431 432 /** 433 * Returns <code>true</code> if there is at least one tool registered using the given url.<p> 434 * 435 * @param url the url of the tool 436 * 437 * @return <code>true</code> if there is at least one tool registered using the given url 438 */ 439 public boolean hasToolPathForUrl(String url) { 440 441 List<String> toolPaths = m_urls.getObjectList(url); 442 return ((toolPaths != null) && !toolPaths.isEmpty()); 443 } 444 445 /** 446 * This method initializes the tool manager for the current user.<p> 447 * 448 * @param wp the jsp page coming from 449 */ 450 public synchronized void initParams(CmsToolDialog wp) { 451 452 setCurrentRoot(wp, wp.getParamRoot()); 453 setCurrentToolPath(wp, wp.getParamPath()); 454 setBaseToolPath(wp, wp.getParamBase()); 455 456 // if the current tool path is not under the current root, set the current root as the current tool 457 if (!getCurrentToolPath(wp).startsWith(getBaseToolPath(wp))) { 458 setCurrentToolPath(wp, getBaseToolPath(wp)); 459 } 460 wp.setParamPath(getCurrentToolPath(wp)); 461 wp.setParamBase(getBaseToolPath(wp)); 462 wp.setParamRoot(getCurrentRoot(wp).getKey()); 463 } 464 465 /** 466 * Redirects to the given page with the given parameters.<p> 467 * 468 * @param wp the workplace object 469 * @param pagePath the path to the page to redirect to 470 * @param params the parameters to send 471 * 472 * @throws IOException in case of errors during forwarding 473 * @throws ServletException in case of errors during forwarding 474 */ 475 public void jspForwardPage(CmsWorkplace wp, String pagePath, Map<String, String[]> params) 476 throws IOException, ServletException { 477 478 Map<String, String[]> newParams = createToolParams(wp, pagePath, params); 479 if (pagePath.indexOf("?") > 0) { 480 pagePath = pagePath.substring(0, pagePath.indexOf("?")); 481 } 482 483 wp.setForwarded(true); 484 // forward to the requested page uri 485 CmsRequestUtil.forwardRequest( 486 wp.getJsp().link(pagePath), 487 CmsRequestUtil.createParameterMap(newParams), 488 wp.getJsp().getRequest(), 489 wp.getJsp().getResponse()); 490 } 491 492 /** 493 * Redirects to the given tool with the given parameters.<p> 494 * 495 * @param wp the workplace object 496 * @param toolPath the path to the tool to redirect to 497 * @param params the parameters to send 498 * 499 * @throws IOException in case of errors during forwarding 500 * @throws ServletException in case of errors during forwarding 501 */ 502 public void jspForwardTool(CmsWorkplace wp, String toolPath, Map<String, String[]> params) 503 throws IOException, ServletException { 504 505 Map<String, String[]> newParams; 506 if (params == null) { 507 newParams = new HashMap<String, String[]>(); 508 } else { 509 newParams = new HashMap<String, String[]>(params); 510 } 511 // update path param 512 newParams.put(CmsToolDialog.PARAM_PATH, new String[] {toolPath}); 513 jspForwardPage(wp, VIEW_JSPPAGE_LOCATION, newParams); 514 } 515 516 /** 517 * Returns the admin tool corresponding to the given abstract path.<p> 518 * 519 * @param rootKey the tool root 520 * @param toolPath the path 521 * 522 * @return the corresponding tool, or <code>null</code> if not found 523 */ 524 public CmsTool resolveAdminTool(String rootKey, String toolPath) { 525 526 return m_tools.getObject(rootKey + ROOT_SEPARATOR + toolPath); 527 } 528 529 /** 530 * Sets the base tool path.<p> 531 * 532 * @param wp the workplace object 533 * @param baseToolPath the base tool path to set 534 */ 535 public void setBaseToolPath(CmsWorkplace wp, String baseToolPath) { 536 537 // use last used base if param empty 538 if (CmsStringUtil.isEmpty(baseToolPath) || baseToolPath.trim().equals("null")) { 539 baseToolPath = getBaseToolPath(wp); 540 } 541 baseToolPath = repairPath(wp, baseToolPath); 542 // set it 543 CmsToolUserData userData = getUserData(wp); 544 userData.setBaseTool(userData.getRootKey(), baseToolPath); 545 } 546 547 /** 548 * Sets the current user's root key.<p> 549 * 550 * @param wp the workplace context 551 * @param key the current user's root key to set 552 */ 553 public void setCurrentRoot(CmsWorkplace wp, String key) { 554 555 // use last used root if param empty 556 if (CmsStringUtil.isEmpty(key) || key.trim().equals("null")) { 557 key = getCurrentRoot(wp).getKey(); 558 } 559 // set it 560 CmsToolUserData userData = getUserData(wp); 561 userData.setRootKey(key); 562 } 563 564 /** 565 * Sets the current tool path.<p> 566 * 567 * @param wp the workplace object 568 * @param currentToolPath the current tool path to set 569 */ 570 public void setCurrentToolPath(CmsWorkplace wp, String currentToolPath) { 571 572 // use last used path if param empty 573 if (CmsStringUtil.isEmptyOrWhitespaceOnly(currentToolPath) || currentToolPath.trim().equals("null")) { 574 currentToolPath = getCurrentToolPath(wp); 575 } 576 currentToolPath = repairPath(wp, currentToolPath); 577 // use it 578 CmsToolUserData userData = getUserData(wp); 579 userData.setCurrentToolPath(userData.getRootKey(), currentToolPath); 580 } 581 582 /** 583 * Configures a whole tool root with all its tools.<p> 584 * 585 * @param cms the cms context 586 * @param toolRoot the tool root to configure 587 * 588 * @throws CmsException if something goes wrong 589 */ 590 private void configureToolRoot(CmsObject cms, CmsToolRootHandler toolRoot) throws CmsException { 591 592 List<I_CmsToolHandler> handlers = new ArrayList<I_CmsToolHandler>(); 593 594 // add tool root handler 595 handlers.add(toolRoot); 596 597 // look in every file under the root uri for valid 598 // admin tools and register them 599 List<CmsResource> resources = cms.readResourcesWithProperty(toolRoot.getUri(), HANDLERCLASS_PROPERTY); 600 Iterator<CmsResource> itRes = resources.iterator(); 601 while (itRes.hasNext()) { 602 CmsResource res = itRes.next(); 603 CmsProperty prop = cms.readPropertyObject(res.getRootPath(), HANDLERCLASS_PROPERTY, false); 604 if (!prop.isNullProperty()) { 605 try { 606 // instantiate the handler 607 Class<?> handlerClass = Class.forName(prop.getValue()); 608 I_CmsToolHandler handler = (I_CmsToolHandler)handlerClass.newInstance(); 609 610 if (!handler.setup(cms, toolRoot, res.getRootPath())) { 611 // log failure 612 if (CmsLog.INIT.isWarnEnabled()) { 613 CmsLog.INIT.warn( 614 Messages.get().getBundle().key( 615 Messages.INIT_TOOLMANAGER_TOOL_SETUP_ERROR_1, 616 res.getRootPath())); 617 } 618 } 619 620 // keep for later use 621 handlers.add(handler); 622 // log success 623 if (CmsLog.INIT.isDebugEnabled()) { 624 if (!handler.getLink().equals(VIEW_JSPPAGE_LOCATION)) { 625 CmsLog.INIT.debug( 626 Messages.get().getBundle().key( 627 Messages.INIT_TOOLMANAGER_NEWTOOL_FOUND_2, 628 handler.getPath(), 629 handler.getLink())); 630 } else { 631 CmsLog.INIT.debug( 632 Messages.get().getBundle().key( 633 Messages.INIT_TOOLMANAGER_NEWTOOL_FOUND_2, 634 handler.getPath(), 635 res.getRootPath())); 636 } 637 } 638 } catch (Exception e) { 639 // log failure 640 if (CmsLog.INIT.isWarnEnabled()) { 641 CmsLog.INIT.warn( 642 Messages.get().getBundle().key( 643 Messages.INIT_TOOLMANAGER_TOOL_SETUP_ERROR_1, 644 res.getRootPath()), 645 e); 646 } 647 } 648 } 649 } 650 registerHandlerList(cms, toolRoot, 1, handlers); 651 } 652 653 /** 654 * Creates a parameter map from the given url and additional parameters.<p> 655 * 656 * @param wp the workplace context 657 * @param url the url to create the parameter map for (extracting query params) 658 * @param params additional parameter map 659 * 660 * @return the new parameter map 661 */ 662 private Map<String, String[]> createToolParams(CmsWorkplace wp, String url, Map<String, String[]> params) { 663 664 Map<String, String[]> newParams = new HashMap<String, String[]>(); 665 // add query parameters to the parameter map if required 666 if (url.indexOf("?") > 0) { 667 String query = url.substring(url.indexOf("?")); 668 Map<String, String[]> reqParameters = CmsRequestUtil.createParameterMap(query); 669 newParams.putAll(reqParameters); 670 } 671 if (params != null) { 672 newParams.putAll(params); 673 } 674 675 // put close link if not set 676 if (!newParams.containsKey(CmsDialog.PARAM_CLOSELINK)) { 677 Map<String, String[]> argMap = resolveAdminTool( 678 getCurrentRoot(wp).getKey(), 679 getCurrentToolPath(wp)).getHandler().getParameters(wp); 680 newParams.put( 681 CmsDialog.PARAM_CLOSELINK, 682 new String[] {linkForToolPath(wp.getJsp(), getCurrentToolPath(wp), argMap)}); 683 } 684 return newParams; 685 } 686 687 /** 688 * Registers a new tool at a given install point for the given tool root.<p> 689 * 690 * @param cms the cms context object 691 * @param toolRoot the tool root 692 * @param handler the handler to install 693 */ 694 private void registerAdminTool(CmsObject cms, CmsToolRootHandler toolRoot, I_CmsToolHandler handler) { 695 696 String link = handler.getLink(); 697 if (link.indexOf("?") > 0) { 698 link = link.substring(0, link.indexOf("?")); 699 } 700 // check visibility 701 if (!cms.existsResource(link)) { 702 return; 703 } 704 705 //validate path 706 if (!validatePath(toolRoot.getKey(), handler.getPath(), false)) { 707 // log failure 708 if (CmsLog.INIT.isWarnEnabled()) { 709 CmsLog.INIT.warn( 710 Messages.get().getBundle().key( 711 Messages.INIT_TOOLMANAGER_INCONSISTENT_PATH_2, 712 handler.getPath(), 713 handler.getLink())); 714 } 715 return; 716 } 717 718 String id = "tool" + m_tools.elementList().size(); 719 CmsTool tool = new CmsTool(id, handler); 720 721 try { 722 // try to find problems in custom tools 723 handler.isEnabled(cms); 724 handler.isVisible(cms); 725 } catch (Throwable ex) { 726 String message = Messages.get().getBundle().key( 727 Messages.INIT_TOOLMANAGER_INSTALL_ERROR_2, 728 handler.getPath(), 729 handler.getLink()); 730 if (CmsLog.INIT.isWarnEnabled()) { 731 CmsLog.INIT.warn(message); 732 } else if (CmsLog.INIT.isDebugEnabled()) { 733 CmsLog.INIT.debug(message, ex); 734 } 735 return; 736 } 737 738 try { 739 // try to register, can fail if path is already used by another tool 740 m_tools.addIdentifiableObject(toolRoot.getKey() + ROOT_SEPARATOR + handler.getPath(), tool); 741 // just for fast association of links with tools 742 m_urls.addIdentifiableObject(link, handler.getPath()); 743 } catch (Throwable ex) { 744 CmsLog.INIT.warn( 745 Messages.get().getBundle().key( 746 Messages.INIT_TOOLMANAGER_DUPLICATED_ERROR_3, 747 handler.getPath(), 748 handler.getLink(), 749 resolveAdminTool(toolRoot.getKey(), handler.getPath()).getHandler().getLink())); 750 } 751 } 752 753 /** 754 * Registers all tool handlers recursively for a given tool root.<p> 755 * 756 * @param cms the cms context object 757 * @param toolRoot the tool root 758 * @param len the recursion level 759 * @param handlers the list of handlers to register 760 */ 761 private void registerHandlerList( 762 CmsObject cms, 763 CmsToolRootHandler toolRoot, 764 int len, 765 List<I_CmsToolHandler> handlers) { 766 767 boolean found = false; 768 Iterator<I_CmsToolHandler> it = handlers.iterator(); 769 while (it.hasNext()) { 770 I_CmsToolHandler handler = it.next(); 771 int myLen = CmsStringUtil.splitAsArray(handler.getPath(), TOOLPATH_SEPARATOR).length; 772 if (((len == myLen) && !handler.getPath().equals(TOOLPATH_SEPARATOR)) 773 || ((len == 1) && handler.getPath().equals(TOOLPATH_SEPARATOR))) { 774 found = true; 775 registerAdminTool(cms, toolRoot, handler); 776 } 777 } 778 if (found) { 779 registerHandlerList(cms, toolRoot, len + 1, handlers); 780 } 781 782 } 783 784 /** 785 * Given a string a valid and visible tool path is computed.<p> 786 * 787 * @param wp the workplace object 788 * @param path the path to repair 789 * 790 * @return a valid and visible tool path 791 */ 792 private String repairPath(CmsWorkplace wp, String path) { 793 794 String rootKey = getCurrentRoot(wp).getKey(); 795 // navigate until to reach a valid path 796 while (!validatePath(rootKey, path, true)) { 797 // log failure 798 LOG.warn(Messages.get().getBundle().key(Messages.LOG_MISSING_ADMIN_TOOL_1, path)); 799 // try parent 800 path = getParent(wp, path); 801 } 802 // navigate until to reach a valid tool 803 while ((resolveAdminTool(rootKey, path) == null) && !"/".equals(path)) { 804 // log failure 805 LOG.warn(Messages.get().getBundle().key(Messages.LOG_MISSING_ADMIN_TOOL_1, path)); 806 // try parent 807 path = getParent(wp, path); 808 } 809 810 // navigate until to reach an enabled path 811 CmsTool aTool = resolveAdminTool(rootKey, path); 812 while ((aTool != null) && !aTool.getHandler().isEnabled(wp)) { 813 if (aTool.getHandler().getLink().equals(VIEW_JSPPAGE_LOCATION)) { 814 // just grouping 815 break; 816 } 817 path = getParent(wp, path); 818 aTool = resolveAdminTool(rootKey, path); 819 } 820 821 return path; 822 } 823 824 /** 825 * Tests if the full tool path is available.<p> 826 * 827 * @param rootKey the root tool 828 * @param toolPath the path 829 * @param full if <code>true</code> the whole path is checked, if not the last part is not checked (for new tools) 830 * 831 * @return if valid or not 832 */ 833 private boolean validatePath(String rootKey, String toolPath, boolean full) { 834 835 if (toolPath.equals(TOOLPATH_SEPARATOR)) { 836 return true; 837 } 838 if (!toolPath.startsWith(TOOLPATH_SEPARATOR)) { 839 return false; 840 } 841 List<String> groups = CmsStringUtil.splitAsList(toolPath, TOOLPATH_SEPARATOR); 842 Iterator<String> itGroups = groups.iterator(); 843 String subpath = ""; 844 while (itGroups.hasNext()) { 845 String group = itGroups.next(); 846 if (subpath.length() != TOOLPATH_SEPARATOR.length()) { 847 subpath += TOOLPATH_SEPARATOR + group; 848 } else { 849 subpath += group; 850 } 851 if (itGroups.hasNext() || full) { 852 try { 853 // just check if the tool is available 854 resolveAdminTool(rootKey, subpath).toString(); 855 } catch (Exception e) { 856 return false; 857 } 858 } 859 } 860 return true; 861 } 862}