All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zaproxy.zap.extension.help.ZapTocMerger Maven / Gradle / Ivy

/*
 * Zed Attack Proxy (ZAP) and its related class files.
 *
 * ZAP is an HTTP/HTTPS proxy for assessing web application security.
 *
 * Copyright 2014 The ZAP Development Team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.zaproxy.zap.extension.help;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.help.MergeHelpUtilities;
import javax.help.NavigatorView;
import javax.help.SortMerge;
import javax.help.TreeItem;
import javax.help.UniteAppendMerge;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;

/**
 * NOTE: The name (and package) of the class must not be changed lightly! It will
 * break help's TOC merging at runtime. The name and package is hard coded in helpset files and is
 * also referenced in others for documentation purposes. (END NOTE)
 *
 * 

An {@code UniteAppendMerge} that takes into account the "tocid" attribute of the "tocitem" * elements to do the merging. The "tocid" attribute is used to facilitate the merging of the TOC * with internationalised helpsets. The node names and targets do not provide enough information to * do a safe merging. The name might not be the same (when it is translated) and the target is not * present in all nodes. In those cases a "tocid" attribute is set to unambiguously identify those * nodes. * *

The merge depends on the information provided by the "tocitem" elements and if they use or not * the "tocid" attribute. * *

First the nodes are compared to check if they have the same "tocid" and merged if they have. *
* Otherwise and for backward compatibility with helpsets that still do not use the attribute * "tocid" a forced merge is performed if some predefined requirements are met. The requirements are * as follow: * *

    *
  1. The master node must have an attribute "tocid"; *
  2. The master node "tocid" must be present in the map of forced merges ({@code * TOC_IDS_FORCE_MERGE_MAP}); *
  3. The slave node must have the same name as the one defined in the value ({@code * ForceMergeRequirement}) of the map of forced merges; *
  4. The master node level must be the same as the one defined in the value of the map of forced * merges (the level is used to prevent matching other nodes with the same name in the tree). *
* *

If none of the aforementioned merges are performed the actual merging will be done as defined * by {@code UniteAppendMerge}. * * @see UniteAppendMerge * @see ZapTocItem * @see ZapTocView * @see #TOC_IDS_FORCE_MERGE_MAP * @see ZapTocMerger.ForceMergeRequirement */ // Note: This class contains copied (verbatim) code from the base class UniteAppendMerge. public class ZapTocMerger extends UniteAppendMerge { private static final String DEFAULT_MERGE_TYPE = ZapTocMerger.class.getCanonicalName(); private static final String ADDONS_TOC_ID = "addons"; /** * A map containing the requirements to do forced merging. * *

The map key corresponds to the attribute "tocid" of the "tocitem" elements as defined in * the toc.xml file. The value has the requirements that should be met to actually do the * merging. */ public static final Map TOC_IDS_FORCE_MERGE_MAP; static { Map tempMap = new HashMap<>(); // Note: The attribute "tocid" should match the ones defined in the toc.xml file. // Note 2: the TOC tree node names are hard coded because the "older" add-ons use the same // (hard coded) names. tempMap.put("toplevelitem", new ForceMergeRequirement(1, "ZAP User Guide")); tempMap.put(ADDONS_TOC_ID, new ForceMergeRequirement(2, "Add Ons")); TOC_IDS_FORCE_MERGE_MAP = Collections.unmodifiableMap(tempMap); } public ZapTocMerger(NavigatorView master, NavigatorView slave) { super(master, slave); } /** * Processes unite-append merge * * @param node The master node * @return Merged master node */ // Note: the implementation and JavaDoc has been copied (verbatim) from the base method to call // the method // ZapTocMerger#mergeNodes(TreeNode, TreeNode) instead of UniteAppendMerge#mergeNodes(TreeNode, // TreeNode). @Override public TreeNode processMerge(TreeNode node) { DefaultMutableTreeNode masterNode = (DefaultMutableTreeNode) node; // if master and slave are the same object return the // masterNode if (masterNode.equals(slaveTopNode)) { return masterNode; } // If there are not children in slaveTopNode return the // masterNode if (slaveTopNode.getChildCount() == 0) { return masterNode; } mergeNodes(masterNode, slaveTopNode); return masterNode; } /** * Merge Nodes. Merge two nodes according to the merging rules of the masterNode. Each Subclass * should override this implementation. * * @param master The master node to merge with * @param slave The node to merge into the master */ // Note: the implementation and JavaDoc has been copied (verbatim) from // UniteAppendMerge#mergeNodes(TreeNode, TreeNode) // except for the call to doCustomMerge(DefaultMutableTreeNode, DefaultMutableTreeNode) and the // calls to // MergeHelpUtilities.mergeNode* which is set, using DEFAULT_MERGE_TYPE, to merge with this // class instead. public static void mergeNodes(TreeNode master, TreeNode slave) { DefaultMutableTreeNode masterNode = (DefaultMutableTreeNode) master; DefaultMutableTreeNode slaveNode = (DefaultMutableTreeNode) slave; int masterCnt = masterNode.getChildCount(); // loop thru the slaves while (slaveNode.getChildCount() > 0) { DefaultMutableTreeNode slaveNodeChild = (DefaultMutableTreeNode) slaveNode.getFirstChild(); // loop thru the master children for (int m = 0; m < masterCnt; m++) { DefaultMutableTreeNode masterAtM = (DefaultMutableTreeNode) masterNode.getChildAt(m); if (doCustomMerge(slaveNodeChild, masterAtM)) { slaveNodeChild = null; break; } // see if the names are the same if (MergeHelpUtilities.compareNames(masterAtM, slaveNodeChild) == 0) { if (MergeHelpUtilities.haveEqualID(masterAtM, slaveNodeChild)) { // ID and name the same merge the slave node in MergeHelpUtilities.mergeNodes( DEFAULT_MERGE_TYPE, masterAtM, slaveNodeChild); // Need to remove the slaveNodeChild from the list slaveNodeChild.removeFromParent(); slaveNodeChild = null; break; } // Names are the same but the ID are not // Mark the nodes and add the slaveChild MergeHelpUtilities.markNodes(masterAtM, slaveNodeChild); masterNode.add(slaveNodeChild); MergeHelpUtilities.mergeNodeChildren(DEFAULT_MERGE_TYPE, slaveNodeChild); slaveNodeChild = null; break; } } if (slaveNodeChild != null) { masterNode.add(slaveNodeChild); MergeHelpUtilities.mergeNodeChildren(DEFAULT_MERGE_TYPE, slaveNodeChild); } } // There are no more children. // Remove slaveNode from it's parent slaveNode.removeFromParent(); slaveNode = null; } private static boolean doCustomMerge( DefaultMutableTreeNode slaveNodeChild, DefaultMutableTreeNode masterAtM) { if (isSameTOCID(masterAtM, slaveNodeChild) || isForceMerge(masterAtM, slaveNodeChild)) { MergeHelpUtilities.mergeNodes(DEFAULT_MERGE_TYPE, masterAtM, slaveNodeChild); slaveNodeChild.removeFromParent(); if (ADDONS_TOC_ID.equals(getTOCID(masterAtM))) { SortMerge.sortNode(masterAtM, MergeHelpUtilities.getLocale(masterAtM)); } return true; } return false; } private static boolean isSameTOCID( DefaultMutableTreeNode masterAtM, DefaultMutableTreeNode slaveNodeChild) { String slaveTocId = getTOCID(slaveNodeChild); if (slaveTocId == null) { return false; } return slaveTocId.equals(getTOCID(masterAtM)); } private static String getTOCID(DefaultMutableTreeNode node) { TreeItem treeItem = (TreeItem) node.getUserObject(); if (treeItem != null && (treeItem instanceof ZapTocItem)) { return ((ZapTocItem) treeItem).getTocId(); } return null; } private static boolean isForceMerge( DefaultMutableTreeNode masterAtM, DefaultMutableTreeNode slaveNodeChild) { TreeItem slaveNodeChildTreeItem = (TreeItem) slaveNodeChild.getUserObject(); String slaveName = slaveNodeChildTreeItem.getName(); if (slaveName == null) { return false; } String tocId = getTOCID(masterAtM); if (tocId != null) { ForceMergeRequirement forceMergeRequirement = TOC_IDS_FORCE_MERGE_MAP.get(tocId); if (forceMergeRequirement != null && forceMergeRequirement.isSameMasterLevel(masterAtM.getLevel()) && forceMergeRequirement.isSameSlaveName(slaveName)) { return true; } } return false; } /** * Merge Node Children. Merge the children of a node according to the merging rules of the * parent. Each subclass must implement this method * * @param node The parent node from which the children are merged */ // Note: the implementation and JavaDoc has been copied (verbatim) from // UniteAppendMerge#mergeNodeChildren(TreeNode) except // for the call to MergeHelpUtilities.mergeNodeChildren(String, child) which is set, using // DEFAULT_MERGE_TYPE, to merge with // this class instead. public static void mergeNodeChildren(TreeNode node) { DefaultMutableTreeNode masterNode = (DefaultMutableTreeNode) node; // The rules are there are no rules. Nothing else needs to be done // except for merging through the children for (int i = 0; i < masterNode.getChildCount(); i++) { DefaultMutableTreeNode child = (DefaultMutableTreeNode) masterNode.getChildAt(i); if (!child.isLeaf()) { MergeHelpUtilities.mergeNodeChildren(DEFAULT_MERGE_TYPE, child); } } } /** * The {@code ForceMergeRequirement} class contains the requirements to do a forced merging. * * @see ForceMergeRequirement#ForceMergeRequirement(int, String) */ public static final class ForceMergeRequirement { private final int masterNodeLevel; private final String slaveNodeName; /** * Creates a {@code ForceMergeRequirement} instance. * * @param masterNodeLevel the level of the master node in the TOC tree * @param slaveNodeName the name of the slave node * @see DefaultMutableTreeNode#getLevel() */ public ForceMergeRequirement(int masterNodeLevel, String slaveNodeName) { if (masterNodeLevel < 0) { throw new IllegalArgumentException( "Parameter masterNodeLevel must not be negative."); } if (slaveNodeName == null || slaveNodeName.isEmpty()) { throw new IllegalArgumentException("Parameter slaveNodeName must not be null."); } this.masterNodeLevel = masterNodeLevel; this.slaveNodeName = slaveNodeName; } public boolean isSameMasterLevel(int level) { return (masterNodeLevel == level); } public boolean isSameSlaveName(String name) { return slaveNodeName.equals(name); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy