842d6329cf
Reviewed-by: alanb, cjplummer, dholmes
643 lines
22 KiB
Java
643 lines
22 KiB
Java
/*
|
|
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
/*
|
|
@test
|
|
@key headful
|
|
@bug 6392086 8014725
|
|
@summary tests that HTMLs of all supported native HTML formats are transfered
|
|
properly
|
|
@run main/othervm HTMLTransferTest
|
|
*/
|
|
|
|
import java.awt.*;
|
|
import java.awt.datatransfer.*;
|
|
import java.io.*;
|
|
|
|
public class HTMLTransferTest {
|
|
public static final int CODE_NOT_RETURNED = 100;
|
|
public static final int CODE_CONSUMER_TEST_FAILED = 101;
|
|
public static final int CODE_FAILURE = 102;
|
|
public static DataFlavor[] HTMLFlavors = null;
|
|
public static DataFlavor SyncFlavor = null;
|
|
static {
|
|
try{
|
|
HTMLFlavors = new DataFlavor[] {
|
|
new DataFlavor("text/html; document=selection; Class=" + InputStream.class.getName() + "; charset=UTF-8"),
|
|
new DataFlavor("text/html; document=selection; Class=" + String.class.getName() + "; charset=UTF-8")
|
|
};
|
|
SyncFlavor = new DataFlavor(
|
|
"application/x-java-serialized-object; class="
|
|
+ SyncMessage.class.getName()
|
|
+ "; charset=UTF-8"
|
|
);
|
|
}catch(Exception e){
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
private THTMLProducer imPr;
|
|
private int returnCode = CODE_NOT_RETURNED;
|
|
|
|
public static void main(final String[] args) {
|
|
HTMLTransferTest app = new HTMLTransferTest();
|
|
app.init();
|
|
app.start();
|
|
}
|
|
|
|
public void init() {
|
|
initImpl();
|
|
|
|
} // init()
|
|
|
|
private void initImpl() {
|
|
imPr = new THTMLProducer();
|
|
imPr.begin();
|
|
}
|
|
|
|
|
|
public void start() {
|
|
try {
|
|
String stFormats = "";
|
|
|
|
String iniMsg = "Testing formats from the list:\n";
|
|
for (int i = 0; i < HTMLTransferTest.HTMLFlavors.length; i++) {
|
|
stFormats += "\"" + HTMLTransferTest.HTMLFlavors[i].getMimeType() + "\"\n";
|
|
}
|
|
System.out.println(iniMsg + stFormats);
|
|
System.err.println("===>" + iniMsg + stFormats);
|
|
|
|
String javaPath = System.getProperty("java.home", "");
|
|
String cmd = javaPath + File.separator + "bin" + File.separator
|
|
+ "java -cp " + System.getProperty("test.classes", ".") +
|
|
//+ "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 "
|
|
" THTMLConsumer"
|
|
//+ stFormats
|
|
;
|
|
|
|
Process process = Runtime.getRuntime().exec(cmd);
|
|
ProcessResults pres = ProcessResults.doWaitFor(process);
|
|
returnCode = pres.exitValue;
|
|
|
|
if (pres.stderr != null && pres.stderr.length() > 0) {
|
|
System.err.println("========= Child VM System.err ========");
|
|
System.err.print(pres.stderr);
|
|
System.err.println("======================================");
|
|
}
|
|
|
|
if (pres.stdout != null && pres.stdout.length() > 0) {
|
|
System.err.println("========= Child VM System.out ========");
|
|
System.err.print(pres.stdout);
|
|
System.err.println("======================================");
|
|
}
|
|
} catch (Throwable e) {
|
|
e.printStackTrace();
|
|
//returnCode equals CODE_NOT_RETURNED
|
|
}
|
|
|
|
switch (returnCode) {
|
|
case CODE_NOT_RETURNED:
|
|
System.err.println("Child VM: failed to start");
|
|
break;
|
|
case CODE_FAILURE:
|
|
System.err.println("Child VM: abnormal termination");
|
|
break;
|
|
case CODE_CONSUMER_TEST_FAILED:
|
|
throw new RuntimeException("test failed: HTMLs in some " +
|
|
"native formats are not transferred properly: " +
|
|
"see output of child VM");
|
|
default:
|
|
boolean failed = false;
|
|
String passedFormats = "";
|
|
String failedFormats = "";
|
|
|
|
for (int i = 0; i < imPr.passedArray.length; i++) {
|
|
if (imPr.passedArray[i]) {
|
|
passedFormats += HTMLTransferTest.HTMLFlavors[i].getMimeType() + " ";
|
|
} else {
|
|
failed = true;
|
|
failedFormats += HTMLTransferTest.HTMLFlavors[i].getMimeType() + " ";
|
|
}
|
|
}
|
|
if (failed) {
|
|
throw new RuntimeException(
|
|
"test failed: HTMLs in following "
|
|
+ "native formats are not transferred properly: "
|
|
+ failedFormats
|
|
);
|
|
} else {
|
|
System.err.println(
|
|
"HTMLs in following native formats are "
|
|
+ "transferred properly: "
|
|
+ passedFormats
|
|
);
|
|
}
|
|
}
|
|
|
|
} // start()
|
|
|
|
} // class HTMLTransferTest
|
|
|
|
class SyncMessage implements Serializable {
|
|
String msg;
|
|
|
|
public SyncMessage(String sync) {
|
|
this.msg = sync;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
return this.msg.equals(((SyncMessage)obj).msg);
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return msg;
|
|
}
|
|
}
|
|
|
|
class ProcessResults {
|
|
public int exitValue;
|
|
public String stdout;
|
|
public String stderr;
|
|
|
|
public ProcessResults() {
|
|
exitValue = -1;
|
|
stdout = "";
|
|
stderr = "";
|
|
}
|
|
|
|
/**
|
|
* Method to perform a "wait" for a process and return its exit value.
|
|
* This is a workaround for <code>Process.waitFor()</code> never returning.
|
|
*/
|
|
public static ProcessResults doWaitFor(Process p) {
|
|
ProcessResults pres = new ProcessResults();
|
|
|
|
InputStream in = null;
|
|
InputStream err = null;
|
|
|
|
try {
|
|
in = p.getInputStream();
|
|
err = p.getErrorStream();
|
|
|
|
boolean finished = false;
|
|
|
|
while (!finished) {
|
|
try {
|
|
while (in.available() > 0) {
|
|
pres.stdout += (char)in.read();
|
|
}
|
|
while (err.available() > 0) {
|
|
pres.stderr += (char)err.read();
|
|
}
|
|
// Ask the process for its exitValue. If the process
|
|
// is not finished, an IllegalThreadStateException
|
|
// is thrown. If it is finished, we fall through and
|
|
// the variable finished is set to true.
|
|
pres.exitValue = p.exitValue();
|
|
finished = true;
|
|
}
|
|
catch (IllegalThreadStateException e) {
|
|
// Process is not finished yet;
|
|
// Sleep a little to save on CPU cycles
|
|
Thread.currentThread().sleep(500);
|
|
}
|
|
}
|
|
if (in != null) in.close();
|
|
if (err != null) err.close();
|
|
}
|
|
catch (Throwable e) {
|
|
System.err.println("doWaitFor(): unexpected exception");
|
|
e.printStackTrace();
|
|
}
|
|
return pres;
|
|
}
|
|
}
|
|
|
|
|
|
abstract class HTMLTransferer implements ClipboardOwner {
|
|
|
|
static final SyncMessage S_PASSED = new SyncMessage("Y");
|
|
static final SyncMessage S_FAILED = new SyncMessage("N");
|
|
static final SyncMessage S_BEGIN = new SyncMessage("B");
|
|
static final SyncMessage S_BEGIN_ANSWER = new SyncMessage("BA");
|
|
static final SyncMessage S_END = new SyncMessage("E");
|
|
|
|
|
|
|
|
Clipboard m_clipboard;
|
|
|
|
HTMLTransferer() {
|
|
m_clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
|
|
}
|
|
|
|
|
|
abstract void notifyTransferSuccess(boolean status);
|
|
|
|
|
|
static Object createTRInstance(int i) {
|
|
try{
|
|
String _htmlText =
|
|
"The quick <font color='#78650d'>brown</font> <b>mouse</b> jumped over the lazy <b>cat</b>.";
|
|
switch(i){
|
|
case 0:
|
|
return new ByteArrayInputStream(_htmlText.getBytes("utf-8"));
|
|
case 1:
|
|
return _htmlText;
|
|
}
|
|
}catch(UnsupportedEncodingException e){ e.printStackTrace(); }
|
|
return null;
|
|
}
|
|
|
|
static byte[] getContent(InputStream is)
|
|
{
|
|
ByteArrayOutputStream tmp = new ByteArrayOutputStream();
|
|
try{
|
|
int read;
|
|
while( -1 != (read = is.read()) ){
|
|
tmp.write(read);
|
|
};
|
|
} catch( IOException e ) {
|
|
e.printStackTrace();
|
|
}
|
|
return tmp.toByteArray();
|
|
}
|
|
|
|
static void Dump(byte[] b){
|
|
System.err.println( new String(b) );
|
|
};
|
|
|
|
void setClipboardContents(
|
|
Transferable contents,
|
|
ClipboardOwner owner
|
|
) {
|
|
synchronized (m_clipboard) {
|
|
boolean set = false;
|
|
while (!set) {
|
|
try {
|
|
m_clipboard.setContents(contents, owner);
|
|
set = true;
|
|
} catch (IllegalStateException ise) {
|
|
try {
|
|
Thread.sleep(100);
|
|
} catch(InterruptedException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Transferable getClipboardContents(Object requestor)
|
|
{
|
|
synchronized (m_clipboard) {
|
|
while (true) {
|
|
try {
|
|
Transferable t = m_clipboard.getContents(requestor);
|
|
return t;
|
|
} catch (IllegalStateException ise) {
|
|
try {
|
|
Thread.sleep(100);
|
|
} catch (InterruptedException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
class THTMLProducer extends HTMLTransferer {
|
|
|
|
boolean[] passedArray;
|
|
int fi = 0; // next format index
|
|
private boolean isFirstCallOfLostOwnership = true;
|
|
|
|
THTMLProducer() {
|
|
passedArray = new boolean[HTMLTransferTest.HTMLFlavors.length];
|
|
}
|
|
|
|
void begin() {
|
|
setClipboardContents(
|
|
new HTMLSelection(
|
|
HTMLTransferTest.SyncFlavor,
|
|
S_BEGIN
|
|
),
|
|
this
|
|
);
|
|
}
|
|
|
|
public void lostOwnership(Clipboard cb, Transferable contents) {
|
|
System.err.println("{PRODUCER: lost clipboard ownership");
|
|
Transferable t = getClipboardContents(null);
|
|
if (t.isDataFlavorSupported(HTMLTransferTest.SyncFlavor)) {
|
|
SyncMessage msg = null;
|
|
// for test going on if t.getTransferData() will throw an exception
|
|
if (isFirstCallOfLostOwnership) {
|
|
isFirstCallOfLostOwnership = false;
|
|
msg = S_BEGIN_ANSWER;
|
|
} else {
|
|
msg = S_PASSED;
|
|
}
|
|
try {
|
|
msg = (SyncMessage)t.getTransferData(HTMLTransferTest.SyncFlavor);
|
|
System.err.println("++received message: " + msg);
|
|
} catch (Exception e) {
|
|
System.err.println("Can't getTransferData-message: " + e);
|
|
}
|
|
if( msg.equals(S_PASSED) ){
|
|
notifyTransferSuccess(true);
|
|
} else if( msg.equals(S_FAILED) ){
|
|
notifyTransferSuccess(false);
|
|
} else if (!msg.equals(S_BEGIN_ANSWER)) {
|
|
throw new RuntimeException("wrong message in " +
|
|
"THTMLProducer.lostOwnership(): " + msg +
|
|
" (possibly due to bug 4683804)");
|
|
}
|
|
} else {
|
|
throw new RuntimeException(
|
|
"DataFlavor.stringFlavor is not "
|
|
+ "suppurted by transferable in "
|
|
+ "THTMLProducer.lostOwnership()"
|
|
);
|
|
}
|
|
|
|
if (fi < HTMLTransferTest.HTMLFlavors.length) {
|
|
System.err.println(
|
|
"testing native HTML format \""
|
|
+ HTMLTransferTest.HTMLFlavors[fi].getMimeType()
|
|
+ "\"..."
|
|
);
|
|
//leaveFormat( HTMLTransferTest.HTMLFlavors[fi].getMimeType() );
|
|
setClipboardContents(
|
|
new HTMLSelection(
|
|
HTMLTransferTest.HTMLFlavors[fi],
|
|
HTMLTransferer.createTRInstance(fi)
|
|
),
|
|
this
|
|
);
|
|
} else {
|
|
setClipboardContents(
|
|
new HTMLSelection(
|
|
HTMLTransferTest.SyncFlavor,
|
|
S_END
|
|
),
|
|
null
|
|
);
|
|
}
|
|
System.err.println("}PRODUCER: lost clipboard ownership");
|
|
}
|
|
|
|
|
|
void notifyTransferSuccess(boolean status) {
|
|
passedArray[fi] = status;
|
|
fi++;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
class THTMLConsumer extends HTMLTransferer
|
|
{
|
|
private static final Object LOCK = new Object();
|
|
private static boolean failed;
|
|
int fi = 0; // next format index
|
|
|
|
public void lostOwnership(Clipboard cb, Transferable contents) {
|
|
System.err.println("{CONSUMER: lost clipboard ownership");
|
|
Transferable t = getClipboardContents(null);
|
|
boolean bContinue = true;
|
|
if(t.isDataFlavorSupported(HTMLTransferTest.SyncFlavor)) {
|
|
try {
|
|
SyncMessage msg = (SyncMessage)t.getTransferData(HTMLTransferTest.SyncFlavor);
|
|
System.err.println("received message: " + msg);
|
|
if(msg.equals(S_END)){
|
|
synchronized (LOCK) {
|
|
LOCK.notifyAll();
|
|
}
|
|
bContinue = false;
|
|
}
|
|
} catch (Exception e) {
|
|
System.err.println("Can't getTransferData-message: " + e);
|
|
}
|
|
}
|
|
if(bContinue){
|
|
// all HTML formats have been processed
|
|
System.err.println( "============================================================");
|
|
System.err.println( "Put as " + HTMLTransferTest.HTMLFlavors[fi].getMimeType() );
|
|
boolean bSuccess = false;
|
|
for(int i = 0; i < HTMLTransferTest.HTMLFlavors.length; ++i) {
|
|
System.err.println( "----------------------------------------------------------");
|
|
if( t.isDataFlavorSupported(HTMLTransferTest.HTMLFlavors[i]) ){
|
|
Object im = null; //? HTML;
|
|
try {
|
|
im = t.getTransferData(HTMLTransferTest.HTMLFlavors[i]);
|
|
if (im == null) {
|
|
System.err.println("getTransferData returned null");
|
|
} else {
|
|
System.err.println( "Extract as " + HTMLTransferTest.HTMLFlavors[i].getMimeType() );
|
|
String stIn = "(unknown)", stOut = "(unknown)";
|
|
switch( i ){
|
|
case 0:
|
|
stIn = new String( getContent( (InputStream)HTMLTransferer.createTRInstance(i) ) );
|
|
stOut = new String( getContent((InputStream)im) );
|
|
bSuccess = stIn.equals(stOut);
|
|
break;
|
|
case 1:
|
|
stIn = (String)HTMLTransferer.createTRInstance(i);
|
|
stOut = (String)im;
|
|
int head = stOut.indexOf("<HTML><BODY>");
|
|
if (head >= 0) {
|
|
stOut = stOut.substring(head + 12, stOut.length() - 14);
|
|
}
|
|
bSuccess = stIn.equals(stOut);
|
|
break;
|
|
default:
|
|
bSuccess = HTMLTransferer.createTRInstance(i).equals(im);
|
|
break;
|
|
};
|
|
System.err.println("in :" + stIn);
|
|
System.err.println("out:" + stOut);
|
|
};
|
|
} catch (Exception e) {
|
|
System.err.println("Can't getTransferData: " + e);
|
|
}
|
|
if(!bSuccess)
|
|
System.err.println("transferred DATA is different from initial DATA\n");
|
|
} else {
|
|
System.err.println("Flavor is not supported by transferable:\n");
|
|
DataFlavor[] dfs = t.getTransferDataFlavors();
|
|
int ii;
|
|
for(ii = 0; ii < dfs.length; ++ii)
|
|
System.err.println("Supported:" + dfs[ii] + "\n");
|
|
dfs = HTMLTransferTest.HTMLFlavors;
|
|
for(ii = 0; ii < dfs.length; ++ii)
|
|
System.err.println("Accepted:" + dfs[ii] + "\n" );
|
|
}
|
|
}
|
|
System.err.println( "----------------------------------------------------------");
|
|
notifyTransferSuccess(bSuccess);
|
|
System.err.println( "============================================================");
|
|
++fi;
|
|
}
|
|
System.err.println("}CONSUMER: lost clipboard ownership");
|
|
}
|
|
|
|
|
|
void notifyTransferSuccess(boolean status) {
|
|
System.err.println(
|
|
"format "
|
|
+ (status
|
|
? "passed"
|
|
: "failed"
|
|
)
|
|
+ "!!!"
|
|
);
|
|
setClipboardContents(
|
|
new HTMLSelection(
|
|
HTMLTransferTest.SyncFlavor,
|
|
status
|
|
? S_PASSED
|
|
: S_FAILED
|
|
),
|
|
this
|
|
);
|
|
}
|
|
|
|
|
|
public static void main(String[] args) {
|
|
try {
|
|
System.err.println("{CONSUMER: start");
|
|
THTMLConsumer ic = new THTMLConsumer();
|
|
ic.setClipboardContents(
|
|
new HTMLSelection(
|
|
HTMLTransferTest.SyncFlavor,
|
|
S_BEGIN_ANSWER
|
|
),
|
|
ic
|
|
);
|
|
synchronized (LOCK) {
|
|
LOCK.wait();
|
|
}
|
|
System.err.println("}CONSUMER: start");
|
|
} catch (Throwable e) {
|
|
e.printStackTrace();
|
|
System.exit(HTMLTransferTest.CODE_FAILURE);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* A <code>Transferable</code> which implements the capability required
|
|
* to transfer an <code>HTML</code>.
|
|
*
|
|
* This <code>Transferable</code> properly supports
|
|
* <code>HTMLTransferTest.HTMLFlavors</code>.
|
|
* and all equivalent flavors.
|
|
* No other <code>DataFlavor</code>s are supported.
|
|
*
|
|
* @see java.awt.datatransfer.HTMLTransferTest.HTMLFlavors
|
|
*/
|
|
class HTMLSelection implements Transferable {
|
|
private DataFlavor m_flavor;
|
|
private Object m_data;
|
|
|
|
/**
|
|
* Creates a <code>Transferable</code> capable of transferring
|
|
* the specified <code>String</code>.
|
|
*/
|
|
public HTMLSelection(
|
|
DataFlavor flavor,
|
|
Object data
|
|
){
|
|
m_flavor = flavor;
|
|
m_data = data;
|
|
}
|
|
|
|
/**
|
|
* Returns an array of flavors in which this <code>Transferable</code>
|
|
* can provide the data. <code>DataFlavor.stringFlavor</code>
|
|
* is properly supported.
|
|
* Support for <code>DataFlavor.plainTextFlavor</code> is
|
|
* <b>deprecated</b>.
|
|
*
|
|
* @return an array of length one, whose element is <code>DataFlavor.
|
|
* HTMLTransferTest.HTMLFlavors</code>
|
|
*/
|
|
public DataFlavor[] getTransferDataFlavors() {
|
|
// returning flavors itself would allow client code to modify
|
|
// our internal behavior
|
|
return new DataFlavor[]{ m_flavor } ;
|
|
}
|
|
|
|
/**
|
|
* Returns whether the requested flavor is supported by this
|
|
* <code>Transferable</code>.
|
|
*
|
|
* @param flavor the requested flavor for the data
|
|
* @return true if <code>flavor</code> is equal to
|
|
* <code>HTMLTransferTest.HTMLFlavors</code>;
|
|
* false if <code>flavor</code>
|
|
* is not one of the above flavors
|
|
* @throws NullPointerException if flavor is <code>null</code>
|
|
*/
|
|
public boolean isDataFlavorSupported(DataFlavor flavor) {
|
|
System.err.println("Have:" + flavor + " Can:" + m_flavor);
|
|
if(flavor.equals(m_flavor))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns the <code>Transferable</code>'s data in the requested
|
|
* <code>DataFlavor</code> if possible. If the desired flavor is
|
|
* <code>HTMLTransferTest.HTMLFlavors</code>, or an equivalent flavor,
|
|
* the <code>HTML</code> representing the selection is
|
|
* returned.
|
|
*
|
|
* @param flavor the requested flavor for the data
|
|
* @return the data in the requested flavor, as outlined above
|
|
* @throws UnsupportedFlavorException if the requested data flavor is
|
|
* not equivalent to <code>HTMLTransferTest.HTMLFlavors</code>
|
|
* @throws IOException if an IOException occurs while retrieving the data.
|
|
* By default, <code>HTMLSelection</code> never throws
|
|
* this exception, but a subclass may.
|
|
* @throws NullPointerException if flavor is <code>null</code>
|
|
*/
|
|
public Object getTransferData(DataFlavor flavor)
|
|
throws UnsupportedFlavorException, IOException
|
|
{
|
|
if (flavor.equals(m_flavor)) {
|
|
return (Object)m_data;
|
|
} else {
|
|
throw new UnsupportedFlavorException(flavor);
|
|
}
|
|
}
|
|
|
|
} // class HTMLSelection
|