1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package transform; 25 26 import java.io.StringReader; 27 import java.io.StringWriter; 28 import java.util.concurrent.CyclicBarrier; 29 import java.util.concurrent.ExecutorService; 30 import java.util.concurrent.Executors; 31 import java.util.concurrent.TimeUnit; 32 import java.util.concurrent.atomic.AtomicBoolean; 33 34 import javax.xml.transform.Source; 35 import javax.xml.transform.Templates; 36 import javax.xml.transform.Transformer; 37 import javax.xml.transform.TransformerFactory; 38 import javax.xml.transform.stream.StreamResult; 39 import javax.xml.transform.stream.StreamSource; 40 41 import org.testng.annotations.Test; 42 import static org.testng.Assert.assertTrue; 43 import static jaxp.library.JAXPTestUtilities.runWithAllPerm; 44 45 /* 46 * @test 47 * @bug 8167179 48 * @library /javax/xml/jaxp/libs 49 * @run testng/othervm -DrunSecMngr=true -Djava.security.manager=allow transform.NamespacePrefixTest 50 * @run testng/othervm transform.NamespacePrefixTest 51 * @summary This class tests the generation of namespace prefixes 52 */ 53 public class NamespacePrefixTest { 54 55 @Test testReuseTemplates()56 public void testReuseTemplates() throws Exception { 57 final TransformerFactory tf = TransformerFactory.newInstance(); 58 final Source xslsrc = new StreamSource(new StringReader(XSL)); 59 final Templates tmpl = tf.newTemplates(xslsrc); 60 for (int i = 0; i < TRANSF_COUNT; i++) { 61 checkResult(doTransformation(tmpl.newTransformer())); 62 } 63 } 64 65 @Test testReuseTransformer()66 public void testReuseTransformer() throws Exception { 67 final TransformerFactory tf = TransformerFactory.newInstance(); 68 final Source xslsrc = new StreamSource(new StringReader(XSL)); 69 final Transformer t = tf.newTransformer(xslsrc); 70 for (int i = 0; i < TRANSF_COUNT; i++) { 71 checkResult(doTransformation(t)); 72 } 73 } 74 75 @Test testConcurrentTransformations()76 public void testConcurrentTransformations() throws Exception { 77 final TransformerFactory tf = TransformerFactory.newInstance(); 78 final Source xslsrc = new StreamSource(new StringReader(XSL)); 79 final Templates tmpl = tf.newTemplates(xslsrc); 80 concurrentTestPassed.set(true); 81 82 // Execute multiple TestWorker tasks 83 for (int id = 0; id < THREADS_COUNT; id++) { 84 EXECUTOR.execute(new TransformerThread(tmpl.newTransformer(), id)); 85 } 86 // Initiate shutdown of previously submitted task 87 runWithAllPerm(EXECUTOR::shutdown); 88 // Wait for termination of submitted tasks 89 if (!EXECUTOR.awaitTermination(THREADS_COUNT, TimeUnit.SECONDS)) { 90 // If not all tasks terminates during the time out force them to shutdown 91 runWithAllPerm(EXECUTOR::shutdownNow); 92 } 93 // Check if all transformation threads generated the correct namespace prefix 94 assertTrue(concurrentTestPassed.get()); 95 } 96 97 // Do one transformation with the provided transformer doTransformation(Transformer t)98 private static String doTransformation(Transformer t) throws Exception { 99 StringWriter resWriter = new StringWriter(); 100 Source xmlSrc = new StreamSource(new StringReader(XML)); 101 t.transform(xmlSrc, new StreamResult(resWriter)); 102 return resWriter.toString(); 103 } 104 105 // Check if the transformation result string contains the 106 // element with the exact namespace prefix generated. checkResult(String result)107 private static void checkResult(String result) { 108 // Check prefix of 'Element2' element, it should always be the same 109 assertTrue(result.contains(EXPECTED_CONTENT)); 110 } 111 112 // Check if the transformation result string contains the element with 113 // the exact namespace prefix generated by current thread. 114 // If the expected prefix is not found and there was no failures observed by 115 // other test threads then mark concurrent test as failed. checkThreadResult(String result, int id)116 private static void checkThreadResult(String result, int id) { 117 boolean res = result.contains(EXPECTED_CONTENT); 118 System.out.printf("%d: transformation result: %s%n", id, res ? "Pass" : "Fail"); 119 if (!res) { 120 System.out.printf("%d result:%s%n", id, result); 121 } 122 concurrentTestPassed.compareAndSet(true, res); 123 } 124 125 // TransformerThread task that does the transformation similar 126 // to testReuseTransformer test method 127 private class TransformerThread implements Runnable { 128 129 private final Transformer transformer; 130 private final int id; 131 TransformerThread(Transformer transformer, int id)132 TransformerThread(Transformer transformer, int id) { 133 this.transformer = transformer; 134 this.id = id; 135 } 136 137 @Override run()138 public void run() { 139 try { 140 System.out.printf("%d: waiting for barrier%n", id); 141 //Synchronize startup of all tasks 142 BARRIER.await(); 143 System.out.printf("%d: starting transformation%n", id); 144 checkThreadResult(doTransformation(transformer), id); 145 } catch (Exception ex) { 146 throw new RuntimeException("TransformerThread " + id + " failed", ex); 147 } 148 } 149 } 150 151 // Number of subsequent transformations 152 private static final int TRANSF_COUNT = 10; 153 154 // Number of transformer threads running concurently 155 private static final int THREADS_COUNT = 10; 156 157 // Variable for storing the concurrent transformation test result. It is 158 // updated by transformer threads 159 private static final AtomicBoolean concurrentTestPassed = new AtomicBoolean(true); 160 161 // Cyclic barrier for threads startup synchronization 162 private static final CyclicBarrier BARRIER = new CyclicBarrier(THREADS_COUNT); 163 164 // Thread pool 165 private static final ExecutorService EXECUTOR = Executors.newCachedThreadPool(); 166 167 // XSL that transforms XML and produces unique namespace prefixes for each element 168 private final static String XSL = "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n" 169 + " <xsl:template match=\"node()|@*\" priority=\"1\">\n" 170 + " <xsl:copy>\n" 171 + " <xsl:apply-templates select=\"node()|@*\"/>\n" 172 + " </xsl:copy>\n" 173 + " </xsl:template>\n" 174 + " <xsl:template match=\"*\" priority=\"2\">\n" 175 + " <xsl:element name=\"{name()}\" namespace=\"{namespace-uri()}\">\n" 176 + " <xsl:apply-templates select=\"node()|@*\"/>\n" 177 + " </xsl:element>\n" 178 + " </xsl:template>\n" 179 + "</xsl:stylesheet>"; 180 181 // Simple XML content with root and two child elements 182 private final static String XML = "<TestRoot xmlns=\"test.xmlns\">\n" 183 + " <Element1 xmlns=\"test.xmlns\">\n" 184 + " </Element1>\n" 185 + " <Element2 xmlns=\"test.xmlns\">\n" 186 + " </Element2>\n" 187 + "</TestRoot>"; 188 189 // With thread local namespace prefix index each transformation result should 190 // be the same and contain the same prefix for Element2 191 private final static String EXPECTED_CONTENT = "</ns2:Element2>"; 192 193 } 194