diff --git a/backend/src/main/java/io/metersphere/performance/engine/EngineContext.java b/backend/src/main/java/io/metersphere/performance/engine/EngineContext.java index e4ef1fa2b0..75c78ebb44 100644 --- a/backend/src/main/java/io/metersphere/performance/engine/EngineContext.java +++ b/backend/src/main/java/io/metersphere/performance/engine/EngineContext.java @@ -8,7 +8,7 @@ public class EngineContext { private String testName; private String namespace; private String fileType; - private String content; + private byte[] content; private String resourcePoolId; private String reportId; private Integer resourceIndex; @@ -52,11 +52,11 @@ public class EngineContext { return this.properties.get(key); } - public String getContent() { + public byte[] getContent() { return content; } - public void setContent(String content) { + public void setContent(byte[] content) { this.content = content; } diff --git a/backend/src/main/java/io/metersphere/performance/engine/EngineFactory.java b/backend/src/main/java/io/metersphere/performance/engine/EngineFactory.java index 01eb9ec2ed..fef24c8509 100644 --- a/backend/src/main/java/io/metersphere/performance/engine/EngineFactory.java +++ b/backend/src/main/java/io/metersphere/performance/engine/EngineFactory.java @@ -25,25 +25,15 @@ import org.apache.commons.beanutils.ConstructorUtils; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; +import org.dom4j.Document; +import org.dom4j.Element; import org.reflections8.Reflections; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; import javax.annotation.Resource; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; +import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; @@ -239,7 +229,7 @@ public class EngineFactory { engineContext.setTestResourceFiles(testResourceFiles); try (ByteArrayInputStream source = new ByteArrayInputStream(jmxBytes)) { - String content = engineSourceParser.parse(engineContext, source); + byte[] content = engineSourceParser.parse(engineContext, source); engineContext.setContent(content); } catch (MSException e) { LogUtil.error(e.getMessage(), e); @@ -309,80 +299,75 @@ public class EngineFactory { return props.toString().getBytes(StandardCharsets.UTF_8); } + public static byte[] mergeJmx(List jmxFiles) { try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder docBuilder = factory.newDocumentBuilder(); Element hashTree = null; Document rootDocument = null; for (FileMetadata fileMetadata : jmxFiles) { FileContent fileContent = fileService.getFileContent(fileMetadata.getId()); - final InputSource inputSource = new InputSource(new ByteArrayInputStream(fileContent.getFile())); + InputStream inputSource = new ByteArrayInputStream(fileContent.getFile()); if (hashTree == null) { - rootDocument = docBuilder.parse(inputSource); - Element jmeterTestPlan = rootDocument.getDocumentElement(); - NodeList childNodes = jmeterTestPlan.getChildNodes(); + rootDocument = EngineSourceParserFactory.getDocument(inputSource); + Element jmeterTestPlan = rootDocument.getRootElement(); + List childNodes = jmeterTestPlan.elements(); outer: - for (int i = 0; i < childNodes.getLength(); i++) { - Node node = childNodes.item(i); - if (node instanceof Element) { - // jmeterTestPlan的子元素肯定是 - NodeList childNodes1 = node.getChildNodes(); - for (int j = 0; j < childNodes1.getLength(); j++) { - Node item = childNodes1.item(j); - if (StringUtils.equalsIgnoreCase("hashTree", item.getNodeName())) { - hashTree = (Element) node; - break outer; - } + for (Element node : childNodes) { + // jmeterTestPlan的子元素肯定是 + List childNodes1 = node.elements(); + for (Element item : childNodes1) { + if (StringUtils.equalsIgnoreCase("TestPlan", item.getName())) { + hashTree = getNextSibling(item); + break outer; } } } } else { - Document document = docBuilder.parse(inputSource); - Element jmeterTestPlan = document.getDocumentElement(); - NodeList childNodes = jmeterTestPlan.getChildNodes(); - for (int i = 0; i < childNodes.getLength(); i++) { - Node node = childNodes.item(i); - if (node instanceof Element) { - // jmeterTestPlan的子元素肯定是 - Element secondHashTree = (Element) node; - NodeList secondChildNodes = secondHashTree.getChildNodes(); - for (int j = 0; j < secondChildNodes.getLength(); j++) { - Node item = secondChildNodes.item(j); - if (StringUtils.equalsIgnoreCase("TestPlan", item.getNodeName())) { - continue; - } - if (StringUtils.equalsIgnoreCase("hashTree", item.getNodeName())) { - NodeList itemChildNodes = item.getChildNodes(); - for (int k = 0; k < itemChildNodes.getLength(); k++) { - Node item1 = itemChildNodes.item(k); - Node newNode = item1.cloneNode(true); - rootDocument.adoptNode(newNode); - hashTree.appendChild(newNode); - } - } - + Document document = EngineSourceParserFactory.getDocument(inputSource); + Element jmeterTestPlan = document.getRootElement(); + List childNodes = jmeterTestPlan.elements(); + for (Element node : childNodes) { + // jmeterTestPlan的子元素肯定是 + Element secondHashTree = node; + List secondChildNodes = secondHashTree.elements(); + for (Element item : secondChildNodes) { + if (StringUtils.equalsIgnoreCase("TestPlan", item.getName())) { + secondHashTree = getNextSibling(item); + break; } } + if (StringUtils.equalsIgnoreCase("hashTree", secondHashTree.getName())) { + List itemChildNodes = secondHashTree.elements(); + for (Element item1 : itemChildNodes) { + hashTree.add((Element) item1.clone()); + } + } + } } + // + inputSource.close(); } - return documentToBytes(rootDocument); + return EngineSourceParserFactory.formatXml(rootDocument); } catch (Exception e) { MSException.throwException(e); } return new byte[0]; } - private static byte[] documentToBytes(Document document) throws TransformerException { - DOMSource domSource = new DOMSource(document); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - StreamResult result = new StreamResult(out); - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer transformer = tf.newTransformer(); - transformer.transform(domSource, result); - return out.toByteArray(); + private static Element getNextSibling(Element ele) { + Element parent = ele.getParent(); + if (parent != null) { + Iterator iterator = parent.elementIterator(); + while (iterator.hasNext()) { + Element next = iterator.next(); + if (ele.equals(next)) { + return iterator.next(); + } + } + } + return null; } @Resource diff --git a/backend/src/main/java/io/metersphere/performance/parse/EngineSourceParser.java b/backend/src/main/java/io/metersphere/performance/parse/EngineSourceParser.java index 8035145812..890a37c1a8 100644 --- a/backend/src/main/java/io/metersphere/performance/parse/EngineSourceParser.java +++ b/backend/src/main/java/io/metersphere/performance/parse/EngineSourceParser.java @@ -5,5 +5,5 @@ import io.metersphere.performance.engine.EngineContext; import java.io.InputStream; public interface EngineSourceParser { - String parse(EngineContext context, InputStream source) throws Exception; + byte[] parse(EngineContext context, InputStream source) throws Exception; } diff --git a/backend/src/main/java/io/metersphere/performance/parse/EngineSourceParserFactory.java b/backend/src/main/java/io/metersphere/performance/parse/EngineSourceParserFactory.java index e2e54994d2..e82f5e81cf 100644 --- a/backend/src/main/java/io/metersphere/performance/parse/EngineSourceParserFactory.java +++ b/backend/src/main/java/io/metersphere/performance/parse/EngineSourceParserFactory.java @@ -1,16 +1,96 @@ package io.metersphere.performance.parse; import io.metersphere.commons.constants.FileType; -import io.metersphere.performance.parse.xml.XmlEngineSourceParse; +import io.metersphere.commons.utils.LogUtil; +import io.metersphere.performance.parse.xml.reader.JmeterDocumentParser; +import org.apache.commons.lang3.StringUtils; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.SAXReader; +import org.dom4j.io.XMLWriter; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.XMLFilterImpl; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; public class EngineSourceParserFactory { + public static final boolean IS_TRANS = true; + + public static EngineSourceParser createEngineSourceParser(String type) { final FileType engineType = FileType.valueOf(type); if (FileType.JMX.equals(engineType)) { - return new XmlEngineSourceParse(); + return new JmeterDocumentParser(); } return null; } + + public static Document getDocument(InputStream source) throws DocumentException { + SAXReader reader = new SAXReader(); + if (!IS_TRANS) { + reader.setXMLFilter(EngineSourceParserFactory.getFilter()); + } + return reader.read(source); + } + + public static byte[] formatXml(Document document) throws Exception { + OutputFormat format = OutputFormat.createPrettyPrint(); + try ( + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ) { + XMLWriter xw = new XMLWriter(out, format); + xw.setEscapeText(IS_TRANS); + xw.write(document); + xw.flush(); + xw.close(); + return out.toByteArray(); + } catch (IOException e) { + LogUtil.error(e); + } + return new byte[0]; + } + + public static XMLFilterImpl getFilter() { + return new XMLFilterImpl() { + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + String text = new String(ch, start, length); + + if (length == 1) { + if (StringUtils.equals("&", text)) { + char[] escape = "&".toCharArray(); + super.characters(escape, start, escape.length); + return; + } + if (StringUtils.equals("\"", text)) { + char[] escape = """.toCharArray(); + super.characters(escape, start, escape.length); + return; + } + if (StringUtils.equals("'", text)) { + char[] escape = "'".toCharArray(); + super.characters(escape, start, escape.length); + return; + } + if (StringUtils.equals("<", text)) { + char[] escape = "<".toCharArray(); + super.characters(escape, start, escape.length); + return; + } + if (StringUtils.equals(">", text)) { + char[] escape = ">".toCharArray(); + super.characters(escape, start, escape.length); + return; + } + } + + super.characters(ch, start, length); + } + }; + } } diff --git a/backend/src/main/java/io/metersphere/performance/parse/xml/XmlEngineSourceParse.java b/backend/src/main/java/io/metersphere/performance/parse/xml/XmlEngineSourceParse.java deleted file mode 100644 index 3723b45433..0000000000 --- a/backend/src/main/java/io/metersphere/performance/parse/xml/XmlEngineSourceParse.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.metersphere.performance.parse.xml; - -import io.metersphere.performance.engine.EngineContext; -import io.metersphere.performance.parse.EngineSourceParser; -import io.metersphere.performance.parse.xml.reader.DocumentParser; -import io.metersphere.performance.parse.xml.reader.DocumentParserFactory; -import org.w3c.dom.Document; -import org.xml.sax.InputSource; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import java.io.InputStream; - -public class XmlEngineSourceParse implements EngineSourceParser { - @Override - public String parse(EngineContext context, InputStream source) throws Exception { - final InputSource inputSource = new InputSource(source); - - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - - DocumentBuilder docBuilder = factory.newDocumentBuilder(); - final Document document = docBuilder.parse(inputSource); - - final DocumentParser documentParser = createDocumentParser(context.getFileType()); - - return documentParser.parse(context, document); - } - - private DocumentParser createDocumentParser(String type) { - return DocumentParserFactory.createDocumentParser(type); - } -} diff --git a/backend/src/main/java/io/metersphere/performance/parse/xml/reader/DocumentParser.java b/backend/src/main/java/io/metersphere/performance/parse/xml/reader/DocumentParser.java deleted file mode 100644 index 34c8be44f2..0000000000 --- a/backend/src/main/java/io/metersphere/performance/parse/xml/reader/DocumentParser.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.metersphere.performance.parse.xml.reader; - -import io.metersphere.performance.engine.EngineContext; -import org.w3c.dom.Document; - -public interface DocumentParser { - String parse(EngineContext context, Document document) throws Exception; -} diff --git a/backend/src/main/java/io/metersphere/performance/parse/xml/reader/DocumentParserFactory.java b/backend/src/main/java/io/metersphere/performance/parse/xml/reader/DocumentParserFactory.java deleted file mode 100644 index dc3e8ee20b..0000000000 --- a/backend/src/main/java/io/metersphere/performance/parse/xml/reader/DocumentParserFactory.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.metersphere.performance.parse.xml.reader; - -import io.metersphere.commons.constants.FileType; -import io.metersphere.performance.parse.xml.reader.jmx.JmeterDocumentParser; - -public class DocumentParserFactory { - public static DocumentParser createDocumentParser(String type) { - final FileType fileType = FileType.valueOf(type); - - switch (fileType) { - case JMX: - return new JmeterDocumentParser(); - default: - break; - } - return null; - } -} diff --git a/backend/src/main/java/io/metersphere/performance/parse/xml/reader/jmx/JmeterDocumentParser.java b/backend/src/main/java/io/metersphere/performance/parse/xml/reader/JmeterDocumentParser.java similarity index 50% rename from backend/src/main/java/io/metersphere/performance/parse/xml/reader/jmx/JmeterDocumentParser.java rename to backend/src/main/java/io/metersphere/performance/parse/xml/reader/JmeterDocumentParser.java index 45ebe76bbe..c0e66cf26d 100644 --- a/backend/src/main/java/io/metersphere/performance/parse/xml/reader/jmx/JmeterDocumentParser.java +++ b/backend/src/main/java/io/metersphere/performance/parse/xml/reader/JmeterDocumentParser.java @@ -1,4 +1,4 @@ -package io.metersphere.performance.parse.xml.reader.jmx; +package io.metersphere.performance.parse.xml.reader; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; @@ -9,29 +9,25 @@ import io.metersphere.config.KafkaProperties; import io.metersphere.i18n.Translator; import io.metersphere.jmeter.utils.ScriptEngineUtils; import io.metersphere.performance.engine.EngineContext; -import io.metersphere.performance.parse.xml.reader.DocumentParser; +import io.metersphere.performance.parse.EngineSourceParser; +import io.metersphere.performance.parse.EngineSourceParserFactory; import io.metersphere.service.TestResourcePoolService; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ClassUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.reflect.MethodUtils; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; +import org.dom4j.Document; +import org.dom4j.Element; +import org.dom4j.Node; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import java.io.StringWriter; +import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; -public class JmeterDocumentParser implements DocumentParser { +public class JmeterDocumentParser implements EngineSourceParser { private final static String HASH_TREE_ELEMENT = "hashTree"; private final static String TEST_PLAN = "TestPlan"; private final static String STRING_PROP = "stringProp"; @@ -53,86 +49,70 @@ public class JmeterDocumentParser implements DocumentParser { private EngineContext context; @Override - public String parse(EngineContext context, Document document) throws Exception { + public byte[] parse(EngineContext context, InputStream source) throws Exception { this.context = context; - final Element jmeterTestPlan = document.getDocumentElement(); + Document document = EngineSourceParserFactory.getDocument(source); - NodeList childNodes = jmeterTestPlan.getChildNodes(); - for (int i = 0; i < childNodes.getLength(); i++) { - Node node = childNodes.item(i); + final Element jmeterTestPlan = document.getRootElement(); - if (node instanceof Element) { - Element ele = (Element) node; - - // jmeterTestPlan的子元素肯定是 - parseHashTree(ele); - } + List childNodes = jmeterTestPlan.elements(); + for (Element ele : childNodes) { + // jmeterTestPlan的子元素肯定是 + parseHashTree(ele); } - return documentToString(document); + return EngineSourceParserFactory.formatXml(document); } - private String documentToString(Document document) throws TransformerException { - DOMSource domSource = new DOMSource(document); - StringWriter writer = new StringWriter(); - StreamResult result = new StreamResult(writer); - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer transformer = tf.newTransformer(); - transformer.transform(domSource, result); - return writer.toString(); - } private void parseHashTree(Element hashTree) { if (invalid(hashTree)) { return; } - if (hashTree.getChildNodes().getLength() > 0) { - final NodeList childNodes = hashTree.getChildNodes(); - for (int i = 0; i < childNodes.getLength(); i++) { - Node node = childNodes.item(i); - if (node instanceof Element) { - Element ele = (Element) node; - - if (nodeNameEquals(ele, HASH_TREE_ELEMENT)) { - parseHashTree(ele); - } else if (nodeNameEquals(ele, TEST_PLAN)) { - processCheckoutConfigTestElement(ele); - processCheckoutArguments(ele); - processCheckoutResponseAssertion(ele); - processCheckoutSerializeThreadgroups(ele); - processCheckoutBackendListener(ele); - processCheckoutAutoStopListener(ele); - } else if (nodeNameEquals(ele, CONCURRENCY_THREAD_GROUP)) { - processThreadType(ele); - processThreadGroupName(ele); - processCheckoutTimer(ele); - } else if (nodeNameEquals(ele, VARIABLE_THROUGHPUT_TIMER)) { - processVariableThroughputTimer(ele); - } else if (nodeNameEquals(ele, THREAD_GROUP) || - nodeNameEquals(ele, SETUP_THREAD_GROUP) || - nodeNameEquals(ele, POST_THREAD_GROUP)) { - processThreadType(ele); - processThreadGroupName(ele); - processCheckoutTimer(ele); - } else if (nodeNameEquals(ele, BACKEND_LISTENER)) { - processBackendListener(ele); - } else if (nodeNameEquals(ele, CONFIG_TEST_ELEMENT)) { - processConfigTestElement(ele); - } else if (nodeNameEquals(ele, ARGUMENTS)) { - processArguments(ele); - } else if (nodeNameEquals(ele, RESPONSE_ASSERTION)) { - processResponseAssertion(ele); - } else if (nodeNameEquals(ele, CSV_DATA_SET)) { - processCsvDataSet(ele); - } else if (nodeNameEquals(ele, THREAD_GROUP_AUTO_STOP)) { - processAutoStopListener(ele); - } else if (nodeNameEquals(ele, HTTP_SAMPLER_PROXY)) { - // 处理http上传的附件 - processArgumentFiles(ele); - } + if (hashTree.elements().size() > 0) { + final List childNodes = hashTree.elements(); + for (int i = 0; i < childNodes.size(); i++) { + Element ele = childNodes.get(i); + if (nodeNameEquals(ele, HASH_TREE_ELEMENT)) { + parseHashTree(ele); + } else if (nodeNameEquals(ele, TEST_PLAN)) { + processCheckoutConfigTestElement(ele); + processCheckoutArguments(ele); + processCheckoutResponseAssertion(ele); + processCheckoutSerializeThreadgroups(ele); + processCheckoutBackendListener(ele); + processCheckoutAutoStopListener(ele); + } else if (nodeNameEquals(ele, CONCURRENCY_THREAD_GROUP)) { + processThreadType(ele); + processThreadGroupName(ele); + processCheckoutTimer(ele); + } else if (nodeNameEquals(ele, VARIABLE_THROUGHPUT_TIMER)) { + processVariableThroughputTimer(ele); + } else if (nodeNameEquals(ele, THREAD_GROUP) || + nodeNameEquals(ele, SETUP_THREAD_GROUP) || + nodeNameEquals(ele, POST_THREAD_GROUP)) { + processThreadType(ele); + processThreadGroupName(ele); + processCheckoutTimer(ele); + } else if (nodeNameEquals(ele, BACKEND_LISTENER)) { + processBackendListener(ele); + } else if (nodeNameEquals(ele, CONFIG_TEST_ELEMENT)) { + processConfigTestElement(ele); + } else if (nodeNameEquals(ele, ARGUMENTS)) { + processArguments(ele); + } else if (nodeNameEquals(ele, RESPONSE_ASSERTION)) { + processResponseAssertion(ele); + } else if (nodeNameEquals(ele, CSV_DATA_SET)) { + processCsvDataSet(ele); + } else if (nodeNameEquals(ele, THREAD_GROUP_AUTO_STOP)) { + processAutoStopListener(ele); + } else if (nodeNameEquals(ele, HTTP_SAMPLER_PROXY)) { + // 处理http上传的附件 + processArgumentFiles(ele); } + } } } @@ -160,10 +140,11 @@ public class JmeterDocumentParser implements DocumentParser { Object o = ((List) autoStopDelays).get(0); autoStopDelay = o.toString(); } - Document document = autoStopListener.getOwnerDocument(); + Document document = autoStopListener.getDocument(); // 清空child removeChildren(autoStopListener); - autoStopListener.appendChild(createStringProp(document, "delay_seconds", autoStopDelay)); + // 添加子元素 + appendStringProp(autoStopListener, "delay_seconds", autoStopDelay); } private void processCheckoutAutoStopListener(Element element) { @@ -177,20 +158,13 @@ public class JmeterDocumentParser implements DocumentParser { return; } - Document document = element.getOwnerDocument(); - Node listenerParent = element.getNextSibling(); - while (!(listenerParent instanceof Element)) { - listenerParent = listenerParent.getNextSibling(); - } - // add class name - Element autoStopListener = document.createElement(THREAD_GROUP_AUTO_STOP); - autoStopListener.setAttribute("guiclass", "io.metersphere.jmeter.reporters.ThreadGroupAutoStopGui"); - autoStopListener.setAttribute("testclass", "io.metersphere.jmeter.reporters.ThreadGroupAutoStop"); - autoStopListener.setAttribute("testname", "MeterSphere - AutoStop Listener"); - autoStopListener.setAttribute("enabled", "true"); - listenerParent.appendChild(autoStopListener); - listenerParent.appendChild(document.createElement(HASH_TREE_ELEMENT)); + Element autoStopListener = element.addElement(THREAD_GROUP_AUTO_STOP); + autoStopListener.addAttribute("guiclass", "io.metersphere.jmeter.reporters.ThreadGroupAutoStopGui"); + autoStopListener.addAttribute("testclass", "io.metersphere.jmeter.reporters.ThreadGroupAutoStop"); + autoStopListener.addAttribute("testname", "MeterSphere - AutoStop Listener"); + autoStopListener.addAttribute("enabled", "true"); + element.addElement(HASH_TREE_ELEMENT); } private void processCheckoutSerializeThreadgroups(Element element) { @@ -200,13 +174,12 @@ public class JmeterDocumentParser implements DocumentParser { Object o = ((List) serializeThreadGroups).get(0); serializeThreadGroup = o.toString(); } - NodeList childNodes = element.getChildNodes(); - for (int i = 0; i < childNodes.getLength(); i++) { - Node item = childNodes.item(i); + List childNodes = element.elements(); + for (Element item : childNodes) { if (nodeNameEquals(item, BOOL_PROP)) { - String serializeName = ((Element) item).getAttribute("name"); + String serializeName = item.attributeValue("name"); if (StringUtils.equals(serializeName, "TestPlan.serialize_threadgroups")) { - item.setTextContent(serializeThreadGroup); + item.setText(serializeThreadGroup); break; } } @@ -214,28 +187,17 @@ public class JmeterDocumentParser implements DocumentParser { } private void processArgumentFiles(Element element) { - NodeList childNodes = element.getChildNodes(); - for (int i = 0; i < childNodes.getLength(); i++) { - Node item = childNodes.item(i); - if (item instanceof Element && isHTTPFileArgs((Element) item)) { - Node collectionProp = item.getFirstChild(); - - while (!(collectionProp instanceof Element)) { - collectionProp = collectionProp.getNextSibling(); - } - NodeList elementProps = collectionProp.getChildNodes(); - - for (int j = 0; j < elementProps.getLength(); j++) { - Node eleProp = elementProps.item(j); - NodeList strProps = eleProp.getChildNodes(); - for (int k = 0; k < strProps.getLength(); k++) { - Node strPop = strProps.item(k); - if (strPop instanceof Element) { - if (StringUtils.equals(((Element) strPop).getAttribute("name"), "File.path")) { - // 截取文件名 - handleFilename(strPop); - break; - } + List childNodes = element.elements(); + for (Element item : childNodes) { + if (isHTTPFileArgs(item)) { + List elementProps = item.elements(); + for (Element eleProp : elementProps) { + List strProps = eleProp.elements(); + for (Element strPop : strProps) { + if (StringUtils.equals(strPop.attributeValue("name"), "File.path")) { + // 截取文件名 + handleFilename(strPop); + break; } } } @@ -247,24 +209,23 @@ public class JmeterDocumentParser implements DocumentParser { private void handleFilename(Node item) { String separator = "/"; - String filename = item.getTextContent(); + String filename = item.getText(); if (!StringUtils.contains(filename, "/")) { separator = "\\"; } filename = filename.substring(filename.lastIndexOf(separator) + 1); - item.setTextContent(filename); + item.setText(filename); } private boolean isHTTPFileArgs(Element ele) { - return "HTTPFileArgs".equals(ele.getAttribute("elementType")); + return "HTTPFileArgs".equals(ele.attributeValue("elementType")); } private void processCsvDataSet(Element element) { - NodeList childNodes = element.getChildNodes(); - for (int i = 0; i < childNodes.getLength(); i++) { - Node item = childNodes.item(i); - if (item instanceof Element && nodeNameEquals(item, STRING_PROP)) { - String filenameTag = ((Element) item).getAttribute("name"); + List childNodes = element.elements(); + for (Element item : childNodes) { + if (nodeNameEquals(item, STRING_PROP)) { + String filenameTag = item.attributeValue("name"); if (StringUtils.equals(filenameTag, "filename")) { // 截取文件名 handleFilename(item); @@ -283,7 +244,7 @@ public class JmeterDocumentParser implements DocumentParser { } double[] ratios = context.getRatios(); int resourceIndex = context.getResourceIndex(); - String filename = item.getTextContent(); + String filename = item.getText(); byte[] content = context.getTestResourceFiles().get(filename); if (content == null) { return; @@ -342,16 +303,14 @@ public class JmeterDocumentParser implements DocumentParser { } private void processResponseAssertion(Element element) { - NodeList childNodes = element.getChildNodes(); - for (int i = 0; i < childNodes.getLength(); i++) { - Node item = childNodes.item(i); - if (item instanceof Element && nodeNameEquals(item, "collectionProp")) { - Document document = item.getOwnerDocument(); + List childNodes = element.elements(); + for (Element item : childNodes) { + if (nodeNameEquals(item, "collectionProp")) { Object params = context.getProperty("statusCode"); if (params instanceof List) { HashSet set = new HashSet((List) params); for (Object p : set) { - item.appendChild(createStringProp(document, p.toString(), p.toString())); + appendStringProp(item, p.toString(), p.toString()); } } } @@ -362,27 +321,21 @@ public class JmeterDocumentParser implements DocumentParser { if (context.getProperty("statusCode") == null || JSON.parseArray(context.getProperty("statusCode").toString()).size() == 0) { return; } - Document document = element.getOwnerDocument(); + Element hashTree = getNextSibling(element); - Node hashTree = element.getNextSibling(); - while (!(hashTree instanceof Element)) { - hashTree = hashTree.getNextSibling(); - } - - NodeList childNodes = hashTree.getChildNodes(); - for (int i = 0, l = childNodes.getLength(); i < l; i++) { - Node item = childNodes.item(i); + List childNodes = hashTree.elements(); + for (Element item : childNodes) { if (nodeNameEquals(item, RESPONSE_ASSERTION)) { // 如果已经存在,不再添加 removeChildren(item); - Element collectionProp = document.createElement(COLLECTION_PROP); - collectionProp.setAttribute("name", "Asserion.test_strings"); + Element collectionProp = item.addElement(COLLECTION_PROP); + collectionProp.addAttribute("name", "Asserion.test_strings"); // - item.appendChild(collectionProp); - item.appendChild(createStringProp(document, "Assertion.custom_message", "")); - item.appendChild(createStringProp(document, "Assertion.test_field", "Assertion.response_code")); - item.appendChild(createBoolProp(document, "Assertion.assume_success", true)); - item.appendChild(createIntProp(document, "Assertion.test_type", 40)); + + appendStringProp(item, "Assertion.custom_message", ""); + appendStringProp(item, "Assertion.test_field", "Assertion.response_code"); + appendBoolProp(item, "Assertion.assume_success", true); + appendIntProp(item, "Assertion.test_type", 40); return; } } @@ -400,35 +353,30 @@ public class JmeterDocumentParser implements DocumentParser { */ // add class name - Element responseAssertion = document.createElement(RESPONSE_ASSERTION); - responseAssertion.setAttribute("guiclass", "AssertionGui"); - responseAssertion.setAttribute("testclass", "ResponseAssertion"); - responseAssertion.setAttribute("testname", "Response Assertion"); - responseAssertion.setAttribute("enabled", "true"); - Element collectionProp = document.createElement(COLLECTION_PROP); - collectionProp.setAttribute("name", "Asserion.test_strings"); + Element responseAssertion = hashTree.addElement(RESPONSE_ASSERTION); + responseAssertion.addAttribute("guiclass", "AssertionGui"); + responseAssertion.addAttribute("testclass", "ResponseAssertion"); + responseAssertion.addAttribute("testname", "Response Assertion"); + responseAssertion.addAttribute("enabled", "true"); + Element collectionProp = responseAssertion.addElement(COLLECTION_PROP); + collectionProp.addAttribute("name", "Asserion.test_strings"); // - responseAssertion.appendChild(collectionProp); - responseAssertion.appendChild(createStringProp(document, "Assertion.custom_message", "")); - responseAssertion.appendChild(createStringProp(document, "Assertion.test_field", "Assertion.response_code")); - responseAssertion.appendChild(createBoolProp(document, "Assertion.assume_success", true)); - responseAssertion.appendChild(createIntProp(document, "Assertion.test_type", 40)); - hashTree.appendChild(responseAssertion); - hashTree.appendChild(document.createElement(HASH_TREE_ELEMENT)); + appendStringProp(responseAssertion, "Assertion.custom_message", ""); + appendStringProp(responseAssertion, "Assertion.test_field", "Assertion.response_code"); + appendBoolProp(responseAssertion, "Assertion.assume_success", true); + appendIntProp(responseAssertion, "Assertion.test_type", 40); + + hashTree.addElement(HASH_TREE_ELEMENT); } private void processCheckoutArguments(Element ele) { if (context.getProperty("params") == null || JSON.parseArray(context.getProperty("params").toString()).size() == 0) { return; } - Node hashTree = ele.getNextSibling(); - while (!(hashTree instanceof Element)) { - hashTree = hashTree.getNextSibling(); - } + Element hashTree = getNextSibling(ele); - NodeList childNodes = hashTree.getChildNodes(); - for (int i = 0, size = childNodes.getLength(); i < size; i++) { - Node item = childNodes.item(i); + List childNodes = hashTree.elements(); + for (Element item : childNodes) { if (nodeNameEquals(item, ARGUMENTS)) { // 已经存在不再添加 return; @@ -446,32 +394,27 @@ public class JmeterDocumentParser implements DocumentParser { */ - Document document = ele.getOwnerDocument(); - Element element = document.createElement(ARGUMENTS); - element.setAttribute("guiclass", "ArgumentsPanel"); - element.setAttribute("testclass", "Arguments"); - element.setAttribute("testname", "User Defined Variables"); - element.setAttribute("enabled", "true"); - Element collectionProp = document.createElement(COLLECTION_PROP); - collectionProp.setAttribute("name", "Arguments.arguments"); - element.appendChild(collectionProp); - hashTree.appendChild(element); + Element element = ele.addElement(ARGUMENTS); + element.addAttribute("guiclass", "ArgumentsPanel"); + element.addAttribute("testclass", "Arguments"); + element.addAttribute("testname", "User Defined Variables"); + element.addAttribute("enabled", "true"); + Element collectionProp = element.addElement(COLLECTION_PROP); + collectionProp.addAttribute("name", "Arguments.arguments"); + // 空的 hashTree - hashTree.appendChild(document.createElement(HASH_TREE_ELEMENT)); + hashTree.addElement(HASH_TREE_ELEMENT); } private void processCheckoutConfigTestElement(Element ele) { if (context.getProperty("timeout") == null || StringUtils.isBlank(context.getProperty("timeout").toString())) { return; } - Node hashTree = ele.getNextSibling(); - while (!(hashTree instanceof Element)) { - hashTree = hashTree.getNextSibling(); - } - NodeList childNodes = hashTree.getChildNodes(); - for (int i = 0, size = childNodes.getLength(); i < size; i++) { - Node item = childNodes.item(i); + Element hashTree = getNextSibling(ele); + + List childNodes = hashTree.elements(); + for (Element item : childNodes) { if (nodeNameEquals(item, CONFIG_TEST_ELEMENT)) { // 已经存在不再添加 return; @@ -494,42 +437,56 @@ public class JmeterDocumentParser implements DocumentParser { */ - Document document = ele.getOwnerDocument(); - Element element = document.createElement(CONFIG_TEST_ELEMENT); - element.setAttribute("guiclass", "HttpDefaultsGui"); - element.setAttribute("testclass", "ConfigTestElement"); - element.setAttribute("testname", "HTTP Request Defaults"); - element.setAttribute("enabled", "true"); - Element elementProp = document.createElement("elementProp"); - elementProp.setAttribute("name", "HTTPsampler.Arguments"); - elementProp.setAttribute("elementType", "Arguments"); - elementProp.setAttribute("guiclass", "HTTPArgumentsPanel"); - elementProp.setAttribute("testclass", "Arguments"); - elementProp.setAttribute("enabled", "true"); - Element collectionProp = document.createElement(COLLECTION_PROP); - collectionProp.setAttribute("name", "Arguments.arguments"); - elementProp.appendChild(collectionProp); - element.appendChild(elementProp); - element.appendChild(createStringProp(document, "HTTPSampler.domain", "")); - element.appendChild(createStringProp(document, "HTTPSampler.port", "")); - element.appendChild(createStringProp(document, "HTTPSampler.protocol", "")); - element.appendChild(createStringProp(document, "HTTPSampler.contentEncoding", "")); - element.appendChild(createStringProp(document, "HTTPSampler.path", "")); - element.appendChild(createStringProp(document, "HTTPSampler.concurrentPool", "6")); - element.appendChild(createStringProp(document, "HTTPSampler.connect_timeout", "60000")); - element.appendChild(createStringProp(document, "HTTPSampler.response_timeout", "")); - hashTree.appendChild(element); + + Element element = hashTree.addElement(CONFIG_TEST_ELEMENT); + element.addAttribute("guiclass", "HttpDefaultsGui"); + element.addAttribute("testclass", "ConfigTestElement"); + element.addAttribute("testname", "HTTP Request Defaults"); + element.addAttribute("enabled", "true"); + + Element elementProp = element.addElement(ELEMENT_PROP); + elementProp.addAttribute("name", "HTTPsampler.Arguments"); + elementProp.addAttribute("elementType", "Arguments"); + elementProp.addAttribute("guiclass", "HTTPArgumentsPanel"); + elementProp.addAttribute("testclass", "Arguments"); + elementProp.addAttribute("enabled", "true"); + + Element collectionProp = elementProp.addElement(COLLECTION_PROP); + collectionProp.addAttribute("name", "Arguments.arguments"); + + + appendStringProp(element, "HTTPSampler.domain", ""); + appendStringProp(element, "HTTPSampler.port", ""); + appendStringProp(element, "HTTPSampler.protocol", ""); + appendStringProp(element, "HTTPSampler.contentEncoding", ""); + appendStringProp(element, "HTTPSampler.path", ""); + appendStringProp(element, "HTTPSampler.concurrentPool", "6"); + appendStringProp(element, "HTTPSampler.connect_timeout", "60000"); + appendStringProp(element, "HTTPSampler.response_timeout", ""); + // 空的 hashTree - hashTree.appendChild(document.createElement(HASH_TREE_ELEMENT)); + hashTree.addElement(HASH_TREE_ELEMENT); + } + + private Element getNextSibling(Element ele) { + Element parent = ele.getParent(); + if (parent != null) { + Iterator iterator = parent.elementIterator(); + while (iterator.hasNext()) { + Element next = iterator.next(); + if (ele.equals(next)) { + return iterator.next(); + } + } + } + return null; } private void processArguments(Element ele) { - NodeList childNodes = ele.getChildNodes(); - for (int i = 0; i < childNodes.getLength(); i++) { - Node item = childNodes.item(i); - if (item instanceof Element && nodeNameEquals(item, "collectionProp")) { + List childNodes = ele.elements(); + for (Element item : childNodes) { + if (nodeNameEquals(item, "collectionProp")) { // - Document document = item.getOwnerDocument(); Object params = context.getProperty("params"); if (params instanceof List) { for (Object p : (List) params) { @@ -537,15 +494,14 @@ public class JmeterDocumentParser implements DocumentParser { if (!jsonObject.getBooleanValue("enable")) { continue; } - Element elementProp = document.createElement("elementProp"); - elementProp.setAttribute("name", jsonObject.getString("name")); - elementProp.setAttribute("elementType", "Argument"); - elementProp.appendChild(createStringProp(document, "Argument.name", jsonObject.getString("name"))); + Element elementProp = item.addElement(ELEMENT_PROP); + elementProp.addAttribute("name", jsonObject.getString("name")); + elementProp.addAttribute("elementType", "Argument"); + appendStringProp(elementProp, "Argument.name", jsonObject.getString("name")); // 处理 mock data String value = jsonObject.getString("value"); - elementProp.appendChild(createStringProp(document, "Argument.value", ScriptEngineUtils.buildFunctionCallString(value))); - elementProp.appendChild(createStringProp(document, "Argument.metadata", "=")); - item.appendChild(elementProp); + appendStringProp(elementProp, "Argument.value", ScriptEngineUtils.buildFunctionCallString(value)); + appendStringProp(elementProp, "Argument.metadata", "="); } } } @@ -555,39 +511,36 @@ public class JmeterDocumentParser implements DocumentParser { private void processConfigTestElement(Element ele) { - NodeList childNodes = ele.getChildNodes(); - for (int i = 0, size = childNodes.getLength(); i < size; i++) { - Node item = childNodes.item(i); - if (item instanceof Element && nodeNameEquals(item, STRING_PROP) - && StringUtils.equals(((Element) item).getAttribute("name"), "HTTPSampler.connect_timeout")) { + List childNodes = ele.elements(); + for (Element item : childNodes) { + if (nodeNameEquals(item, STRING_PROP) + && StringUtils.equals(item.attributeValue("name"), "HTTPSampler.connect_timeout")) { if (context.getProperty("timeout") != null) { removeChildren(item); - item.appendChild(ele.getOwnerDocument().createTextNode(context.getProperty("timeout").toString())); + item.setText(context.getProperty("timeout").toString()); } } // 增加一个response_timeout,避免目标网站不反回结果导致测试不能结束 - if (item instanceof Element && nodeNameEquals(item, STRING_PROP) - && StringUtils.equals(((Element) item).getAttribute("name"), "HTTPSampler.response_timeout")) { + if (nodeNameEquals(item, STRING_PROP) + && StringUtils.equals(item.attributeValue("name"), "HTTPSampler.response_timeout")) { if (context.getProperty("responseTimeout") != null) { removeChildren(item); - item.appendChild(ele.getOwnerDocument().createTextNode(context.getProperty("responseTimeout").toString())); + item.setText(context.getProperty("responseTimeout").toString()); } } } } - private Element createBoolProp(Document document, String name, boolean value) { - Element boolProp = document.createElement(BOOL_PROP); - boolProp.setAttribute("name", name); - boolProp.appendChild(document.createTextNode(String.valueOf(value))); - return boolProp; + private void appendBoolProp(Element ele, String name, boolean value) { + Element boolProp = ele.addElement(BOOL_PROP); + boolProp.addAttribute("name", name); + boolProp.setText(String.valueOf(value)); } - private Element createIntProp(Document document, String name, int value) { - Element intProp = document.createElement("intProp"); - intProp.setAttribute("name", name); - intProp.appendChild(document.createTextNode(String.valueOf(value))); - return intProp; + private void appendIntProp(Element ele, String name, int value) { + Element intProp = ele.addElement(BOOL_PROP); + intProp.addAttribute("name", name); + intProp.setText(String.valueOf(value)); } private void processBackendListener(Element backendListener) { @@ -597,62 +550,57 @@ public class JmeterDocumentParser implements DocumentParser { return; } KafkaProperties kafkaProperties = CommonBeanFactory.getBean(KafkaProperties.class); - Document document = backendListener.getOwnerDocument(); // 清空child removeChildren(backendListener); - backendListener.appendChild(createStringProp(document, "classname", "io.github.rahulsinghai.jmeter.backendlistener.kafka.KafkaBackendClient")); - backendListener.appendChild(createStringProp(document, "QUEUE_SIZE", kafkaProperties.getQueueSize())); + appendStringProp(backendListener, "classname", "io.github.rahulsinghai.jmeter.backendlistener.kafka.KafkaBackendClient"); + appendStringProp(backendListener, "QUEUE_SIZE", kafkaProperties.getQueueSize()); // elementProp - Element elementProp = document.createElement("elementProp"); - elementProp.setAttribute("name", "arguments"); - elementProp.setAttribute("elementType", "Arguments"); - elementProp.setAttribute("guiclass", "ArgumentsPanel"); - elementProp.setAttribute("testclass", "Arguments"); - elementProp.setAttribute("enabled", "true"); - Element collectionProp = document.createElement("collectionProp"); - collectionProp.setAttribute("name", "Arguments.arguments"); - collectionProp.appendChild(createKafkaProp(document, "kafka.acks", kafkaProperties.getAcks())); - collectionProp.appendChild(createKafkaProp(document, "kafka.bootstrap.servers", kafkaProperties.getBootstrapServers())); - collectionProp.appendChild(createKafkaProp(document, "kafka.topic", kafkaProperties.getTopic())); - collectionProp.appendChild(createKafkaProp(document, "kafka.sample.filter", kafkaProperties.getSampleFilter())); - collectionProp.appendChild(createKafkaProp(document, "kafka.fields", kafkaProperties.getFields())); - collectionProp.appendChild(createKafkaProp(document, "kafka.test.mode", kafkaProperties.getTestMode())); - collectionProp.appendChild(createKafkaProp(document, "kafka.parse.all.req.headers", kafkaProperties.getParseAllReqHeaders())); - collectionProp.appendChild(createKafkaProp(document, "kafka.parse.all.res.headers", kafkaProperties.getParseAllResHeaders())); - collectionProp.appendChild(createKafkaProp(document, "kafka.timestamp", kafkaProperties.getTimestamp())); - collectionProp.appendChild(createKafkaProp(document, "kafka.compression.type", kafkaProperties.getCompressionType())); - collectionProp.appendChild(createKafkaProp(document, "kafka.ssl.enabled", kafkaProperties.getSsl().getEnabled())); - collectionProp.appendChild(createKafkaProp(document, "kafka.ssl.key.password", kafkaProperties.getSsl().getKeyPassword())); - collectionProp.appendChild(createKafkaProp(document, "kafka.ssl.keystore.location", kafkaProperties.getSsl().getKeystoreLocation())); - collectionProp.appendChild(createKafkaProp(document, "kafka.ssl.keystore.password", kafkaProperties.getSsl().getKeystorePassword())); - collectionProp.appendChild(createKafkaProp(document, "kafka.ssl.truststore.location", kafkaProperties.getSsl().getTruststoreLocation())); - collectionProp.appendChild(createKafkaProp(document, "kafka.ssl.truststore.password", kafkaProperties.getSsl().getTruststorePassword())); - collectionProp.appendChild(createKafkaProp(document, "kafka.ssl.enabled.protocols", kafkaProperties.getSsl().getEnabledProtocols())); - collectionProp.appendChild(createKafkaProp(document, "kafka.ssl.keystore.type", kafkaProperties.getSsl().getKeystoreType())); - collectionProp.appendChild(createKafkaProp(document, "kafka.ssl.protocol", kafkaProperties.getSsl().getProtocol())); - collectionProp.appendChild(createKafkaProp(document, "kafka.ssl.provider", kafkaProperties.getSsl().getProvider())); - collectionProp.appendChild(createKafkaProp(document, "kafka.ssl.truststore.type", kafkaProperties.getSsl().getTruststoreType())); - collectionProp.appendChild(createKafkaProp(document, "kafka.batch.size", kafkaProperties.getBatchSize())); - collectionProp.appendChild(createKafkaProp(document, "kafka.client.id", kafkaProperties.getClientId())); - collectionProp.appendChild(createKafkaProp(document, "kafka.connections.max.idle.ms", kafkaProperties.getConnectionsMaxIdleMs())); + Element elementProp = backendListener.addElement(ELEMENT_PROP); + elementProp.addAttribute("name", "arguments"); + elementProp.addAttribute("elementType", "Arguments"); + elementProp.addAttribute("guiclass", "ArgumentsPanel"); + elementProp.addAttribute("testclass", "Arguments"); + elementProp.addAttribute("enabled", "true"); + Element collectionProp = elementProp.addElement("collectionProp"); + collectionProp.addAttribute("name", "Arguments.arguments"); + appendKafkaProp(collectionProp, "kafka.acks", kafkaProperties.getAcks()); + appendKafkaProp(collectionProp, "kafka.bootstrap.servers", kafkaProperties.getBootstrapServers()); + appendKafkaProp(collectionProp, "kafka.topic", kafkaProperties.getTopic()); + appendKafkaProp(collectionProp, "kafka.sample.filter", kafkaProperties.getSampleFilter()); + appendKafkaProp(collectionProp, "kafka.fields", kafkaProperties.getFields()); + appendKafkaProp(collectionProp, "kafka.test.mode", kafkaProperties.getTestMode()); + appendKafkaProp(collectionProp, "kafka.parse.all.req.headers", kafkaProperties.getParseAllReqHeaders()); + appendKafkaProp(collectionProp, "kafka.parse.all.res.headers", kafkaProperties.getParseAllResHeaders()); + appendKafkaProp(collectionProp, "kafka.timestamp", kafkaProperties.getTimestamp()); + appendKafkaProp(collectionProp, "kafka.compression.type", kafkaProperties.getCompressionType()); + appendKafkaProp(collectionProp, "kafka.ssl.enabled", kafkaProperties.getSsl().getEnabled()); + appendKafkaProp(collectionProp, "kafka.ssl.key.password", kafkaProperties.getSsl().getKeyPassword()); + appendKafkaProp(collectionProp, "kafka.ssl.keystore.location", kafkaProperties.getSsl().getKeystoreLocation()); + appendKafkaProp(collectionProp, "kafka.ssl.keystore.password", kafkaProperties.getSsl().getKeystorePassword()); + appendKafkaProp(collectionProp, "kafka.ssl.truststore.location", kafkaProperties.getSsl().getTruststoreLocation()); + appendKafkaProp(collectionProp, "kafka.ssl.truststore.password", kafkaProperties.getSsl().getTruststorePassword()); + appendKafkaProp(collectionProp, "kafka.ssl.enabled.protocols", kafkaProperties.getSsl().getEnabledProtocols()); + appendKafkaProp(collectionProp, "kafka.ssl.keystore.type", kafkaProperties.getSsl().getKeystoreType()); + appendKafkaProp(collectionProp, "kafka.ssl.protocol", kafkaProperties.getSsl().getProtocol()); + appendKafkaProp(collectionProp, "kafka.ssl.provider", kafkaProperties.getSsl().getProvider()); + appendKafkaProp(collectionProp, "kafka.ssl.truststore.type", kafkaProperties.getSsl().getTruststoreType()); + appendKafkaProp(collectionProp, "kafka.batch.size", kafkaProperties.getBatchSize()); + appendKafkaProp(collectionProp, "kafka.client.id", kafkaProperties.getClientId()); + appendKafkaProp(collectionProp, "kafka.connections.max.idle.ms", kafkaProperties.getConnectionsMaxIdleMs()); // 添加关联关系 test.id test.name test.startTime test.reportId - collectionProp.appendChild(createKafkaProp(document, "test.id", context.getTestId())); - collectionProp.appendChild(createKafkaProp(document, "test.name", context.getTestName())); - collectionProp.appendChild(createKafkaProp(document, "test.reportId", context.getReportId())); + appendKafkaProp(collectionProp, "test.id", context.getTestId()); + appendKafkaProp(collectionProp, "test.name", context.getTestName()); + appendKafkaProp(collectionProp, "test.reportId", context.getReportId()); - elementProp.appendChild(collectionProp); - // set elementProp - backendListener.appendChild(elementProp); } - private Element createKafkaProp(Document document, String name, String value) { - Element eleProp = document.createElement("elementProp"); - eleProp.setAttribute("name", name); - eleProp.setAttribute("elementType", "Argument"); - eleProp.appendChild(createStringProp(document, "Argument.name", name)); - eleProp.appendChild(createStringProp(document, "Argument.value", value)); - eleProp.appendChild(createStringProp(document, "Argument.metadata", "=")); - return eleProp; + private void appendKafkaProp(Element ele, String name, String value) { + Element eleProp = ele.addElement(ELEMENT_PROP); + eleProp.addAttribute("name", name); + eleProp.addAttribute("elementType", "Argument"); + appendStringProp(eleProp, "Argument.name", name); + appendStringProp(eleProp, "Argument.value", value); + appendStringProp(eleProp, "Argument.metadata", "="); } private void processCheckoutBackendListener(Element element) { @@ -662,21 +610,16 @@ public class JmeterDocumentParser implements DocumentParser { return; } - Document document = element.getOwnerDocument(); - - Node listenerParent = element.getNextSibling(); - while (!(listenerParent instanceof Element)) { - listenerParent = listenerParent.getNextSibling(); - } + Element listenerParent = getNextSibling(element); // add class name - Element backendListener = document.createElement(BACKEND_LISTENER); - backendListener.setAttribute("guiclass", "BackendListenerGui"); - backendListener.setAttribute("testclass", "BackendListener"); - backendListener.setAttribute("testname", "Backend Listener"); - backendListener.setAttribute("enabled", "true"); - listenerParent.appendChild(backendListener); - listenerParent.appendChild(document.createElement(HASH_TREE_ELEMENT)); + Element backendListener = listenerParent.addElement(BACKEND_LISTENER); + backendListener.addAttribute("guiclass", "BackendListenerGui"); + backendListener.addAttribute("testclass", "BackendListener"); + backendListener.addAttribute("testname", "Backend Listener"); + backendListener.addAttribute("enabled", "true"); + + listenerParent.addElement(HASH_TREE_ELEMENT); } private boolean checkLicense() { @@ -695,11 +638,8 @@ public class JmeterDocumentParser implements DocumentParser { private void processThreadGroup(Element threadGroup) { // 检查 threadgroup 后面的hashtree是否为空 - Node hashTree = threadGroup.getNextSibling(); - while (!(hashTree instanceof Element)) { - hashTree = hashTree.getNextSibling(); - } - if (!hashTree.hasChildNodes()) { + Element hashTree = getNextSibling(threadGroup); + if (hashTree == null) { MSException.throwException(Translator.get("jmx_content_valid")); } Object tgTypes = context.getProperty("tgType"); @@ -725,10 +665,9 @@ public class JmeterDocumentParser implements DocumentParser { } private void processBaseThreadGroup(Element threadGroup, String tgType) { - Document document = threadGroup.getOwnerDocument(); - document.renameNode(threadGroup, threadGroup.getNamespaceURI(), tgType); - threadGroup.setAttribute("guiclass", tgType + "Gui"); - threadGroup.setAttribute("testclass", tgType); + threadGroup.setName(tgType); + threadGroup.addAttribute("guiclass", tgType + "Gui"); + threadGroup.addAttribute("testclass", tgType); /* continue @@ -810,34 +749,33 @@ public class JmeterDocumentParser implements DocumentParser { enabled = o.toString(); } - threadGroup.setAttribute("enabled", enabled); + threadGroup.addAttribute("enabled", enabled); if (BooleanUtils.toBoolean(deleted)) { - threadGroup.setAttribute("enabled", "false"); + threadGroup.addAttribute("enabled", "false"); } - Element elementProp = document.createElement("elementProp"); - elementProp.setAttribute("name", "ThreadGroup.main_controller"); - elementProp.setAttribute("elementType", "LoopController"); - elementProp.setAttribute("guiclass", "LoopControlPanel"); - elementProp.setAttribute("testclass", "LoopController"); - elementProp.setAttribute("testname", "Loop Controller"); - elementProp.appendChild(createBoolProp(document, "LoopController.continue_forever", false)); - elementProp.appendChild(createStringProp(document, "LoopController.loops", "-1")); - threadGroup.appendChild(elementProp); - threadGroup.appendChild(createStringProp(document, "ThreadGroup.on_sample_error", onSampleError)); - threadGroup.appendChild(createStringProp(document, "ThreadGroup.num_threads", threads)); - threadGroup.appendChild(createStringProp(document, "ThreadGroup.ramp_time", rampUp)); - threadGroup.appendChild(createStringProp(document, "ThreadGroup.duration", duration)); - threadGroup.appendChild(createStringProp(document, "ThreadGroup.delay", "0")); - threadGroup.appendChild(createBoolProp(document, "ThreadGroup.scheduler", true)); - threadGroup.appendChild(createBoolProp(document, "ThreadGroup.same_user_on_next_iteration", true)); + Element elementProp = threadGroup.addElement(ELEMENT_PROP); + elementProp.addAttribute("name", "ThreadGroup.main_controller"); + elementProp.addAttribute("elementType", "LoopController"); + elementProp.addAttribute("guiclass", "LoopControlPanel"); + elementProp.addAttribute("testclass", "LoopController"); + elementProp.addAttribute("testname", "Loop Controller"); + appendBoolProp(elementProp, "LoopController.continue_forever", false); + appendStringProp(elementProp, "LoopController.loops", "-1"); + // + appendStringProp(threadGroup, "ThreadGroup.on_sample_error", onSampleError); + appendStringProp(threadGroup, "ThreadGroup.num_threads", threads); + appendStringProp(threadGroup, "ThreadGroup.ramp_time", rampUp); + appendStringProp(threadGroup, "ThreadGroup.duration", duration); + appendStringProp(threadGroup, "ThreadGroup.delay", "0"); + appendBoolProp(threadGroup, "ThreadGroup.scheduler", true); + appendBoolProp(threadGroup, "ThreadGroup.same_user_on_next_iteration", true); } private void processConcurrencyThreadGroup(Element threadGroup) { // 重命名 tagName - Document document = threadGroup.getOwnerDocument(); - document.renameNode(threadGroup, threadGroup.getNamespaceURI(), CONCURRENCY_THREAD_GROUP); - threadGroup.setAttribute("guiclass", CONCURRENCY_THREAD_GROUP + "Gui"); - threadGroup.setAttribute("testclass", CONCURRENCY_THREAD_GROUP); + threadGroup.setName(CONCURRENCY_THREAD_GROUP); + threadGroup.addAttribute("guiclass", CONCURRENCY_THREAD_GROUP + "Gui"); + threadGroup.addAttribute("testclass", CONCURRENCY_THREAD_GROUP); /* continue @@ -919,33 +857,29 @@ public class JmeterDocumentParser implements DocumentParser { enabled = o.toString(); } - threadGroup.setAttribute("enabled", enabled); + threadGroup.addAttribute("enabled", enabled); if (BooleanUtils.toBoolean(deleted)) { - threadGroup.setAttribute("enabled", "false"); + threadGroup.addAttribute("enabled", "false"); } - Element elementProp = document.createElement("elementProp"); - elementProp.setAttribute("name", "ThreadGroup.main_controller"); - elementProp.setAttribute("elementType", "com.blazemeter.jmeter.control.VirtualUserController"); - threadGroup.appendChild(elementProp); - threadGroup.appendChild(createStringProp(document, "ThreadGroup.on_sample_error", onSampleError)); - threadGroup.appendChild(createStringProp(document, "TargetLevel", threads)); - threadGroup.appendChild(createStringProp(document, "RampUp", rampUp)); - threadGroup.appendChild(createStringProp(document, "Steps", step)); - threadGroup.appendChild(createStringProp(document, "Hold", hold)); - threadGroup.appendChild(createStringProp(document, "LogFilename", "")); + Element elementProp = threadGroup.addElement(ELEMENT_PROP); + elementProp.addAttribute("name", "ThreadGroup.main_controller"); + elementProp.addAttribute("elementType", "com.blazemeter.jmeter.control.VirtualUserController"); + + appendStringProp(threadGroup, "ThreadGroup.on_sample_error", onSampleError); + appendStringProp(threadGroup, "TargetLevel", threads); + appendStringProp(threadGroup, "RampUp", rampUp); + appendStringProp(threadGroup, "Steps", step); + appendStringProp(threadGroup, "Hold", hold); + appendStringProp(threadGroup, "LogFilename", ""); // bzm - Concurrency Thread Group "Thread Iterations Limit:" 设置为空 // threadGroup.appendChild(createStringProp(document, "Iterations", "1")); - threadGroup.appendChild(createStringProp(document, "Unit", "S")); + appendStringProp(threadGroup, "Unit", "S"); } private void processIterationThreadGroup(Element threadGroup) { - Document document = threadGroup.getOwnerDocument(); // 检查 threadgroup 后面的hashtree是否为空 - Node hashTree = threadGroup.getNextSibling(); - while (!(hashTree instanceof Element)) { - hashTree = hashTree.getNextSibling(); - } - if (!hashTree.hasChildNodes()) { + Element hashTree = getNextSibling(threadGroup); + if (hashTree == null) { MSException.throwException(Translator.get("jmx_content_valid")); } Object tgTypes = context.getProperty("tgType"); @@ -956,19 +890,19 @@ public class JmeterDocumentParser implements DocumentParser { tgType = o.toString(); } if (StringUtils.equals(tgType, THREAD_GROUP)) { - document.renameNode(threadGroup, threadGroup.getNamespaceURI(), THREAD_GROUP); - threadGroup.setAttribute("guiclass", THREAD_GROUP + "Gui"); - threadGroup.setAttribute("testclass", THREAD_GROUP); + threadGroup.setName(THREAD_GROUP); + threadGroup.addAttribute("guiclass", THREAD_GROUP + "Gui"); + threadGroup.addAttribute("testclass", THREAD_GROUP); } if (StringUtils.equals(tgType, SETUP_THREAD_GROUP)) { - document.renameNode(threadGroup, threadGroup.getNamespaceURI(), SETUP_THREAD_GROUP); - threadGroup.setAttribute("guiclass", SETUP_THREAD_GROUP + "Gui"); - threadGroup.setAttribute("testclass", SETUP_THREAD_GROUP); + threadGroup.setName(SETUP_THREAD_GROUP); + threadGroup.addAttribute("guiclass", SETUP_THREAD_GROUP + "Gui"); + threadGroup.addAttribute("testclass", SETUP_THREAD_GROUP); } if (StringUtils.equals(tgType, POST_THREAD_GROUP)) { - document.renameNode(threadGroup, threadGroup.getNamespaceURI(), POST_THREAD_GROUP); - threadGroup.setAttribute("guiclass", POST_THREAD_GROUP + "Gui"); - threadGroup.setAttribute("testclass", POST_THREAD_GROUP); + threadGroup.setName(POST_THREAD_GROUP); + threadGroup.addAttribute("guiclass", POST_THREAD_GROUP + "Gui"); + threadGroup.addAttribute("testclass", POST_THREAD_GROUP); } removeChildren(threadGroup); @@ -1050,29 +984,28 @@ public class JmeterDocumentParser implements DocumentParser { ((List) enableds).remove(0); enabled = o.toString(); } - threadGroup.setAttribute("enabled", enabled); + threadGroup.addAttribute("enabled", enabled); if (BooleanUtils.toBoolean(deleted)) { - threadGroup.setAttribute("enabled", "false"); + threadGroup.addAttribute("enabled", "false"); } - Element elementProp = document.createElement("elementProp"); - elementProp.setAttribute("name", "ThreadGroup.main_controller"); - elementProp.setAttribute("elementType", "LoopController"); - elementProp.setAttribute("guiclass", "LoopControlPanel"); - elementProp.setAttribute("testclass", "LoopController"); - elementProp.setAttribute("testname", "Loop Controller"); - elementProp.setAttribute("enabled", "true"); - elementProp.appendChild(createBoolProp(document, "LoopController.continue_forever", false)); - elementProp.appendChild(createStringProp(document, "LoopController.loops", loops)); - threadGroup.appendChild(elementProp); + Element elementProp = threadGroup.addElement(ELEMENT_PROP); + elementProp.addAttribute("name", "ThreadGroup.main_controller"); + elementProp.addAttribute("elementType", "LoopController"); + elementProp.addAttribute("guiclass", "LoopControlPanel"); + elementProp.addAttribute("testclass", "LoopController"); + elementProp.addAttribute("testname", "Loop Controller"); + elementProp.addAttribute("enabled", "true"); + appendBoolProp(elementProp, "LoopController.continue_forever", false); + appendStringProp(elementProp, "LoopController.loops", loops); - threadGroup.appendChild(createStringProp(document, "ThreadGroup.on_sample_error", onSampleError)); - threadGroup.appendChild(createStringProp(document, "ThreadGroup.num_threads", threads)); - threadGroup.appendChild(createStringProp(document, "ThreadGroup.ramp_time", rampUp)); - threadGroup.appendChild(createBoolProp(document, "ThreadGroup.scheduler", false)); // 不指定执行时间 - threadGroup.appendChild(createStringProp(document, "Hold", "1")); - threadGroup.appendChild(createStringProp(document, "ThreadGroup.duration", "10")); - threadGroup.appendChild(createStringProp(document, "ThreadGroup.delay", "")); - threadGroup.appendChild(createBoolProp(document, "ThreadGroup.same_user_on_next_iteration", true)); + appendStringProp(threadGroup, "ThreadGroup.on_sample_error", onSampleError); + appendStringProp(threadGroup, "ThreadGroup.num_threads", threads); + appendStringProp(threadGroup, "ThreadGroup.ramp_time", rampUp); + appendBoolProp(threadGroup, "ThreadGroup.scheduler", false); + appendStringProp(threadGroup, "Hold", "1"); + appendStringProp(threadGroup, "ThreadGroup.duration", "10"); + appendStringProp(threadGroup, "ThreadGroup.delay", ""); + appendBoolProp(threadGroup, "ThreadGroup.same_user_on_next_iteration", true); } private void processCheckoutTimer(Element element) { @@ -1099,53 +1032,42 @@ public class JmeterDocumentParser implements DocumentParser { } } - Document document = element.getOwnerDocument(); + Element timerParent = getNextSibling(element); - - Node timerParent = element.getNextSibling(); - while (!(timerParent instanceof Element)) { - timerParent = timerParent.getNextSibling(); - } - - NodeList childNodes = timerParent.getChildNodes(); - for (int i = 0, l = childNodes.getLength(); i < l; i++) { - Node item = childNodes.item(i); + List childNodes = timerParent.elements(); + for (Element item : childNodes) { if (nodeNameEquals(item, VARIABLE_THROUGHPUT_TIMER)) { // 如果已经存在,不再添加 return; } } - Element timer = document.createElement(VARIABLE_THROUGHPUT_TIMER); - timer.setAttribute("guiclass", VARIABLE_THROUGHPUT_TIMER + "Gui"); - timer.setAttribute("testclass", VARIABLE_THROUGHPUT_TIMER); - timer.setAttribute("testname", "jp@gc - Throughput Shaping Timer"); - timer.setAttribute("enabled", "true"); + Element timer = timerParent.addElement(VARIABLE_THROUGHPUT_TIMER); + timer.addAttribute("guiclass", VARIABLE_THROUGHPUT_TIMER + "Gui"); + timer.addAttribute("testclass", VARIABLE_THROUGHPUT_TIMER); + timer.addAttribute("testname", "jp@gc - Throughput Shaping Timer"); + timer.addAttribute("enabled", "true"); - Element collectionProp = document.createElement("collectionProp"); - collectionProp.setAttribute("name", "load_profile"); - Element childCollectionProp = document.createElement("collectionProp"); - childCollectionProp.setAttribute("name", "140409499"); - childCollectionProp.appendChild(createStringProp(document, "49", "1")); - childCollectionProp.appendChild(createStringProp(document, "49", "1")); - childCollectionProp.appendChild(createStringProp(document, "1570", "10")); - collectionProp.appendChild(childCollectionProp); - timer.appendChild(collectionProp); - timerParent.appendChild(timer); + Element collectionProp = timer.addElement("collectionProp"); + collectionProp.addAttribute("name", "load_profile"); + Element childCollectionProp = collectionProp.addElement("collectionProp"); + childCollectionProp.addAttribute("name", "140409499"); + appendStringProp(childCollectionProp, "49", "1"); + appendStringProp(childCollectionProp, "49", "1"); + appendStringProp(childCollectionProp, "1570", "10"); // 添加一个空的hashTree - timerParent.appendChild(document.createElement(HASH_TREE_ELEMENT)); + timerParent.addElement(HASH_TREE_ELEMENT); } - private Element createStringProp(Document document, String name, String value) { - Element element = document.createElement(STRING_PROP); - element.setAttribute("name", name); - element.appendChild(document.createTextNode(value)); - return element; + private void appendStringProp(Element element, String name, String value) { + Element ele = element.addElement(STRING_PROP); + ele.addAttribute("name", name); + ele.setText(value); } private void processThreadGroupName(Element threadGroup) { - String testname = threadGroup.getAttribute("testname"); - threadGroup.setAttribute("testname", testname + "-" + context.getResourceIndex()); + String testname = threadGroup.attributeValue("testname"); + threadGroup.addAttribute("testname", testname + "-" + context.getResourceIndex()); } private void processVariableThroughputTimer(Element variableThroughputTimer) { @@ -1160,35 +1082,31 @@ public class JmeterDocumentParser implements DocumentParser { } else { rpsLimit = rpsLimits.toString(); } - if (variableThroughputTimer.getChildNodes().getLength() > 0) { - final NodeList childNodes = variableThroughputTimer.getChildNodes(); - for (int i = 0; i < childNodes.getLength(); i++) { - Node node = childNodes.item(i); - if (node instanceof Element) { - Element ele = (Element) node; + if (variableThroughputTimer.elements().size() > 0) { + List childNodes = variableThroughputTimer.elements(); + for (Element ele : childNodes) { + if (ele != null) { if (invalid(ele)) { continue; } // TODO kg.apc.jmeter.timers.VariableThroughputTimer的stringProp的name属性是动态的 if (nodeNameEquals(ele, COLLECTION_PROP)) { - NodeList eleChildNodes = ele.getChildNodes(); - for (int j = 0; j < eleChildNodes.getLength(); j++) { - Node item = eleChildNodes.item(j); + List eleChildNodes = ele.elements(); + for (Element item : eleChildNodes) { if (nodeNameEquals(item, COLLECTION_PROP)) { int stringPropCount = 0; - NodeList itemChildNodes = item.getChildNodes(); - for (int k = 0; k < itemChildNodes.getLength(); k++) { - Node prop = itemChildNodes.item(k); + List itemChildNodes = item.elements(); + for (Element prop : itemChildNodes) { if (nodeNameEquals(prop, STRING_PROP)) { if (stringPropCount < 2) { stringPropCount++; } else { stringPropCount = 0; - prop.getFirstChild().setNodeValue(String.valueOf(duration)); + prop.setText(String.valueOf(duration)); continue; } - prop.getFirstChild().setNodeValue(rpsLimit); + prop.setText(rpsLimit); } } } @@ -1201,30 +1119,18 @@ public class JmeterDocumentParser implements DocumentParser { } } - private void parseStringProp(Element stringProp) { - Object threadParams = context.getProperty(stringProp.getAttribute("name")); - if (stringProp.getChildNodes().getLength() > 0 && threadParams != null) { - if (threadParams instanceof List) { - Object o = ((List) threadParams).get(0); - ((List) threadParams).remove(0); - stringProp.getFirstChild().setNodeValue(o.toString()); - } else { - stringProp.getFirstChild().setNodeValue(threadParams.toString()); - } - } - } - - private boolean nodeNameEquals(Node node, String desiredName) { - return desiredName.equals(node.getNodeName()) || desiredName.equals(node.getLocalName()); + private boolean nodeNameEquals(Element element, String desiredName) { + return desiredName.equals(element.getName()); } private boolean invalid(Element ele) { - return !StringUtils.isBlank(ele.getAttribute("enabled")) && !Boolean.parseBoolean(ele.getAttribute("enabled")); + return !StringUtils.isBlank(ele.attributeValue("enabled")) && !Boolean.parseBoolean(ele.attributeValue("enabled")); } - private void removeChildren(Node node) { - while (node.hasChildNodes()) { - node.removeChild(node.getFirstChild()); + private void removeChildren(Element node) { + List elements = node.elements(); + for (Element ele : elements) { + node.remove(ele); } } } diff --git a/backend/src/main/java/io/metersphere/performance/service/JmeterFileService.java b/backend/src/main/java/io/metersphere/performance/service/JmeterFileService.java index 1b206a28eb..c2f2fbc68d 100644 --- a/backend/src/main/java/io/metersphere/performance/service/JmeterFileService.java +++ b/backend/src/main/java/io/metersphere/performance/service/JmeterFileService.java @@ -13,7 +13,6 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -60,11 +59,11 @@ public class JmeterFileService { Map files = new HashMap<>(); // 每个测试生成一个文件夹 - files.put(fileName, context.getContent().getBytes(StandardCharsets.UTF_8)); + files.put(fileName, context.getContent()); // 保存jmx LoadTestReportWithBLOBs record = new LoadTestReportWithBLOBs(); record.setId(context.getReportId()); - record.setJmxContent(context.getContent()); + record.setJmxContent(new String(context.getContent())); extLoadTestReportMapper.updateJmxContentIfAbsent(record); // 保存 byte[] Map jarFiles = context.getTestResourceFiles();