1 /*
   2  * Copyright (c) 1998, 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 package javax.swing.text.html;
  26 
  27 import java.awt.*;
  28 import javax.swing.*;
  29 import javax.swing.text.*;
  30 import java.beans.*;
  31 import java.lang.reflect.*;
  32 
  33 import sun.reflect.misc.MethodUtil;
  34 import sun.reflect.misc.ReflectUtil;
  35 
  36 /**
  37  * Component decorator that implements the view interface
  38  * for <object> elements.
  39  * <p>
  40  * This view will try to load the class specified by the
  41  * <code>classid</code> attribute.  If possible, the Classloader
  42  * used to load the associated Document is used.
  43  * This would typically be the same as the ClassLoader
  44  * used to load the EditorKit.  If the document's
  45  * ClassLoader is null, <code>Class.forName</code> is used.
  46  * <p>
  47  * If the class can successfully be loaded, an attempt will
  48  * be made to create an instance of it by calling
  49  * <code>Class.newInstance</code>.  An attempt will be made
  50  * to narrow the instance to type <code>java.awt.Component</code>
  51  * to display the object.
  52  * <p>
  53  * This view can also manage a set of parameters with limitations.
  54  * The parameters to the &lt;object&gt; element are expected to
  55  * be present on the associated elements attribute set as simple
  56  * strings.  Each bean property will be queried as a key on
  57  * the AttributeSet, with the expectation that a non-null value
  58  * (of type String) will be present if there was a parameter
  59  * specification for the property.  Reflection is used to
  60  * set the parameter.  Currently, this is limited to a very
  61  * simple single parameter of type String.
  62  * <p>
  63  * A simple example HTML invocation is:
  64  * <pre>
  65  *      &lt;object classid="javax.swing.JLabel"&gt;
  66  *      &lt;param name="text" value="sample text"&gt;
  67  *      &lt;/object&gt;
  68  * </pre>
  69  *
  70  * @author Timothy Prinzing
  71  */
  72 public class ObjectView extends ComponentView  {
  73 
  74     /**
  75      * Creates a new ObjectView object.
  76      *
  77      * @param elem the element to decorate
  78      */
  79     public ObjectView(Element elem) {
  80         super(elem);
  81     }
  82 
  83     /**
  84      * Create the component.  The classid is used
  85      * as a specification of the classname, which
  86      * we try to load.
  87      */
  88     protected Component createComponent() {
  89         AttributeSet attr = getElement().getAttributes();
  90         String classname = (String) attr.getAttribute(HTML.Attribute.CLASSID);
  91         try {
  92             ReflectUtil.checkPackageAccess(classname);
  93             Class<?> c = Class.forName(classname, true,Thread.currentThread().
  94                                        getContextClassLoader());
  95             Object o = c.newInstance();
  96             if (o instanceof Component) {
  97                 Component comp = (Component) o;
  98                 setParameters(comp, attr);
  99                 return comp;
 100             }
 101         } catch (Throwable e) {
 102             // couldn't create a component... fall through to the
 103             // couldn't load representation.
 104         }
 105 
 106         return getUnloadableRepresentation();
 107     }
 108 
 109     /**
 110      * Fetch a component that can be used to represent the
 111      * object if it can't be created.
 112      */
 113     Component getUnloadableRepresentation() {
 114         // PENDING(prinz) get some artwork and return something
 115         // interesting here.
 116         Component comp = new JLabel("??");
 117         comp.setForeground(Color.red);
 118         return comp;
 119     }
 120 
 121     /**
 122      * Initialize this component according the KEY/VALUEs passed in
 123      * via the &lt;param&gt; elements in the corresponding
 124      * &lt;object&gt; element.
 125      */
 126     private void setParameters(Component comp, AttributeSet attr) {
 127         Class<?> k = comp.getClass();
 128         BeanInfo bi;
 129         try {
 130             bi = Introspector.getBeanInfo(k);
 131         } catch (IntrospectionException ex) {
 132             System.err.println("introspector failed, ex: "+ex);
 133             return;             // quit for now
 134         }
 135         PropertyDescriptor props[] = bi.getPropertyDescriptors();
 136         for (int i=0; i < props.length; i++) {
 137             //      System.err.println("checking on props[i]: "+props[i].getName());
 138             Object v = attr.getAttribute(props[i].getName());
 139             if (v instanceof String) {
 140                 // found a property parameter
 141                 String value = (String) v;
 142                 Method writer = props[i].getWriteMethod();
 143                 if (writer == null) {
 144                     // read-only property. ignore
 145                     return;     // for now
 146                 }
 147                 Class<?>[] params = writer.getParameterTypes();
 148                 if (params.length != 1) {
 149                     // zero or more than one argument, ignore
 150                     return;     // for now
 151                 }
 152                 Object [] args = { value };
 153                 try {
 154                     MethodUtil.invoke(writer, comp, args);
 155                 } catch (Exception ex) {
 156                     System.err.println("Invocation failed");
 157                     // invocation code
 158                 }
 159             }
 160         }
 161     }
 162 
 163 }