1 /* 2 * Copyright (c) 1997, 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. 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 javax.activation; 27 28 import java.io.*; 29 import java.lang.reflect.InvocationTargetException; 30 import java.lang.reflect.Method; 31 import java.security.AccessController; 32 import java.security.PrivilegedAction; 33 34 /** 35 * The CommandInfo class is used by CommandMap implementations to 36 * describe the results of command requests. It provides the requestor 37 * with both the verb requested, as well as an instance of the 38 * bean. There is also a method that will return the name of the 39 * class that implements the command but <i>it is not guaranteed to 40 * return a valid value</i>. The reason for this is to allow CommandMap 41 * implmentations that subclass CommandInfo to provide special 42 * behavior. For example a CommandMap could dynamically generate 43 * JavaBeans. In this case, it might not be possible to create an 44 * object with all the correct state information solely from the class 45 * name. 46 * 47 * @since 1.6 48 */ 49 50 public class CommandInfo { 51 private String verb; 52 private String className; 53 54 /** 55 * The Constructor for CommandInfo. 56 * @param verb The command verb this CommandInfo decribes. 57 * @param className The command's fully qualified class name. 58 */ 59 public CommandInfo(String verb, String className) { 60 this.verb = verb; 61 this.className = className; 62 } 63 64 /** 65 * Return the command verb. 66 * 67 * @return the command verb. 68 */ 69 public String getCommandName() { 70 return verb; 71 } 72 73 /** 74 * Return the command's class name. <i>This method MAY return null in 75 * cases where a CommandMap subclassed CommandInfo for its 76 * own purposes.</i> In other words, it might not be possible to 77 * create the correct state in the command by merely knowing 78 * its class name. <b>DO NOT DEPEND ON THIS METHOD RETURNING 79 * A VALID VALUE!</b> 80 * 81 * @return The class name of the command, or <i>null</i> 82 */ 83 public String getCommandClass() { 84 return className; 85 } 86 87 /** 88 * Return the instantiated JavaBean component. 89 * <p> 90 * If the current runtime environment supports 91 * {@link java.beans.Beans#instantiate Beans.instantiate}, 92 * use it to instantiate the JavaBeans component. Otherwise, use 93 * {@link java.lang.Class#forName Class.forName}. 94 * <p> 95 * The component class needs to be public. 96 * On Java SE 9 and newer, if the component class is in a named module, 97 * it needs to be in an exported package. 98 * <p> 99 * If the bean implements the <code>javax.activation.CommandObject</code> 100 * interface, call its <code>setCommandContext</code> method. 101 * <p> 102 * If the DataHandler parameter is null, then the bean is 103 * instantiated with no data. NOTE: this may be useful 104 * if for some reason the DataHandler that is passed in 105 * throws IOExceptions when this method attempts to 106 * access its InputStream. It will allow the caller to 107 * retrieve a reference to the bean if it can be 108 * instantiated. 109 * <p> 110 * If the bean does NOT implement the CommandObject interface, 111 * this method will check if it implements the 112 * java.io.Externalizable interface. If it does, the bean's 113 * readExternal method will be called if an InputStream 114 * can be acquired from the DataHandler.<p> 115 * 116 * @param dh The DataHandler that describes the data to be 117 * passed to the command. 118 * @param loader The ClassLoader to be used to instantiate the bean. 119 * @return The bean 120 * @see java.beans.Beans#instantiate 121 * @see javax.activation.CommandObject 122 */ 123 public Object getCommandObject(DataHandler dh, ClassLoader loader) 124 throws IOException, ClassNotFoundException { 125 Object new_bean = null; 126 127 // try to instantiate the bean 128 new_bean = Beans.instantiate(loader, className); 129 130 // if we got one and it is a CommandObject 131 if (new_bean != null) { 132 if (new_bean instanceof CommandObject) { 133 ((CommandObject)new_bean).setCommandContext(verb, dh); 134 } else if (new_bean instanceof Externalizable) { 135 if (dh != null) { 136 InputStream is = dh.getInputStream(); 137 if (is != null) { 138 ((Externalizable)new_bean).readExternal( 139 new ObjectInputStream(is)); 140 } 141 } 142 } 143 } 144 145 return new_bean; 146 } 147 148 /** 149 * Helper class to invoke Beans.instantiate reflectively or the equivalent 150 * with core reflection when module java.desktop is not readable. 151 */ 152 private static final class Beans { 153 static final Method instantiateMethod; 154 155 static { 156 Method m; 157 try { 158 Class<?> c = Class.forName("java.beans.Beans"); 159 m = c.getDeclaredMethod("instantiate", ClassLoader.class, String.class); 160 } catch (ClassNotFoundException e) { 161 m = null; 162 } catch (NoSuchMethodException e) { 163 m = null; 164 } 165 instantiateMethod = m; 166 } 167 168 /** 169 * Equivalent to invoking java.beans.Beans.instantiate(loader, cn) 170 */ 171 static Object instantiate(ClassLoader loader, String cn) 172 throws IOException, ClassNotFoundException { 173 174 Exception exception; 175 176 if (instantiateMethod != null) { 177 178 // invoke Beans.instantiate 179 try { 180 return instantiateMethod.invoke(null, loader, cn); 181 } catch (InvocationTargetException e) { 182 exception = e; 183 } catch (IllegalAccessException e) { 184 exception = e; 185 } 186 187 } else { 188 189 SecurityManager security = System.getSecurityManager(); 190 if (security != null) { 191 // if it's ok with the SecurityManager, it's ok with me. 192 String cname = cn.replace('/', '.'); 193 if (cname.startsWith("[")) { 194 int b = cname.lastIndexOf('[') + 2; 195 if (b > 1 && b < cname.length()) { 196 cname = cname.substring(b); 197 } 198 } 199 int i = cname.lastIndexOf('.'); 200 if (i != -1) { 201 security.checkPackageAccess(cname.substring(0, i)); 202 } 203 } 204 205 // Beans.instantiate specified to use SCL when loader is null 206 if (loader == null) { 207 loader = (ClassLoader) 208 AccessController.doPrivileged(new PrivilegedAction() { 209 public Object run() { 210 ClassLoader cl = null; 211 try { 212 cl = ClassLoader.getSystemClassLoader(); 213 } catch (SecurityException ex) { } 214 return cl; 215 } 216 }); 217 } 218 Class<?> beanClass = Class.forName(cn, true, loader); 219 try { 220 return beanClass.newInstance(); 221 } catch (Exception ex) { 222 throw new ClassNotFoundException(beanClass + ": " + ex, ex); 223 } 224 225 } 226 return null; 227 } 228 } 229 }