1 /* 2 * Copyright (c) 2000, 2013, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.awt.datatransfer; 27 28 import java.awt.datatransfer.DataFlavor; 29 import java.awt.datatransfer.Transferable; 30 import java.awt.datatransfer.UnsupportedFlavorException; 31 import java.io.ByteArrayInputStream; 32 import java.io.ByteArrayOutputStream; 33 import java.io.InputStream; 34 import java.io.IOException; 35 import java.io.ObjectInputStream; 36 import java.io.ObjectOutputStream; 37 import java.io.ObjectStreamClass; 38 import java.io.OutputStream; 39 import java.lang.reflect.Modifier; 40 import java.lang.reflect.Proxy; 41 import java.security.AccessController; 42 import java.security.PrivilegedAction; 43 import java.util.HashMap; 44 import java.util.HashSet; 45 import java.util.Map; 46 import java.util.Set; 47 48 49 /** 50 * Proxies for another Transferable so that Serializable objects are never 51 * returned directly by DnD or the Clipboard. Instead, a new instance of the 52 * object is returned. 53 * 54 * @author Lawrence P.G. Cable 55 * @author David Mendenhall 56 * 57 * @since 1.4 58 */ 59 public class TransferableProxy implements Transferable { 60 public TransferableProxy(Transferable t, boolean local) { 61 transferable = t; 62 isLocal = local; 63 } 64 public DataFlavor[] getTransferDataFlavors() { 65 return transferable.getTransferDataFlavors(); 66 } 67 public boolean isDataFlavorSupported(DataFlavor flavor) { 68 return transferable.isDataFlavorSupported(flavor); 69 } 70 public Object getTransferData(DataFlavor df) 71 throws UnsupportedFlavorException, IOException 72 { 73 Object data = transferable.getTransferData(df); 74 75 // If the data is a Serializable object, then create a new instance 76 // before returning it. This insulates applications sharing DnD and 77 // Clipboard data from each other. 78 if (data != null && isLocal && df.isFlavorSerializedObjectType()) { 79 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 80 81 ClassLoaderObjectOutputStream oos = 82 new ClassLoaderObjectOutputStream(baos); 83 oos.writeObject(data); 84 85 ByteArrayInputStream bais = 86 new ByteArrayInputStream(baos.toByteArray()); 87 88 try { 89 ClassLoaderObjectInputStream ois = 90 new ClassLoaderObjectInputStream(bais, 91 oos.getClassLoaderMap()); 92 data = ois.readObject(); 93 } catch (ClassNotFoundException cnfe) { 94 throw (IOException)new IOException().initCause(cnfe); 95 } 96 } 97 98 return data; 99 } 100 101 protected final Transferable transferable; 102 protected final boolean isLocal; 103 } 104 105 final class ClassLoaderObjectOutputStream extends ObjectOutputStream { 106 private final Map<Set<String>, ClassLoader> map = 107 new HashMap<Set<String>, ClassLoader>(); 108 109 ClassLoaderObjectOutputStream(OutputStream os) throws IOException { 110 super(os); 111 } 112 113 protected void annotateClass(final Class<?> cl) throws IOException { 114 ClassLoader classLoader = AccessController.doPrivileged( 115 new PrivilegedAction<ClassLoader>() { 116 public ClassLoader run() { 117 return cl.getClassLoader(); 118 } 119 }); 120 121 Set<String> s = new HashSet<String>(1); 122 s.add(cl.getName()); 123 124 map.put(s, classLoader); 125 } 126 protected void annotateProxyClass(final Class<?> cl) throws IOException { 127 ClassLoader classLoader = AccessController.doPrivileged( 128 new PrivilegedAction<ClassLoader>() { 129 public ClassLoader run() { 130 return cl.getClassLoader(); 131 } 132 }); 133 134 Class<?>[] interfaces = cl.getInterfaces(); 135 Set<String> s = new HashSet<String>(interfaces.length); 136 for (int i = 0; i < interfaces.length; i++) { 137 s.add(interfaces[i].getName()); 138 } 139 140 map.put(s, classLoader); 141 } 142 143 Map<Set<String>, ClassLoader> getClassLoaderMap() { 144 return new HashMap<>(map); 145 } 146 } 147 148 final class ClassLoaderObjectInputStream extends ObjectInputStream { 149 private final Map<Set<String>, ClassLoader> map; 150 151 ClassLoaderObjectInputStream(InputStream is, 152 Map<Set<String>, ClassLoader> map) 153 throws IOException { 154 super(is); 155 if (map == null) { 156 throw new NullPointerException("Null map"); 157 } 158 this.map = map; 159 } 160 161 protected Class<?> resolveClass(ObjectStreamClass classDesc) 162 throws IOException, ClassNotFoundException { 163 String className = classDesc.getName(); 164 165 Set<String> s = new HashSet<String>(1); 166 s.add(className); 167 168 ClassLoader classLoader = map.get(s); 169 if (classLoader != null) { 170 return Class.forName(className, false, classLoader); 171 } else { 172 return super.resolveClass(classDesc); 173 } 174 } 175 176 protected Class<?> resolveProxyClass(String[] interfaces) 177 throws IOException, ClassNotFoundException { 178 179 Set<String> s = new HashSet<String>(interfaces.length); 180 for (int i = 0; i < interfaces.length; i++) { 181 s.add(interfaces[i]); 182 } 183 184 ClassLoader classLoader = map.get(s); 185 if (classLoader == null) { 186 return super.resolveProxyClass(interfaces); 187 } 188 189 // The code below is mostly copied from the superclass. 190 ClassLoader nonPublicLoader = null; 191 boolean hasNonPublicInterface = false; 192 193 // define proxy in class loader of non-public interface(s), if any 194 Class<?>[] classObjs = new Class<?>[interfaces.length]; 195 for (int i = 0; i < interfaces.length; i++) { 196 Class<?> cl = Class.forName(interfaces[i], false, classLoader); 197 if ((cl.getModifiers() & Modifier.PUBLIC) == 0) { 198 if (hasNonPublicInterface) { 199 if (nonPublicLoader != cl.getClassLoader()) { 200 throw new IllegalAccessError( 201 "conflicting non-public interface class loaders"); 202 } 203 } else { 204 nonPublicLoader = cl.getClassLoader(); 205 hasNonPublicInterface = true; 206 } 207 } 208 classObjs[i] = cl; 209 } 210 try { 211 return Proxy.getProxyClass(hasNonPublicInterface ? 212 nonPublicLoader : classLoader, 213 classObjs); 214 } catch (IllegalArgumentException e) { 215 throw new ClassNotFoundException(null, e); 216 } 217 } 218 }