blob: 6daeab953a29dcf8188308ea199839e698fcfec2 [file] [log] [blame]
/*
* Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.beans;
import com.sun.beans.finder.ClassFinder;
import java.beans.*;
import java.util.*;
import org.xml.sax.*;
import static java.util.Locale.ENGLISH;
/**
* <b>WARNING</b>: This class is an implementation detail and only meant
* for use within the core platform. You should NOT depend upon it! This
* API may change drastically between dot dot release, and it may even be
* removed.
*
* @see java.beans.XMLEncoder
* @see java.io.ObjectInputStream
*
* @since 1.4
*
* @author Philip Milne
*/
public class ObjectHandler extends HandlerBase {
public static Class typeNameToClass(String typeName) {
typeName = typeName.intern();
if (typeName == "boolean") return Boolean.class;
if (typeName == "byte") return Byte.class;
if (typeName == "char") return Character.class;
if (typeName == "short") return Short.class;
if (typeName == "int") return Integer.class;
if (typeName == "long") return Long.class;
if (typeName == "float") return Float.class;
if (typeName == "double") return Double.class;
if (typeName == "void") return Void.class;
return null;
}
public static Class typeNameToPrimitiveClass(String typeName) {
typeName = typeName.intern();
if (typeName == "boolean") return boolean.class;
if (typeName == "byte") return byte.class;
if (typeName == "char") return char.class;
if (typeName == "short") return short.class;
if (typeName == "int") return int.class;
if (typeName == "long") return long.class;
if (typeName == "float") return float.class;
if (typeName == "double") return double.class;
if (typeName == "void") return void.class;
return null;
}
/**
* Returns the <code>Class</code> object associated with
* the class or interface with the given string name,
* using the default class loader.
*
* @param name fully qualified name of the desired class
* @param cl class loader from which the class must be loaded
* @return class object representing the desired class
*
* @exception ClassNotFoundException if the class cannot be located
* by the specified class loader
*
* @deprecated As of JDK version 7, replaced by
* {@link ClassFinder#resolveClass(String)}.
*/
@Deprecated
public static Class classForName(String name) throws ClassNotFoundException {
return ClassFinder.resolveClass(name);
}
/**
* Returns the <code>Class</code> object associated with
* the class or interface with the given string name,
* using the given class loader.
*
* @param name fully qualified name of the desired class
* @param cl class loader from which the class must be loaded
* @return class object representing the desired class
*
* @exception ClassNotFoundException if the class cannot be located
* by the specified class loader
*
* @deprecated As of JDK version 7, replaced by
* {@link ClassFinder#resolveClass(String,ClassLoader)}.
*/
@Deprecated
public static Class classForName(String name, ClassLoader cl)
throws ClassNotFoundException {
return ClassFinder.resolveClass(name, cl);
}
private Hashtable environment;
private Vector expStack;
private StringBuffer chars;
private XMLDecoder is;
private ClassLoader ldr;
private int itemsRead = 0;
private boolean isString;
public ObjectHandler() {
environment = new Hashtable();
expStack = new Vector();
chars = new StringBuffer();
}
public ObjectHandler(XMLDecoder is) {
this();
this.is = is;
}
/* loader can be null */
public ObjectHandler(XMLDecoder is, ClassLoader loader) {
this(is);
this.ldr = loader;
}
public void reset() {
expStack.clear();
chars.setLength(0);
MutableExpression e = new MutableExpression();
e.setTarget(classForName2("java.lang.Object"));
e.setMethodName("null");
expStack.add(e);
}
private Object getValue(Expression exp) {
try {
return exp.getValue();
}
catch (Exception e) {
if (is != null) {
is.getExceptionListener().exceptionThrown(e);
}
return null;
}
}
private void addArg(Object arg) {
lastExp().addArg(arg);
}
private Object pop(Vector v) {
int last = v.size()-1;
Object result = v.get(last);
v.remove(last);
return result;
}
private Object eval() {
return getValue(lastExp());
}
private MutableExpression lastExp() {
return (MutableExpression)expStack.lastElement();
}
public Object dequeueResult() {
Object[] results = lastExp().getArguments();
return results[itemsRead++];
}
private boolean isPrimitive(String name) {
return name != "void" && typeNameToClass(name) != null;
}
private void simulateException(String message) {
Exception e = new Exception(message);
e.fillInStackTrace();
if (is != null) {
is.getExceptionListener().exceptionThrown(e);
}
}
private Class classForName2(String name) {
try {
return ClassFinder.resolveClass(name, this.ldr);
}
catch (ClassNotFoundException e) {
if (is != null) {
is.getExceptionListener().exceptionThrown(e);
}
}
return null;
}
private HashMap getAttributes(AttributeList attrs) {
HashMap attributes = new HashMap();
if (attrs != null && attrs.getLength() > 0) {
for(int i = 0; i < attrs.getLength(); i++) {
attributes.put(attrs.getName(i), attrs.getValue(i));
}
}
return attributes;
}
public void startElement(String name, AttributeList attrs) throws SAXException {
name = name.intern(); // Xerces parser does not supply unique tag names.
if (this.isString) {
parseCharCode(name, getAttributes(attrs));
return;
}
chars.setLength(0);
HashMap attributes = getAttributes(attrs);
MutableExpression e = new MutableExpression();
// Target
String className = (String)attributes.get("class");
if (className != null) {
e.setTarget(classForName2(className));
}
// Property
Object property = attributes.get("property");
String index = (String)attributes.get("index");
if (index != null) {
property = new Integer(index);
e.addArg(property);
}
e.setProperty(property);
// Method
String methodName = (String)attributes.get("method");
if (methodName == null && property == null) {
methodName = "new";
}
e.setMethodName(methodName);
// Tags
if (name == "string") {
e.setTarget(String.class);
e.setMethodName("new");
this.isString = true;
}
else if (isPrimitive(name)){
Class wrapper = typeNameToClass(name);
e.setTarget(wrapper);
e.setMethodName("new");
parseCharCode(name, attributes);
}
else if (name == "class") {
e.setTarget(Class.class);
e.setMethodName("forName");
}
else if (name == "null") {
// Create an arbitrary expression that has a value of null - for
// consistency.
e.setTarget(Object.class);
e.setMethodName("getSuperclass");
e.setValue(null);
}
else if (name == "void") {
if (e.getTarget() == null) { // this check is for "void class="foo" method= ..."
e.setTarget(eval());
}
}
else if (name == "array") {
// The class attribute means sub-type for arrays.
String subtypeName = (String)attributes.get("class");
Class subtype = (subtypeName == null) ? Object.class : classForName2(subtypeName);
String length = (String)attributes.get("length");
if (length != null) {
e.setTarget(java.lang.reflect.Array.class);
e.addArg(subtype);
e.addArg(new Integer(length));
}
else {
Class arrayClass = java.lang.reflect.Array.newInstance(subtype, 0).getClass();
e.setTarget(arrayClass);
}
}
else if (name == "java") {
e.setValue(is); // The outermost scope is the stream itself.
}
else if (name == "object") {
}
else {
simulateException("Unrecognized opening tag: " + name + " " + attrsToString(attrs));
return;
}
// ids
String idName = (String)attributes.get("id");
if (idName != null) {
environment.put(idName, e);
}
// idrefs
String idrefName = (String)attributes.get("idref");
if (idrefName != null) {
e.setValue(lookup(idrefName));
}
// fields
String fieldName = (String)attributes.get("field");
if (fieldName != null) {
e.setValue(getFieldValue(e.getTarget(), fieldName));
}
expStack.add(e);
}
private Object getFieldValue(Object target, String fieldName) {
try {
Class type = target.getClass();
if (type == Class.class) {
type = (Class)target;
}
java.lang.reflect.Field f = sun.reflect.misc.FieldUtil.getField(type, fieldName);
return f.get(target);
}
catch (Exception e) {
if (is != null) {
is.getExceptionListener().exceptionThrown(e);
}
return null;
}
}
private String attrsToString(AttributeList attrs) {
StringBuffer b = new StringBuffer();
for (int i = 0; i < attrs.getLength (); i++) {
b.append(attrs.getName(i)+"=\""+attrs.getValue(i)+"\" ");
}
return b.toString();
}
public void characters(char buf [], int offset, int len) throws SAXException {
chars.append(new String(buf, offset, len));
}
private void parseCharCode(String name, Map map) {
if (name == "char") {
String value = (String) map.get("code");
if (value != null) {
int code = Integer.decode(value);
for (char ch : Character.toChars(code)) {
this.chars.append(ch);
}
}
}
}
public Object lookup(String s) {
Expression e = (Expression)environment.get(s);
if (e == null) {
simulateException("Unbound variable: " + s);
}
return getValue(e);
}
public void register(String id, Object value) {
Expression e = new MutableExpression();
e.setValue(value);
environment.put(id, e);
}
public void endElement(String name) throws SAXException {
name = name.intern(); // Xerces parser does not supply unique tag names.
if (name == "string") {
this.isString = false;
} else if (this.isString) {
return;
}
if (name == "java") {
return;
}
if (isPrimitive(name) || name == "string" || name == "class") {
addArg(chars.toString());
}
if (name == "object" || name == "array" || name == "void" ||
isPrimitive(name) || name == "string" || name == "class" ||
name == "null") {
Expression e = (Expression)pop(expStack);
Object value = getValue(e);
if (name != "void") {
addArg(value);
}
}
else {
simulateException("Unrecognized closing tag: " + name);
}
}
}
class MutableExpression extends Expression {
private Object target;
private String methodName;
private Object property;
private Vector argV = new Vector();
private String capitalize(String propertyName) {
if (propertyName.length() == 0) {
return propertyName;
}
return propertyName.substring(0, 1).toUpperCase(ENGLISH) + propertyName.substring(1);
}
public MutableExpression() {
super(null, null, null);
}
public Object[] getArguments() {
return argV.toArray();
}
public String getMethodName() {
if (property == null) {
return methodName;
}
int setterArgs = (property instanceof String) ? 1 : 2;
String methodName = (argV.size() == setterArgs) ? "set" : "get";
if (property instanceof String) {
return methodName + capitalize((String)property);
}
else {
return methodName;
}
}
public void addArg(Object arg) {
argV.add(arg);
}
public void setTarget(Object target) {
this.target = target;
}
public Object getTarget() {
return target;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public void setProperty(Object property) {
this.property = property;
}
public void setValue(Object value) {
super.setValue(value);
}
public Object getValue() throws Exception {
return super.getValue();
}
}