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 {@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 * @see java.beans.Beans#instantiate 122 * @see javax.activation.CommandObject 123 */ 124 public Object getCommandObject(DataHandler dh, ClassLoader loader) 125 throws IOException, ClassNotFoundException { 126 Object new_bean = null; 127 128 // try to instantiate the bean 129 new_bean = Beans.instantiate(loader, className); 130 131 // if we got one and it is a CommandObject 132 if (new_bean != null) { 133 if (new_bean instanceof CommandObject) { 134 ((CommandObject)new_bean).setCommandContext(verb, dh); 135 } else if (new_bean instanceof Externalizable) { 136 if (dh != null) { 137 InputStream is = dh.getInputStream(); 138 if (is != null) { 139 ((Externalizable)new_bean).readExternal( 140 new ObjectInputStream(is)); 141 } 142 } 143 } 144 } 145 146 return new_bean; 147 } 148 149 /** 150 * Helper class to invoke Beans.instantiate reflectively or the equivalent 151 * with core reflection when module java.desktop is not readable. 152 */ 153 private static final class Beans { 154 static final Method instantiateMethod; 155 156 static { 157 Method m; 158 try { 159 Class<?> c = Class.forName("java.beans.Beans"); 160 m = c.getDeclaredMethod("instantiate", ClassLoader.class, String.class); 161 } catch (ClassNotFoundException e) { 162 m = null; 163 } catch (NoSuchMethodException e) { 164 m = null; 165 } 166 instantiateMethod = m; 167 } 168 169 /** 170 * Equivalent to invoking java.beans.Beans.instantiate(loader, cn) 171 */ 172 static Object instantiate(ClassLoader loader, String cn) 173 throws IOException, ClassNotFoundException { 174 175 Exception exception; 176 177 if (instantiateMethod != null) { 178 179 // invoke Beans.instantiate 180 try { 181 return instantiateMethod.invoke(null, loader, cn); 182 } catch (InvocationTargetException e) { 183 exception = e; 184 } catch (IllegalAccessException e) { 185 exception = e; 186 } 187 188 } else { 189 190 SecurityManager security = System.getSecurityManager(); 191 if (security != null) { 192 // if it's ok with the SecurityManager, it's ok with me. 193 String cname = cn.replace('/', '.'); 194 if (cname.startsWith("[")) { 195 int b = cname.lastIndexOf('[') + 2; 196 if (b > 1 && b < cname.length()) { 197 cname = cname.substring(b); 198 } 199 } 200 int i = cname.lastIndexOf('.'); 201 if (i != -1) { 202 security.checkPackageAccess(cname.substring(0, i)); 203 } 204 } 205 206 // Beans.instantiate specified to use SCL when loader is null 207 if (loader == null) { 208 loader = (ClassLoader) 209 AccessController.doPrivileged(new PrivilegedAction() { 210 public Object run() { 211 ClassLoader cl = null; 212 try { 213 cl = ClassLoader.getSystemClassLoader(); 214 } catch (SecurityException ex) { } 215 return cl; 216 } 217 }); 218 } 219 Class<?> beanClass = Class.forName(cn, false, loader); 220 try { 221 return beanClass.getDeclaredConstructor().newInstance(); 222 } catch (Exception ex) { 223 throw new ClassNotFoundException(beanClass + ": " + ex, ex); 224 } 225 226 } 227 return null; 228 } 229 } 230 }