/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.wss4j.performance; import org.apache.wss4j.common.ext.WSSecurityException; import org.apache.wss4j.dom.handler.WSHandlerConstants; import org.apache.xml.security.stax.securityEvent.SecurityEvent; import org.apache.wss4j.stax.WSSec; import org.apache.wss4j.stax.ext.InboundWSSec; import org.apache.wss4j.stax.ext.OutboundWSSec; import org.apache.wss4j.stax.ext.WSSConstants; import org.apache.wss4j.stax.ext.WSSSecurityProperties; import org.apache.wss4j.stax.test.CallbackHandlerImpl; import org.apache.wss4j.stax.test.utils.XmlReaderToWriter; import org.testng.annotations.*; import org.w3c.dom.Document; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; 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.*; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Properties; public class PerformanceMemoryTest extends AbstractTestBase { private FileWriter outSamples; @BeforeClass public void createDir() throws Exception { new File("target/performanceMemoryTest").mkdirs(); } @BeforeGroups(groups = {"memory-out"}) public void createSampleFileOut() throws Exception { outSamples = new FileWriter("target/memory-out-samples.txt"); } //warm up. @BeforeMethod(groups = {"memory-out"}) public void setUpOut() throws Exception { File input = genBigFile(1); doDOMSecurityOutbound(input, new File("target/performanceMemoryTest/bigfile-dom.xml")); doStreamingSecurityOutbound(input, new File("target/performanceMemoryTest/bigfile-stream.xml")); } @AfterGroups(groups = {"memory-out"}) public void tearDownOut() throws Exception { outSamples.close(); } @DataProvider(name = "xmlsizes") public Object[][] getXMLSizes() throws Exception { genBigFile(1); int tagCount = 0; File target = new File("target/performanceMemoryTest/tmp.xml"); XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(new BufferedInputStream(new FileInputStream(target))); while (xmlStreamReader.hasNext()) { int eventType = xmlStreamReader.next(); if (eventType == XMLStreamConstants.START_ELEMENT) { tagCount++; } } /*Object[][] objectArray = new Object[1][2]; objectArray[0][0] = 10; objectArray[0][1] = (tagCount - 4) * 10;*/ int size = 16; Object[][] objectArray = new Object[size][2]; for (int i = 0; i < size; i++) { objectArray[i][0] = i + 1; objectArray[i][1] = (tagCount - 4) * (i + 1) * 40; } return objectArray; } @BeforeGroups(groups = {"memory-out"}, dependsOnMethods = {"createSampleFileOut"}) public void printTagCountsOut() throws Exception { Object[][] sizes = getXMLSizes(); for (int i = 0; i < sizes.length; i++) { Object[] size = sizes[i]; outSamples.write("" + size[1] + " "); } } @Test(groups = "memory-out", dataProvider = "xmlsizes", dependsOnMethods = {"doBeforeStreamOut"}) public void testOutStreamingMemoryPerformance(int run, int tagCount) throws Exception { System.out.println("Run " + run); File input = genBigFile(run * 40); long startMem = getUsedMemory(); ThreadStopper threadStopper = new ThreadStopper(); Thread thread = new Thread(new MemorySamplerThread(threadStopper, outSamples, startMem)); thread.setPriority(9); thread.start(); doStreamingSecurityOutbound(input, new File("target/performanceMemoryTest/stream-" + tagCount + ".xml")); threadStopper.setStop(true); thread.join(); } @Test(groups = "memory-out", dataProvider = "xmlsizes", dependsOnMethods = {"doBeforeStreamCompressedOut"}) public void testOutStreamingCompressedMemoryPerformance(int run, int tagCount) throws Exception { System.out.println("Run " + run); File input = genBigFile(run * 40); long startMem = getUsedMemory(); ThreadStopper threadStopper = new ThreadStopper(); Thread thread = new Thread(new MemorySamplerThread(threadStopper, outSamples, startMem)); thread.setPriority(9); thread.start(); doStreamingSecurityOutboundCompressed(input, new File("target/performanceMemoryTest/stream-compressed-" + tagCount + ".xml"), "http://www.apache.org/2012/04/xmlsec/gzip"); threadStopper.setStop(true); thread.join(); } @Test(groups = "memory-out", dataProvider = "xmlsizes", dependsOnMethods = {"doBeforeDOMOut"}) public void testOutDOMMemoryPerformance(int run, int tagCount) throws Exception { System.out.println("Run " + run); File input = genBigFile(run * 40); long startMem = getUsedMemory(); ThreadStopper threadStopper = new ThreadStopper(); Thread thread = new Thread(new MemorySamplerThread(threadStopper, outSamples, startMem)); thread.setPriority(9); thread.start(); doDOMSecurityOutbound(input, new File("target/performanceMemoryTest/dom-" + tagCount + ".xml")); threadStopper.setStop(true); thread.join(); } @Test(groups = {"memory-out"}) public void doBeforeDOMOut() throws Exception { outSamples.write("\n"); } @Test(groups = {"memory-out"}) public void doBeforeStreamOut() throws Exception { outSamples.write("\n"); } @Test(groups = {"memory-out"}) public void doBeforeStreamCompressedOut() throws Exception { outSamples.write("\n"); } @Test(groups = {"memory-in"}) public void doBeforeDOMIn() throws Exception { inSamples.write("\n"); } @Test(groups = {"memory-in"}) public void doBeforeStreamIn() throws Exception { inSamples.write("\n"); } @Test(groups = {"memory-in"}) public void doBeforeStreamCompressedIn() throws Exception { inSamples.write("\n"); } private FileWriter inSamples; @BeforeGroups(groups = {"memory-in"}) public void createSampleFileIn() throws Exception { inSamples = new FileWriter("target/memory-in-samples.txt"); } //warm up. @BeforeMethod(groups = {"memory-in"}, dependsOnGroups = {"memory-out"}) public void setUpIn() throws Exception { genBigFile(1); doDOMInSecurity(new File("target/performanceMemoryTest/bigfile-dom.xml")); doStreamingInSecurity(new File("target/performanceMemoryTest/bigfile-stream.xml")); } @AfterGroups(groups = {"memory-in"}) public void tearDownIn() throws Exception { inSamples.close(); } @BeforeGroups(groups = {"memory-in"}, dependsOnMethods = {"createSampleFileIn"}) public void printTagCountsIn() throws Exception { Object[][] sizes = getXMLSizes(); for (int i = 0; i < sizes.length; i++) { Object[] size = sizes[i]; inSamples.write("" + size[1] + " "); } } @Test(groups = "memory-in", dataProvider = "xmlsizes", dependsOnMethods = {"doBeforeStreamIn", "testOutStreamingMemoryPerformance"}) public void testInboundStreamingMemoryPerformance(int run, int tagCount) throws Exception { System.out.println("Run " + run); long startMem = getUsedMemory(); ThreadStopper threadStopper = new ThreadStopper(); Thread thread = new Thread(new MemorySamplerThread(threadStopper, inSamples, startMem)); thread.setPriority(9); thread.start(); doStreamingInSecurity(new File("target/performanceMemoryTest/stream-" + tagCount + ".xml")); threadStopper.setStop(true); thread.join(); } @Test(groups = "memory-in", dataProvider = "xmlsizes", dependsOnMethods = {"doBeforeStreamCompressedIn", "testOutStreamingCompressedMemoryPerformance"}) public void testInboundStreamingCompressedMemoryPerformance(int run, int tagCount) throws Exception { System.out.println("Run " + run); long startMem = getUsedMemory(); ThreadStopper threadStopper = new ThreadStopper(); Thread thread = new Thread(new MemorySamplerThread(threadStopper, inSamples, startMem)); thread.setPriority(9); thread.start(); doStreamingInSecurity(new File("target/performanceMemoryTest/stream-compressed-" + tagCount + ".xml")); threadStopper.setStop(true); thread.join(); } @Test(groups = "memory-in", dataProvider = "xmlsizes", dependsOnMethods = {"doBeforeDOMIn", "testOutDOMMemoryPerformance"}) public void testInboundDOMMemoryPerformance(int run, int tagCount) throws Exception { System.out.println("Run " + run); long startMem = getUsedMemory(); ThreadStopper threadStopper = new ThreadStopper(); Thread thread = new Thread(new MemorySamplerThread(threadStopper, inSamples, startMem)); thread.setPriority(9); thread.start(); doDOMInSecurity(new File("target/performanceMemoryTest/dom-" + tagCount + ".xml")); threadStopper.setStop(true); thread.join(); } private OutboundWSSec outboundWSSec; private void doStreamingSecurityOutbound(File source, File output) throws Exception { if (outboundWSSec == null) { WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.setEncryptionUser("receiver"); securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); securityProperties.setSignatureUser("transmitter"); securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); List<WSSConstants.Action> actions = new ArrayList<WSSConstants.Action>(); actions.add(WSSConstants.TIMESTAMP); actions.add(WSSConstants.SIGNATURE); actions.add(WSSConstants.ENCRYPT); securityProperties.setActions(actions); securityProperties.setTimestampTTL(60 * 60 * 24 * 7); //a week for testing:) outboundWSSec = WSSec.getOutboundWSSec(securityProperties); } InputStream sourceDocument = new BufferedInputStream(new FileInputStream(source)); XMLStreamWriter xmlStreamWriter = outboundWSSec.processOutMessage(new BufferedOutputStream(new FileOutputStream(output)), "UTF-8", new ArrayList<>()); XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(sourceDocument); XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter); xmlStreamWriter.close(); xmlStreamReader.close(); } private OutboundWSSec outboundWSSecCompressed; private void doStreamingSecurityOutboundCompressed(File source, File output, String compress) throws Exception { if (outboundWSSecCompressed == null) { WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.setEncryptionUser("receiver"); securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); securityProperties.setSignatureUser("transmitter"); securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); List<WSSConstants.Action> actions = new ArrayList<WSSConstants.Action>(); actions.add(WSSConstants.TIMESTAMP); actions.add(WSSConstants.SIGNATURE); actions.add(WSSConstants.ENCRYPT); securityProperties.setActions(actions); securityProperties.setTimestampTTL(60 * 60 * 24 * 7); //a week for testing:) securityProperties.setEncryptionCompressionAlgorithm(compress); outboundWSSecCompressed = WSSec.getOutboundWSSec(securityProperties); } InputStream sourceDocument = new BufferedInputStream(new FileInputStream(source)); XMLStreamWriter xmlStreamWriter = outboundWSSecCompressed.processOutMessage(new BufferedOutputStream(new FileOutputStream(output)), "UTF-8", new ArrayList<>()); XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(sourceDocument); XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter); xmlStreamWriter.close(); xmlStreamReader.close(); } private void doDOMSecurityOutbound(File input, File output) throws WSSecurityException, FileNotFoundException, TransformerException { Properties properties = new Properties(); properties.setProperty(WSHandlerConstants.ENC_SYM_ALGO, "http://www.w3.org/2001/04/xmlenc#aes256-cbc"); properties.setProperty(WSHandlerConstants.ENC_KEY_TRANSPORT, "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"); properties.setProperty(WSHandlerConstants.TTL_TIMESTAMP, "" + 60 * 60 * 24 * 7); Document doc = doOutboundSecurityWithWSS4J(new FileInputStream(input), WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT, properties); Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.transform(new DOMSource(doc), new StreamResult(output)); } private File genBigFile(int factor) throws IOException { File target = new File("target/performanceMemoryTest/tmp.xml"); FileWriter fileWriter = new FileWriter(target, false); fileWriter.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<env:Envelope xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" + "<env:Header></env:Header>\n" + "<env:Body><test xmlns=\"http://www.example.com\">"); fileWriter.close(); FileOutputStream fileOutputStream = new FileOutputStream(target, true); for (int i = 0; i < factor; i++) { int read = 0; byte[] buffer = new byte[4096]; InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"); while ((read = inputStream.read(buffer)) != -1) { fileOutputStream.write(buffer, 0, read); } inputStream.close(); } fileOutputStream.close(); fileWriter = new FileWriter(target, true); fileWriter.write("</test></env:Body>\n" + "</env:Envelope>"); fileWriter.close(); return target; } private void doDOMInSecurity(File input) throws Exception { String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); properties.setProperty(WSHandlerConstants.TTL_TIMESTAMP, "" + 60 * 60 * 24 * 7); doInboundSecurityWithWSS4J_1(documentBuilderFactory.newDocumentBuilder().parse(input), action, properties, false); } private InboundWSSec inboundWSSec; private void doStreamingInSecurity(File input) throws Exception { if (inboundWSSec == null) { WSSSecurityProperties inSecurityProperties = new WSSSecurityProperties(); inSecurityProperties.setStrictTimestampCheck(false); inSecurityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); inSecurityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); inSecurityProperties.setCallbackHandler(new CallbackHandlerImpl()); inboundWSSec = WSSec.getInboundWSSec(inSecurityProperties); } InputStream fileInputStream = new BufferedInputStream(new FileInputStream(input)); XMLStreamReader outXmlStreamReader = inboundWSSec.processInMessage(xmlInputFactory.createXMLStreamReader(fileInputStream)); while (outXmlStreamReader.hasNext()) { outXmlStreamReader.next(); } fileInputStream.close(); outXmlStreamReader.close(); } private static void gc() { System.gc(); System.runFinalization(); System.gc(); } private static long getUsedMemory() { gc(); gc(); long totalMemory = Runtime.getRuntime().totalMemory(); long freeMemory = Runtime.getRuntime().freeMemory(); return totalMemory - freeMemory; } class ThreadStopper { private volatile boolean stop = false; public boolean isStop() { return stop; } public void setStop(boolean stop) { this.stop = stop; } } class MemorySamplerThread implements Runnable { private ThreadStopper threadStopper; private FileWriter fileWriter; private long memoryDiff; private List<Integer> memory = new LinkedList<Integer>(); MemorySamplerThread(ThreadStopper threadStopper, FileWriter fileWriter, long memoryDiff) { this.threadStopper = threadStopper; this.fileWriter = fileWriter; this.memoryDiff = memoryDiff; } @Override public void run() { int sleepTime = 100; while (!threadStopper.isStop()) { try { Thread.sleep(sleepTime); if (threadStopper.isStop()) { break; } } catch (InterruptedException e) { throw new RuntimeException(e); } //parentThread.suspend(); memory.add((int) (((getUsedMemory()) - memoryDiff) / 1024.0 / 1024.0)); //System.out.println("Sample: " + memory.get(memory.size() - 1)); //parentThread.resume(); } System.out.println("Collected " + memory.size() + " samples"); int maxMem = Integer.MIN_VALUE; for (int i = 0; i < memory.size(); i++) { //System.out.println("Sample: " + memory.get(i)); int mem = memory.get(i); maxMem = mem > maxMem ? mem : maxMem; } try { fileWriter.write("" + maxMem + " "); fileWriter.flush(); } catch (Exception e) { throw new RuntimeException(e); } System.out.println("Max memory usage: " + maxMem + "MB"); } } }