blob: 9e16478ebad7a3d835c24885edc7a25d60bd6414 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jem.internal.proxy.ide;
/*
* $RCSfile: IDEStandardBeanTypeProxyFactory.java,v $
* $Revision: 1.8 $ $Date: 2005/02/15 22:57:26 $
*/
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.MessageFormat;
import java.util.*;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jem.internal.proxy.common.MapTypes;
import org.eclipse.jem.internal.proxy.core.*;
public class IDEStandardBeanTypeProxyFactory implements IStandardBeanTypeProxyFactory {
protected final IDEProxyFactoryRegistry fFactoryRegistry;
// Hashtable to cache proxies for classes so they are found on second and subsequent lookups
protected Map beanProxies;
public static Map MAP_SHORTSIG_TO_TYPE = new HashMap(8);
public static Map MAP_TYPENAME_TO_SHORTSIG = new HashMap(8);
static {
MAP_SHORTSIG_TO_TYPE.put("B", Byte.TYPE); //$NON-NLS-1$
MAP_SHORTSIG_TO_TYPE.put("C", Character.TYPE); //$NON-NLS-1$
MAP_SHORTSIG_TO_TYPE.put("D", Double.TYPE); //$NON-NLS-1$
MAP_SHORTSIG_TO_TYPE.put("F", Float.TYPE); //$NON-NLS-1$
MAP_SHORTSIG_TO_TYPE.put("I", Integer.TYPE); //$NON-NLS-1$
MAP_SHORTSIG_TO_TYPE.put("J", Long.TYPE); //$NON-NLS-1$
MAP_SHORTSIG_TO_TYPE.put("S", Short.TYPE); //$NON-NLS-1$
MAP_SHORTSIG_TO_TYPE.put("Z", Boolean.TYPE); //$NON-NLS-1$
MAP_TYPENAME_TO_SHORTSIG.put("byte","B"); //$NON-NLS-1$ //$NON-NLS-2$
MAP_TYPENAME_TO_SHORTSIG.put("char","C"); //$NON-NLS-1$ //$NON-NLS-2$
MAP_TYPENAME_TO_SHORTSIG.put("double","D"); //$NON-NLS-1$ //$NON-NLS-2$
MAP_TYPENAME_TO_SHORTSIG.put("float","F"); //$NON-NLS-1$ //$NON-NLS-2$
MAP_TYPENAME_TO_SHORTSIG.put("int","I"); //$NON-NLS-1$ //$NON-NLS-2$
MAP_TYPENAME_TO_SHORTSIG.put("long","J"); //$NON-NLS-1$ //$NON-NLS-2$
MAP_TYPENAME_TO_SHORTSIG.put("short","S"); //$NON-NLS-1$ //$NON-NLS-2$
MAP_TYPENAME_TO_SHORTSIG.put("boolean","Z"); //$NON-NLS-1$ //$NON-NLS-2$
}
// Cached copy of a few typical bean type proxies.
IDEBeanTypeProxy objectClass;
IDEBooleanTypeBeanTypeProxy booleanType;
IDEBooleanClassBeanTypeProxy booleanClass;
IDEIntegerTypeBeanTypeProxy intType;
IDEIntegerClassBeanTypeProxy integerClass;
IDEFloatTypeBeanTypeProxy floatType;
IDEFloatClassBeanTypeProxy floatClass;
IDELongTypeBeanTypeProxy longType;
IDELongClassBeanTypeProxy longClass;
IDEShortTypeBeanTypeProxy shortType;
IDEShortClassBeanTypeProxy shortClass;
IDEByteTypeBeanTypeProxy byteType;
IDEByteClassBeanTypeProxy byteClass;
IDECharTypeBeanTypeProxy charType;
IDECharacterClassBeanTypeProxy charClass;
IDEDoubleTypeBeanTypeProxy doubleType;
IDEDoubleClassBeanTypeProxy doubleClass;
IDEStringBeanTypeProxy stringClass;
IDEClassBeanTypeProxy classClass;
IDEBeanTypeProxy voidType;
public IDEStandardBeanTypeProxyFactory(IDEProxyFactoryRegistry aRegistry) {
fFactoryRegistry = aRegistry;
aRegistry.registerBeanTypeProxyFactory(this);
// Now initialize the cache.
objectClass = new IDEBeanTypeProxy(fFactoryRegistry,Object.class);
booleanType = new IDEBooleanTypeBeanTypeProxy(fFactoryRegistry, Boolean.TYPE);
booleanClass = new IDEBooleanClassBeanTypeProxy(fFactoryRegistry, Boolean.class);
intType = new IDEIntegerTypeBeanTypeProxy(fFactoryRegistry, Integer.TYPE);
integerClass = new IDEIntegerClassBeanTypeProxy(fFactoryRegistry, Integer.class);
floatType = new IDEFloatTypeBeanTypeProxy(fFactoryRegistry,Float.TYPE);
floatClass = new IDEFloatClassBeanTypeProxy(fFactoryRegistry,Float.class);
longType = new IDELongTypeBeanTypeProxy(fFactoryRegistry,Long.TYPE);
longClass = new IDELongClassBeanTypeProxy(fFactoryRegistry,Long.class);
shortType = new IDEShortTypeBeanTypeProxy(fFactoryRegistry,Short.TYPE);
shortClass = new IDEShortClassBeanTypeProxy(fFactoryRegistry,Short.class);
byteType = new IDEByteTypeBeanTypeProxy(fFactoryRegistry,Byte.TYPE);
byteClass = new IDEByteClassBeanTypeProxy(fFactoryRegistry,Byte.class);
charType = new IDECharTypeBeanTypeProxy(fFactoryRegistry,Character.TYPE);
charClass = new IDECharacterClassBeanTypeProxy(fFactoryRegistry,Character.class);
doubleType = new IDEDoubleTypeBeanTypeProxy(fFactoryRegistry,Double.TYPE);
doubleClass = new IDEDoubleClassBeanTypeProxy(fFactoryRegistry,Double.class);
stringClass = new IDEStringBeanTypeProxy(fFactoryRegistry, String.class);
classClass = new IDEClassBeanTypeProxy(fFactoryRegistry,java.lang.Class.class);
voidType = new IDEBeanTypeProxy(fFactoryRegistry, Void.TYPE);
// Initialize the hashtable with the primitives, their lang equivalents, and also common classes like String
beanProxies = new HashMap(20);
// Primitives
beanProxies.put(intType.getTypeName(), intType);
beanProxies.put(booleanType.getTypeName(), booleanType);
beanProxies.put(charType.getTypeName(), charType);
beanProxies.put(byteType.getTypeName(), byteType);
beanProxies.put(shortType.getTypeName(), shortType);
beanProxies.put(longType.getTypeName(), longType);
beanProxies.put(floatType.getTypeName(), floatType);
beanProxies.put(doubleType.getTypeName(), doubleType);
// java.lang primitive peers
// Note that special classes are used for some of these which allow the IDE to get the
// lang objects from the objects that are holding proxies
beanProxies.put(integerClass.getTypeName(), integerClass);
beanProxies.put(booleanClass.getTypeName(), booleanClass);
beanProxies.put(charClass.getTypeName(), charClass);
beanProxies.put(byteClass.getTypeName(), byteClass);
beanProxies.put(shortClass.getTypeName(), shortClass);
beanProxies.put(longClass.getTypeName(), longClass);
beanProxies.put(floatClass.getTypeName(), floatClass);
beanProxies.put(doubleClass.getTypeName(), doubleClass);
beanProxies.put(BigDecimal.class.getName(), new IDEBigDecimalBeanTypeProxy(fFactoryRegistry, BigDecimal.class));//$NON-NLS-1$
beanProxies.put(BigInteger.class.getName(), new IDEBigIntegerBeanTypeProxy(fFactoryRegistry, BigInteger.class));//$NON-NLS-1$
beanProxies.put(stringClass.getTypeName(), stringClass);
beanProxies.put(classClass.getTypeName(), classClass);
beanProxies.put(voidType.getTypeName(), voidType);
}
/**
* We are an IDE proxy and know that the type is in the same VM as the IDE.
* the IDEBeanTypeProxy object
* NOTE This is package protected because the only person who can call it are priveledged classes
* that are also creating things in an IDEProxy environment.
* If anyone needs to make this method public they are doing the wrong thing as they should use the
* public method getBeanTypeProxy(String) that is on the interface. The only other object that can
* guarantee that they have the class for the argument are those that are part of the idevm package
*/
IBeanTypeProxy getBeanTypeProxy(Class anIDEClass) {
return getBeanTypeProxy(anIDEClass.getName());
}
/**
* We are an IDE proxy and know that the type is in the same VM as the IDE.
* the IDEBeanTypeProxy object
*/
public synchronized IBeanTypeProxy getBeanTypeProxy(String typeName) {
typeName = MapTypes.getJNIFormatName(typeName);
// See whether we already have the proxy for the argument name
IBeanTypeProxy beanTypeProxy = (IBeanTypeProxy) beanProxies.get(typeName);
if (beanTypeProxy != null) {
return beanTypeProxy;
}
// If not an array, then see if the package extension mechanism can find it.
// Do this here so that if it is found in the package extension we won't necessarily create an
// extra connection when not needed.
if (typeName.charAt(0) != '[') {
// It is not an array
// First check with the factory for the package of the class.
// Inner classes have to use the dollar notation since if they didn't we couldn't tell where
// the package ended and the class started.
int packageIndex = typeName.lastIndexOf('.');
if (packageIndex != -1) {
String packageName = typeName.substring(0, packageIndex);
IDEExtensionBeanTypeProxyFactory packageFactory = (IDEExtensionBeanTypeProxyFactory)fFactoryRegistry.getBeanTypeProxyFactoryExtension(packageName);
if (packageFactory != null) {
beanTypeProxy = packageFactory.getExtensionBeanTypeProxy(typeName);
if (beanTypeProxy != null) {
registerBeanTypeProxy(beanTypeProxy, false);
return beanTypeProxy;
}
}
}
// There was not a registered factory that dealt with the class. Load it using the factory
// registry which has the plugin's class loader
try {
Class ideClass = fFactoryRegistry.loadClass(typeName);
IDEBeanTypeProxy superTypeProxy = null;
if (ideClass.getSuperclass() != null) {
// Get the beantype proxy of the superclass.
superTypeProxy = (IDEBeanTypeProxy) getBeanTypeProxy(ideClass.getSuperclass());
}
// Ask the supertype
// to create a beantype proxy of the same beantype proxy class.
// This is so that any subclasses will get the same beantype proxy class
// for it if it is special.
if (superTypeProxy != null)
beanTypeProxy = superTypeProxy.newBeanTypeForClass(ideClass);
if (beanTypeProxy == null)
beanTypeProxy = new IDEBeanTypeProxy(fFactoryRegistry, ideClass);
} catch (ClassNotFoundException e) {
ProxyPlugin.getPlugin().getLogger().log(new Status(IStatus.INFO, ProxyPlugin.getPlugin().getBundle().getSymbolicName(), 0, "", e));
String msg = MessageFormat.format("{0}({1})", new Object[] {e.getClass(), e.getMessage()}); //$NON-NLS-1$
beanTypeProxy = new IDEInitErrorBeanTypeProxy(fFactoryRegistry, typeName, msg);
} catch (ExceptionInInitializerError e) {
ProxyPlugin.getPlugin().getLogger().log(new Status(IStatus.WARNING, ProxyPlugin.getPlugin().getBundle().getSymbolicName(), 0, "", e));
String msg = MessageFormat.format("{0}({1})", new Object[] {e.getClass(), e.getMessage()}); //$NON-NLS-1$
beanTypeProxy = new IDEInitErrorBeanTypeProxy(fFactoryRegistry, typeName, msg);
} catch (LinkageError e) {
ProxyPlugin.getPlugin().getLogger().log(new Status(IStatus.WARNING, ProxyPlugin.getPlugin().getBundle().getSymbolicName(), 0, "", e));
String msg = MessageFormat.format("{0}({1})", new Object[] {e.getClass(), e.getMessage()}); //$NON-NLS-1$
beanTypeProxy = new IDEInitErrorBeanTypeProxy(fFactoryRegistry, typeName, msg);
}
// Cache the instance so we can re-use it again
beanProxies.put(typeName, beanTypeProxy);
return beanTypeProxy;
} else {
// need to create a array of this many dimensions so that we can get the appropriate class for it.
int dims = typeName.lastIndexOf('[')+1;
Class finalComponentType = null;
if (typeName.charAt(dims) == 'L') {
// It is a class.
// Strip off up to the 'L', and the trailing ';'. That is the class name.
IDEBeanTypeProxy finalType = (IDEBeanTypeProxy) getBeanTypeProxy(typeName.substring(dims+1, typeName.length()-1));
if (finalType != null)
finalComponentType = finalType.fClass;
} else {
// It is a type. Need to map it.
finalComponentType = (Class) IDEStandardBeanTypeProxyFactory.MAP_SHORTSIG_TO_TYPE.get(typeName.substring(dims, dims+1));
}
if (finalComponentType != null) {
Object dummyArray = Array.newInstance(finalComponentType, new int[dims]);
beanTypeProxy = new IDEArrayBeanTypeProxy(fFactoryRegistry, typeName, dummyArray.getClass());
beanProxies.put(typeName,beanTypeProxy);
}
return beanTypeProxy;
}
}
/**
* Return an Array type proxy for the given class name of
* the specified dimensions. This is a helper method. The
* same result can be gotton from getBeanTypeProxy.
* e.g.
* getBeanTypeProxy("java.lang.Object", 3)
* is the same as:
* getBeanTypeProxy("[[[Ljava.lang.Object;")
*
* They both result in a type of:
* Object [][][]
*
* or
* getBeanTypeProxy("[Ljava.langObject;", 3)
* becomes
* Object [][][][]
*/
public IBeanTypeProxy getBeanTypeProxy(String componentClassName, int dimensions) {
String jniComponentTypeName = MapTypes.getJNIFormatName(componentClassName);
String compType = jniComponentTypeName;
if (jniComponentTypeName.charAt(0) != '[') {
// We're not already an array, so create correct template.
compType = (String) MAP_TYPENAME_TO_SHORTSIG.get(componentClassName);
if (compType == null) {
// It is a class, and not a type.
compType = "L"+jniComponentTypeName+";"; //$NON-NLS-1$ //$NON-NLS-2$
}
}
// Now create it with the appropriate number of '[' in front.
StringBuffer buffer = new StringBuffer(dimensions+compType.length());
for (int i=0; i<dimensions; i++)
buffer.append('[');
buffer.append(compType);
return getBeanTypeProxy(buffer.toString());
}
/*
* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.IBeanProxyFactory#terminateFactory(boolean)
*/
public void terminateFactory(boolean wait){
}
/**
* registerBeanTypeProxy.
* Register this bean type proxy on behalf of the
* custom factory. This is so that during initializations,
* the custom factory can cache specific bean type proxies
* ahead of time.
*/
public synchronized void registerBeanTypeProxy(IBeanTypeProxy aBeanTypeProxy,boolean permanent){
beanProxies.put(aBeanTypeProxy.getTypeName(), aBeanTypeProxy);
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.IStandardBeanTypeProxyFactory#isBeanTypeRegistered(String)
*/
public synchronized boolean isBeanTypeRegistered(String className) {
return beanProxies.containsKey(MapTypes.getJNIFormatName(className));
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.IStandardBeanTypeProxyFactory#registeredTypes()
*/
public Set registeredTypes() {
return beanProxies.keySet();
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.IStandardBeanTypeProxyFactory#isBeanTypeNotFound(String)
*/
public boolean isBeanTypeNotFound(String className) {
// Do nothing. No need for it in IDE system because there will always be a proxy, even when not found.
// In that case an IDEInitErrorBeanTypeProxy will be created.
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.IStandardBeanTypeProxyFactory#isMaintainNotFoundTypes()
*/
public boolean isMaintainNotFoundTypes() {
// Do nothing. No need for it in IDE system because there will always be a proxy, even when not found.
// In that case an IDEInitErrorBeanTypeProxy will be created.
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.IStandardBeanTypeProxyFactory#setMaintainNotFoundTypes(boolean)
*/
public void setMaintainNotFoundTypes(boolean maintain) {
// Do nothing. No need for it in IDE system because there will always be a proxy, even when not found.
// In that case an IDEInitErrorBeanTypeProxy will be created.
}
}