Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copying Test Elements between test plans #2199

Closed
asfimport opened this issue Feb 9, 2009 · 7 comments
Closed

Copying Test Elements between test plans #2199

asfimport opened this issue Feb 9, 2009 · 7 comments

Comments

@asfimport
Copy link
Collaborator

Noel O'Brien (Bug 46677):
I suggest the following enhancements to JMeter to make test element copying more seamless and more straightforward:

  1. Enable test elements to be left in the Workspace between the loading of test plans, this will allow users to copy elements between test plans.

  2. Enable drag & drop and copy/paste between separate instances of JMeter.

Votes in Bugzilla: 1
OS: All

Duplicates:

@asfimport
Copy link
Collaborator Author

Roman Bargezi (migrated from Bugzilla):
For compatibility the attached patch does not remove or replace the currently
unused interfaces "getCopiedNode", "setCopiedNode" and some of the other
obsolete variables and methods in the class
"org.apache.jmeter.gui.action.Copy". The JMeter team may want to consider this
additional cleanup.

The patch does not address the DnD across instances.

Created attachment Enh46677_CopyPasteAccrossInstances.patch: Proposed enhancement as patch to build revision 1196526 of JMeter

Enh46677_CopyPasteAccrossInstances.patch
Index: src/core/org/apache/jmeter/gui/action/Copy.java
===================================================================
--- src/core/org/apache/jmeter/gui/action/Copy.java	(revision 1197485)
+++ src/core/org/apache/jmeter/gui/action/Copy.java	(working copy)
@@ -23,24 +23,29 @@
  */
 package org.apache.jmeter.gui.action;
 
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
 import java.awt.event.ActionEvent;
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Set;
 
+import javax.swing.JOptionPane;
+
 import org.apache.jmeter.gui.GuiPackage;
 import org.apache.jmeter.gui.tree.JMeterTreeListener;
 import org.apache.jmeter.gui.tree.JMeterTreeNode;
 import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.util.JMeterTreeNodeTransferable;
+import org.apache.jmeter.util.JMeterUtils;
 
 /**
  * Implements the Copy menu command
  */
 public class Copy extends AbstractAction {
+    
     private static JMeterTreeNode copiedNode = null;
 
-    private static JMeterTreeNode copiedNodes[] = null;
-
     private static final HashSet<String> commands = new HashSet<String>();
 
     static {
@@ -63,15 +68,15 @@
     }
 
     public static JMeterTreeNode[] getCopiedNodes() {
-        if (copiedNodes == null) { // can be null if Copy has yet to be used
-            return null;
-        }
-        for (int i = 0; i < copiedNodes.length; i++) {
-            if (copiedNodes[i] == null) {
-                return null;
+        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+        if(clipboard.isDataFlavorAvailable(JMeterTreeNodeTransferable.JMETER_TREE_NODE_ARRAY_DATA_FLAVOR)) {
+            try {
+                return (JMeterTreeNode[]) clipboard.getData(JMeterTreeNodeTransferable.JMETER_TREE_NODE_ARRAY_DATA_FLAVOR);
+            } catch (Exception ex) {
+                JOptionPane.showMessageDialog(GuiPackage.getInstance().getMainFrame(), JMeterUtils.getResString("clipboard_node_read_error")+":\n" + ex.getLocalizedMessage(), JMeterUtils.getResString("error_title"), JOptionPane.ERROR_MESSAGE);
             }
         }
-        return cloneTreeNodes(copiedNodes);
+        return null;
     }
 
     public static JMeterTreeNode getCopiedNode() {
@@ -93,9 +98,13 @@
     }
 
     public static void setCopiedNodes(JMeterTreeNode nodes[]) {
-        copiedNodes = new JMeterTreeNode[nodes.length];
-        for (int i = 0; i < nodes.length; i++) {
-            copiedNodes[i] = cloneTreeNode(nodes[i]);
+        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+        try {
+            JMeterTreeNodeTransferable transferable = new JMeterTreeNodeTransferable();
+            transferable.setTransferData(nodes);
+            clipboard.setContents(transferable, null);
+        } catch (Exception ex) {
+            JOptionPane.showMessageDialog(GuiPackage.getInstance().getMainFrame(), JMeterUtils.getResString("clipboard_node_read_error")+":\n" + ex.getLocalizedMessage(), JMeterUtils.getResString("error_title"), JOptionPane.ERROR_MESSAGE);
         }
     }
 
Index: src/core/org/apache/jmeter/resources/messages.properties
===================================================================
--- src/core/org/apache/jmeter/resources/messages.properties	(revision 1197485)
+++ src/core/org/apache/jmeter/resources/messages.properties	(working copy)
@@ -125,6 +125,8 @@
 clear_all=Clear All
 clear_cache_per_iter=Clear cache each iteration?
 clear_cookies_per_iter=Clear cookies each iteration?
+clipboard_node_read_error=Error retrieving nodes from clipboard
+clipboard_node_write_error=Error coping nodes to clipboard
 column_delete_disallowed=Deleting this column is not permitted
 column_number=Column number of CSV file | next | *alias
 compare=Compare
Index: src/core/org/apache/jmeter/util/JMeterTreeNodeTransferable.java
===================================================================
--- src/core/org/apache/jmeter/util/JMeterTreeNodeTransferable.java	(revision 0)
+++ src/core/org/apache/jmeter/util/JMeterTreeNodeTransferable.java	(revision 0)
@@ -0,0 +1,68 @@
+package org.apache.jmeter.util;
+
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.jmeter.gui.tree.JMeterTreeNode;
+
+/**
+ * Simple implementation of a transferable for {@link JMeterTreeNode} arrays based on serialization.
+ */
+public class JMeterTreeNodeTransferable implements Transferable {
+    
+    private static final long serialVersionUID = 192L;
+    
+    public final static DataFlavor JMETER_TREE_NODE_ARRAY_DATA_FLAVOR = new DataFlavor(JMeterTreeNode[].class, JMeterTreeNode[].class.getName());
+    
+    private final static DataFlavor[] DATA_FLAVORS = new DataFlavor[]{JMETER_TREE_NODE_ARRAY_DATA_FLAVOR};
+    
+    private byte[] data = null;
+
+    @Override
+    public DataFlavor[] getTransferDataFlavors() {
+        return DATA_FLAVORS;
+    }
+
+    @Override
+    public boolean isDataFlavorSupported(DataFlavor flavor) {
+        return flavor.match(JMETER_TREE_NODE_ARRAY_DATA_FLAVOR);
+    }
+
+    @Override
+    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
+        if(!isDataFlavorSupported(flavor)) {
+            throw new UnsupportedFlavorException(flavor);
+        }
+        if(data != null) {
+            ByteArrayInputStream bis = new ByteArrayInputStream(data);
+            ObjectInput ois = new ObjectInputStream(bis);
+            try {
+                JMeterTreeNode[] nodes = (JMeterTreeNode[]) ois.readObject();
+                return nodes;
+            } catch (ClassNotFoundException cnfe) {
+                throw new IOException("Failed to read object stream.", cnfe);
+            } finally {
+                ois.close();
+                bis.close();
+            }
+        }
+        return null;
+    }
+    
+    public void setTransferData(JMeterTreeNode[] nodes) throws IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(bos);
+        oos.writeObject(nodes);
+        oos.close();
+        bos.close();
+        data = bos.toByteArray();
+    }
+
+}

@asfimport
Copy link
Collaborator Author

@pmouawad (migrated from Bugzilla):
Thanks for patch but:

  • It is not working under Mac OSX when using CMD+C/CMD+V (or apple C / apple V)

while it is working OK with Menu Copy/paste.
In the first case custom DataFlavor is not supported.

Can you check if you have the same behaviour under Windows ?

Another point, it makes hypothesis all JMeterTreeNode userdata are Serializable, not sure it is always the case.

@asfimport
Copy link
Collaborator Author

Roman Bargezi (migrated from Bugzilla):
True, this also fails for Windows. The reason is that the default transfer handler registered for the Tree component gets called after the Copy action and places its own stuff in the clipboard. I will have to give this implementation some rework. Stay tuned for an update.

@asfimport
Copy link
Collaborator Author

@pmouawad (migrated from Bugzilla):
Here is the updated patch.
After fix to 54172 the copy/paste now works OK.

There remains an issue on ModuleController where reference is not pasted correctly.

Patch needs upgrade to JDK6.

Created attachment BUG_46677.patch: Updated patch

BUG_46677.patch
Index: src/core/org/apache/jmeter/util/JMeterTreeNodeTransferable.java
===================================================================
--- src/core/org/apache/jmeter/util/JMeterTreeNodeTransferable.java	(revision 0)
+++ src/core/org/apache/jmeter/util/JMeterTreeNodeTransferable.java	(revision 0)
@@ -0,0 +1,96 @@
+/*
+ *  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.jmeter.util;
+
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.jmeter.gui.tree.JMeterTreeNode;
+
+/**
+ * Simple implementation of a transferable for {@link JMeterTreeNode} arrays based on serialization.
+ */
+public class JMeterTreeNodeTransferable implements Transferable {
+    
+    public final static DataFlavor JMETER_TREE_NODE_ARRAY_DATA_FLAVOR = new DataFlavor(JMeterTreeNode[].class, JMeterTreeNode[].class.getName());
+    
+    private final static DataFlavor[] DATA_FLAVORS = new DataFlavor[]{JMETER_TREE_NODE_ARRAY_DATA_FLAVOR};
+    
+    private byte[] data = null;
+
+    @Override
+    public DataFlavor[] getTransferDataFlavors() {
+        return DATA_FLAVORS;
+    }
+
+    @Override
+    public boolean isDataFlavorSupported(DataFlavor flavor) {
+        return flavor.match(JMETER_TREE_NODE_ARRAY_DATA_FLAVOR);
+    }
+
+    @Override
+    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
+        if(!isDataFlavorSupported(flavor)) {
+            throw new UnsupportedFlavorException(flavor);
+        }
+        if(data != null) {
+            ObjectInput ois = null;
+            try {
+                ois = new ObjectInputStream(new ByteArrayInputStream(data));
+                JMeterTreeNode[] nodes = (JMeterTreeNode[]) ois.readObject();
+                return nodes;
+            } catch (ClassNotFoundException cnfe) {
+                throw new IOException("Failed to read object stream.", cnfe);
+            } finally {
+                if(ois != null) {
+                    try {
+                        ois.close();
+                    } catch (Exception e) {
+                        // NOOP
+                    }
+                }
+            }
+        }
+        return null;
+    }
+    
+    public void setTransferData(JMeterTreeNode[] nodes) throws IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = null;
+        try {
+            oos = new ObjectOutputStream(bos);
+            oos.writeObject(nodes);
+            data = bos.toByteArray();
+        } finally {
+            if(oos != null) {
+                try {
+                    oos.close();
+                } catch (Exception e) {
+                    // NOOP
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
Index: src/core/org/apache/jmeter/gui/action/Copy.java
===================================================================
--- src/core/org/apache/jmeter/gui/action/Copy.java	(revision 1392846)
+++ src/core/org/apache/jmeter/gui/action/Copy.java	(working copy)
@@ -23,24 +23,27 @@
  */
 package org.apache.jmeter.gui.action;
 
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
 import java.awt.event.ActionEvent;
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Set;
 
+import javax.swing.JOptionPane;
+
 import org.apache.jmeter.gui.GuiPackage;
 import org.apache.jmeter.gui.tree.JMeterTreeListener;
 import org.apache.jmeter.gui.tree.JMeterTreeNode;
 import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.util.JMeterTreeNodeTransferable;
+import org.apache.jmeter.util.JMeterUtils;
 
 /**
  * Implements the Copy menu command
  */
 public class Copy extends AbstractAction {
-    private static JMeterTreeNode copiedNode = null;
-
-    private static JMeterTreeNode copiedNodes[] = null;
-
+    
     private static final HashSet<String> commands = new HashSet<String>();
 
     static {
@@ -63,26 +66,16 @@
     }
 
     public static JMeterTreeNode[] getCopiedNodes() {
-        if (copiedNodes == null) { // can be null if Copy has yet to be used
-            return null;
-        }
-        for (int i = 0; i < copiedNodes.length; i++) {
-            if (copiedNodes[i] == null) {
-                return null;
+        
+        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+        if(clipboard.isDataFlavorAvailable(JMeterTreeNodeTransferable.JMETER_TREE_NODE_ARRAY_DATA_FLAVOR)) {
+            try {
+                return (JMeterTreeNode[]) clipboard.getData(JMeterTreeNodeTransferable.JMETER_TREE_NODE_ARRAY_DATA_FLAVOR);
+            } catch (Exception ex) {
+                JOptionPane.showMessageDialog(GuiPackage.getInstance().getMainFrame(), JMeterUtils.getResString("clipboard_node_read_error")+":\n" + ex.getLocalizedMessage(), JMeterUtils.getResString("error_title"), JOptionPane.ERROR_MESSAGE);
             }
         }
-        return cloneTreeNodes(copiedNodes);
-    }
-
-    public static JMeterTreeNode getCopiedNode() {
-        if (copiedNode == null) {
-            return null;
-        }
-        return cloneTreeNode(copiedNode);
-    }
-
-    public static void setCopiedNode(JMeterTreeNode node) {
-        copiedNode = cloneTreeNode(node);
+        return null;
     }
 
     public static JMeterTreeNode cloneTreeNode(JMeterTreeNode node) {
@@ -93,9 +86,13 @@
     }
 
     public static void setCopiedNodes(JMeterTreeNode nodes[]) {
-        copiedNodes = new JMeterTreeNode[nodes.length];
-        for (int i = 0; i < nodes.length; i++) {
-            copiedNodes[i] = cloneTreeNode(nodes[i]);
+        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+        try {
+            JMeterTreeNodeTransferable transferable = new JMeterTreeNodeTransferable();
+            transferable.setTransferData(nodes);
+            clipboard.setContents(transferable, null);
+        } catch (Exception ex) {
+            JOptionPane.showMessageDialog(GuiPackage.getInstance().getMainFrame(), JMeterUtils.getResString("clipboard_node_read_error")+":\n" + ex.getLocalizedMessage(), JMeterUtils.getResString("error_title"), JOptionPane.ERROR_MESSAGE);
         }
     }
 

@asfimport
Copy link
Collaborator Author

@pmouawad (migrated from Bugzilla):
I found issue, so now I can commit it, but it requires upgrade to JDK 6.

Are you OK with this ?
What must we do to upgrade ?

Thanks

@asfimport
Copy link
Collaborator Author

Sebb (migrated from Bugzilla):
(In reply to comment 6)

I found issue, so now I can commit it, but it requires upgrade to JDK 6.

Are you OK with this ?
What must we do to upgrade ?

Those are questions for the dev list, rather than here.

Thanks

@asfimport
Copy link
Collaborator Author

@pmouawad (migrated from Bugzilla):
Date: Sat Nov 24 20:34:40 2012
New Revision: 1413259

URL: http://svn.apache.org/viewvc?rev=1413259&view=rev
Log:
#2199 - Copying Test Elements between test plans
#2199

Added:
jmeter/trunk/src/core/org/apache/jmeter/util/JMeterTreeNodeTransferable.java (with props)
Modified:
jmeter/trunk/src/components/org/apache/jmeter/control/ModuleController.java
jmeter/trunk/src/core/org/apache/jmeter/gui/action/Copy.java
jmeter/trunk/xdocs/changes.xml

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant