1 /* 2 * Copyright (c) 1997, 2017, 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 {@code java.beans.Beans} is visible then it's 91 * {@code java.beans.Beans#instantiate} method is invoked to instantiate 92 * the component as a JavaBeans component. 93 * When {@code java.beans.Beans} is not visible (when {@code java.desktop} 94 * module is not readable or when the runtime image does not contain the 95 * {@code java.desktop} module) then the command's class is loaded and 96 * instantiated with its public no-args constructor. 97 * <p> 98 * The component class needs to be public. 99 * <p> 100 * If the bean implements the {@code javax.activation.CommandObject} 101 * interface, call its {@code setCommandContext} method. 102 * <p> 103 * If the DataHandler parameter is null, then the bean is 104 * instantiated with no data. NOTE: this may be useful 105 * if for some reason the DataHandler that is passed in 106 * throws IOExceptions when this method attempts to 107 * access its InputStream. It will allow the caller to 108 * retrieve a reference to the bean if it can be 109 * instantiated. 110 * <p> 111 * If the bean does NOT implement the CommandObject interface, 112 * this method will check if it implements the 113 * java.io.Externalizable interface. If it does, the bean's 114 * readExternal method will be called if an InputStream 115 * can be acquired from the DataHandler.<p> 116 * 117 * @param dh The DataHandler that describes the data to be 118 * passed to the command. 119 * @param loader The ClassLoader to be used to instantiate the bean. 120 * @return The bean 121 * @exception IOException for failures reading data 122 * @exception ClassNotFoundException if command object class can't 123 * be found 124 * @see java.beans.Beans#instantiate 125 * @see javax.activation.CommandObject 126 */ 127 public Object getCommandObject(DataHandler dh, ClassLoader loader) 128 throws IOException, ClassNotFoundException { 129 Object new_bean = null; 130 131 // try to instantiate the bean 132 new_bean = Beans.instantiate(loader, className); 133 134 // if we got one and it is a CommandObject 135 if (new_bean != null) { 136 if (new_bean instanceof CommandObject) { 137 ((CommandObject)new_bean).setCommandContext(verb, dh); 138 } else if (new_bean instanceof Externalizable) { 139 if (dh != null) { 140 InputStream is = dh.getInputStream(); 141 if (is != null) { 142 ((Externalizable)new_bean).readExternal( 143 new ObjectInputStream(is)); 144 } 145 } 146 } 147 } 148 149 return new_bean; 150 } 151 152 /** 153 * Helper class to invoke Beans.instantiate reflectively or the equivalent 154 * with core reflection when module java.desktop is not readable. 155 */ 156 private static final class Beans { 157 static final Method instantiateMethod; 158 159 static { 160 Method m; 161 try { 162 Class<?> c = Class.forName("java.beans.Beans"); 163 m = c.getDeclaredMethod("instantiate", ClassLoader.class, String.class); 164 } catch (ClassNotFoundException e) { 165 m = null; 166 } catch (NoSuchMethodException e) { 167 m = null; 168 } 169 instantiateMethod = m; 170 } 171 172 /** 173 * Equivalent to invoking java.beans.Beans.instantiate(loader, cn) 174 */ 175 static Object instantiate(ClassLoader loader, String cn) 176 throws IOException, ClassNotFoundException { 177 178 Exception exception; 179 180 if (instantiateMethod != null) { 181 182 // invoke Beans.instantiate 183 try { 184 return instantiateMethod.invoke(null, loader, cn); 185 } catch (InvocationTargetException e) { 186 exception = e; 187 } catch (IllegalAccessException e) { 188 exception = e; 189 } 190 191 } else { 192 193 SecurityManager security = System.getSecurityManager(); 194 if (security != null) { 195 // if it's ok with the SecurityManager, it's ok with me. 196 String cname = cn.replace('/', '.'); 197 if (cname.startsWith("[")) { 198 int b = cname.lastIndexOf('[') + 2; 199 if (b > 1 && b < cname.length()) { 200 cname = cname.substring(b); 201 } 202 } 203 int i = cname.lastIndexOf('.'); 204 if (i != -1) { 205 security.checkPackageAccess(cname.substring(0, i)); 206 } 207 } 208 209 // Beans.instantiate specified to use SCL when loader is null 210 if (loader == null) { 211 loader = (ClassLoader) 212 AccessController.doPrivileged(new PrivilegedAction() { 213 public Object run() { 214 ClassLoader cl = null; 215 try { 216 cl = ClassLoader.getSystemClassLoader(); 217 } catch (SecurityException ex) { } 218 return cl; 219 } 220 }); 221 } 222 Class<?> beanClass = Class.forName(cn, false, loader); 223 try { 224 return beanClass.getDeclaredConstructor().newInstance(); 225 } catch (Exception ex) { 226 throw new ClassNotFoundException(beanClass + ": " + ex, ex); 227 } 228 229 } 230 return null; 231 } 232 } 233 }