| /******************************************************************************* |
| * Copyright (c) 2001, 2005 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.remote; |
| /* |
| |
| |
| */ |
| |
| |
| 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.core.*; |
| import org.eclipse.jem.internal.proxy.common.CommandException; |
| import org.eclipse.jem.internal.proxy.common.remote.CommandErrorException; |
| import org.eclipse.jem.internal.proxy.common.remote.Commands; |
| |
| /** |
| * The Remote VM Standard Bean Proxy Factory. |
| * Creation date: (12/3/99 12:01:45 PM) |
| * @author: Joe Winchester |
| */ |
| public final class REMStandardBeanProxyFactory implements IStandardBeanProxyFactory { |
| protected final REMProxyFactoryRegistry fRegistry; |
| protected final REMStandardBeanTypeProxyFactory fBeanTypeProxyFactory; // Convenience field. |
| protected final IREMBeanProxy vmServerProxy; |
| |
| |
| // We need a map for mapping object id's to the proxy. The entry will actually be |
| // a REMStandardBeanProxyFactory.WeakProxyReference. This is so that the |
| // proxy will not be held tightly by this map and can be GC'd if not referenced. |
| // Periodically, the reference queue will be processed to remove any of the |
| // entries that have been GC'd and the server will be told that it can release |
| // the ID on its side. |
| // |
| // This map will be used as synchronize object also for access to it. |
| // |
| // There will be a low priority job that will occasionally process the GC'd objects |
| // and remove them from the queue and the remote vm. It will not remove during lockedTransactions. |
| // |
| // NOTE: Certain proxies never get added to the map. They are the |
| // standard types/class (i.e. null, byte, int, long, short, double, float, byte, string). These |
| // always have the value saved in the proxy so that it can be retrieved without going back |
| // to the server. |
| private final HashMap fIDToProxiesMap = new HashMap(1000); // Map ID's to proxies. The proxies have their id's so we don't need a reverse map |
| private int transactionLockCount = 0; // Count of transactions that have locked access. It is changed under sync control of fIDToProxies map. |
| |
| /** |
| * The Weak reference used for the id to proxies map for the proxy |
| * so that we can clean it up when the proxy has been garbage collected. |
| * |
| * It is important that all changes to the ProxyRef are done through sync on fIDToProxiesMap. |
| */ |
| private static class ProxyRef extends java.lang.ref.WeakReference { |
| private Integer id; // We need the id because this reference will be on the value side |
| // and not the key side of the map, so we need to know the key |
| // so that the object can be removed from the map. |
| // |
| // If the ID is null, then this means this entry has been processed |
| // in some way and should not be released or removed from the table. |
| private int useCnt = 1; // Usage/Ref count. Needed so that we don't get rid of too soon. Since we don't |
| // create a ProxyRef without a usage, we start it off with one. It will be incremented |
| // then on retrievals when needed by users outside of the remote factories themselves. |
| // It won't be physically released until either GC got rid of it, or it goes to 0 or less |
| // on a release request. |
| |
| public ProxyRef(Integer anID, Object proxy, java.lang.ref.ReferenceQueue q) { |
| super(proxy, q); |
| id = anID; |
| } |
| |
| public Integer getID() { |
| return id; |
| } |
| |
| public void clear() { |
| super.clear(); |
| id = null; |
| } |
| |
| public synchronized void incrUseCnt() { |
| useCnt++; |
| } |
| |
| public synchronized int decrUseCnt() { |
| if (--useCnt < 0) |
| useCnt = 0; |
| return useCnt; |
| } |
| } |
| |
| /* Reference queue for cleared Proxies */ |
| private java.lang.ref.ReferenceQueue queue = new java.lang.ref.ReferenceQueue(); |
| |
| /** |
| * Process the entries on the id to proxies map that have been garbage collected. |
| * It is package-protected because only REMRegistryController should call it. |
| */ |
| void processQueue() { |
| ProxyRef pr; |
| while (true) { |
| if (Thread.interrupted()) |
| return; // Maybe going down. (This actually a kludge because the thread happens to be the master thread from the registry controller). |
| |
| synchronized (fIDToProxiesMap) { |
| if (queue == null || transactionLockCount > 0) |
| break; // Either no queue (we are cleaning up) or in a transaction, stop processing and retry on next time slice. |
| if ((pr = (ProxyRef) queue.poll()) != null) { |
| if (pr.getID() != null) { |
| // It hasn't been processed by some other means. |
| fIDToProxiesMap.remove(pr.getID()); |
| releaseID(pr.getID().intValue()); |
| } |
| } else |
| break; // There are no more waiting, so leave. |
| } |
| } |
| } |
| |
| |
| /** |
| * REMBeanProxyFactory constructor comment. |
| * |
| * Note: It assumes the beantype factory has already been registered. |
| */ |
| REMStandardBeanProxyFactory(REMProxyFactoryRegistry aRegistry) { |
| fRegistry = aRegistry; |
| aRegistry.registerBeanProxyFactory(this); |
| fBeanTypeProxyFactory = (REMStandardBeanTypeProxyFactory) aRegistry.getBeanTypeProxyFactory(); |
| fBeanTypeProxyFactory.initialize(this); // Now we're ready for the beantype factory to be initialized. |
| |
| IREMBeanTypeProxy serverType = fBeanTypeProxyFactory.objectClass.newBeanTypeForClass(new Integer(Commands.REMOTEVMSERVER_CLASS), "org.eclipse.jem.internal.proxy.vm.remote.RemoteVMServerThread", false); //$NON-NLS-1$ |
| fBeanTypeProxyFactory.registerBeanTypeProxy(serverType, true); |
| vmServerProxy = serverType.newBeanProxy(new Integer(Commands.REMOTESERVER_ID)); |
| registerProxy(vmServerProxy); |
| } |
| |
| |
| /** |
| * Register a collection of Proxies |
| */ |
| public void registerProxies(Collection proxies) { |
| synchronized(fIDToProxiesMap) { |
| Iterator itr = proxies.iterator(); |
| while (itr.hasNext()) { |
| IREMBeanProxy proxy = (IREMBeanProxy) itr.next(); |
| if (proxy instanceof IBeanTypeProxy || !(proxy.getTypeProxy() instanceof IREMConstantBeanTypeProxy)) { |
| ProxyRef oldRef = (ProxyRef) fIDToProxiesMap.put(proxy.getID(), new ProxyRef(proxy.getID(), proxy, queue)); |
| if (oldRef != null) { |
| // We've replaced it with a new one, so we will clear out the ref so that it won't later try to remove itself |
| oldRef.clear(); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Register a single proxy |
| */ |
| public void registerProxy(IREMBeanProxy proxy) { |
| if (proxy instanceof IBeanTypeProxy || !(proxy.getTypeProxy() instanceof IREMConstantBeanTypeProxy)) |
| synchronized(fIDToProxiesMap) { |
| ProxyRef oldRef = (ProxyRef) fIDToProxiesMap.put(proxy.getID(), new ProxyRef(proxy.getID(), proxy, queue)); |
| if (oldRef != null) { |
| // We've replaced it with a new one, so we will clear out the ref so that it won't later try to remove itself |
| oldRef.clear(); |
| } |
| } |
| } |
| |
| /** |
| * Release a proxy because no longer needed. |
| */ |
| public void releaseProxy(IBeanProxy proxy) { |
| if (!proxy.isValid()) |
| return; |
| if (proxy instanceof IBeanTypeProxy && !fBeanTypeProxyFactory.releaseProxy((IBeanTypeProxy) proxy)) |
| return; // BeanType and type factory won't allow release of it. |
| Integer id = ((IREMBeanProxy) proxy).getID(); |
| synchronized(fIDToProxiesMap) { |
| // Synced in here so that we will remove it before some one else from a different thread may try |
| // to access it again. |
| if (id.intValue() != Commands.NOT_AN_ID) { |
| ProxyRef ref = (ProxyRef) fIDToProxiesMap.get(id); |
| if (ref == null || ref.decrUseCnt() <= 0) { |
| // No usage, so do actual release. |
| fIDToProxiesMap.remove(id); |
| ((IREMBeanProxy) proxy).release(); |
| if (ref != null) |
| ref.enqueue(); // Queue it up so that on next release cycle it will go away. |
| } |
| } else { |
| ((IREMBeanProxy) proxy).release(); |
| } |
| } |
| } |
| |
| /** |
| * Release a specific ID. This is used in case an ID has been sent |
| * but we couldn't proxy it. In that case we only have an ID. It is |
| * also used when a proxy has been released explicitly or through GC. |
| * In that case it has already been de-registered. |
| */ |
| private void releaseID(int anID) { |
| try { |
| IREMConnection connect = fRegistry.getFreeConnection(); |
| try { |
| connect.releaseID(anID); |
| } finally { |
| fRegistry.returnConnection(connect); |
| } |
| } catch (IllegalStateException e) { |
| // Couldn't get connection, don't bother with a release. |
| } |
| } |
| |
| /** |
| * For the Remote Factory we will create an REMBeanProxy using the null constructor |
| * Package protected so only REMBeanTypeProxies can create instances. |
| */ |
| |
| IBeanProxy createBeanProxy(IREMBeanTypeProxy aTypeProxy) throws ThrowableProxy { |
| return REMStandardBeanProxyConstants.getConstants(fRegistry).getClassNewInstance().invoke(null, aTypeProxy); |
| } |
| |
| /** |
| * For the Remote Factory we will create a REMBeanProxy using the initializationString. |
| * Package protected so only REMBeanTypeProxies can create instances. |
| */ |
| IBeanProxy createBeanProxy(IREMBeanTypeProxy aTypeProxy, String initializationString) |
| throws ThrowableProxy, CommandException, ClassCastException, InstantiationException, IllegalStateException { |
| IREMConnection connect = fRegistry.getFreeConnection(); |
| startTransaction(); |
| // Starting a transaction, we will be getting id's back and need to get data in a separate step, so we need to group it in a transaction. |
| try { |
| Commands.ValueObject newInstanceData = null; |
| try { |
| newInstanceData = getNewInstanceData(aTypeProxy, initializationString, connect); |
| } catch (CommandErrorException e) { |
| switch (e.getErrorCode()) { |
| case Commands.CLASS_CAST_EXCEPTION: |
| // The result was not of the correct type. |
| throw new ClassCastException( |
| MessageFormat.format(ProxyRemoteMessages.Classcast_EXC_, new Object[] {extractFirstLine(initializationString), aTypeProxy.getTypeName()})); |
| case Commands.CANNOT_EVALUATE_STRING: |
| // Want to log the exception that caused it to not evaluate. |
| // Don't need to log this side, just log the RemoteVM side of the trace. |
| java.io.StringWriter s = new java.io.StringWriter(); |
| java.io.PrintWriter w = new java.io.PrintWriter(s); |
| ((ThrowableProxy) e.getErrorObject()).printProxyStackTrace(w); |
| ProxyPlugin.getPlugin().getLogger().log(new Status(IStatus.WARNING, ProxyPlugin.getPlugin().getBundle().getSymbolicName(), 0, s.toString(), null)); |
| throw new InstantiationException( |
| MessageFormat.format(ProxyRemoteMessages.Instantiate_EXC_, new Object[] {extractFirstLine(initializationString)})); |
| default: |
| throw e; //$NON-NLS-1$ |
| } |
| } catch (CommandException e) { |
| if (e.isRecoverable()) { |
| ProxyPlugin.getPlugin().getLogger().log( |
| new Status( |
| IStatus.WARNING, |
| ProxyPlugin.getPlugin().getBundle().getSymbolicName(), |
| 0, |
| "", //$NON-NLS-1$ |
| e)); |
| } else { |
| // It failed in the command, try again. |
| fRegistry.closeConnection(connect); |
| connect = null; |
| connect = fRegistry.getFreeConnection(); |
| try { |
| newInstanceData = getNewInstanceData(aTypeProxy, initializationString, connect); |
| } catch (CommandException eAgain) { |
| // It failed again. Close this connection and don't let it be returned. |
| fRegistry.closeConnection(connect); |
| connect = null; // This is so that it won't be returned. |
| } |
| } |
| } finally { |
| if (connect != null) |
| fRegistry.returnConnection(connect); |
| } |
| |
| if (newInstanceData != null) |
| return getBeanProxy(newInstanceData); // Turn it into a proxy |
| } finally { |
| stopTransaction(); // Now we can release the transaction. |
| } |
| |
| return null; |
| } |
| |
| private String extractFirstLine(String initString) { |
| // Need to extract the first line for the messageFormat not to barf. |
| int cr = initString.indexOf('\r'); |
| int lf = initString.indexOf('\n'); |
| if (cr != -1 || lf != -1) { |
| if (cr == -1 || (lf != -1 && lf < cr)) |
| return initString.substring(0, lf); |
| else |
| return initString.substring(0, cr); |
| } else |
| return initString; |
| } |
| |
| |
| /** |
| * actually create it using a passed in connection. This allows retry capability. |
| * |
| * This will send the request over to the connection. |
| * |
| * If we get an OBJECT back, then the beantypeproxy that the classID in the |
| * value points to must be of type IREMConstantBeanTypeProxy so that we can |
| * send this new object to the correct beantype to create the correct proxy. |
| * |
| * If we get an OBJECT_ID back, then the beantypeproxy that the classID in |
| * the value points to must be able to handle creating a proxy of that type. |
| */ |
| private Commands.ValueObject getNewInstanceData(IREMBeanTypeProxy aTypeProxy, String initializationString, IREMConnection connect) throws ThrowableProxy, CommandException { |
| try { |
| Commands.ValueObject newInstanceData = new Commands.ValueObject(); |
| connect.getNewInstance(aTypeProxy.getID().intValue(), initializationString, newInstanceData); |
| return newInstanceData; |
| } catch (CommandErrorException e) { |
| // TBD - Needs to handle error of not evaluatable and send over to the compilor. |
| processErrorReturn(e); // Process this |
| } |
| return null; |
| } |
| |
| /** |
| * actually create it using a passed in connection. This allows retry capability. |
| */ |
| private void getObjectInstanceData(IREMConnection connect, int objectID, Commands.ValueObject valueReturn) throws ThrowableProxy, CommandException { |
| try { |
| connect.getObjectData(objectID, valueReturn); |
| } catch (CommandErrorException e) { |
| processErrorReturn(e); // Process this |
| } |
| } |
| |
| /** |
| * Get a bean proxy from the value object passed in. If not yet created, create one. |
| * NOTE: NULL type actually returns a true null. This is so that if people are casting |
| * the returned proxy to a specific type (e.g IIntegerBeanProxy), then they won't get |
| * a ClassCastException, they will get a null. This is easier for them to handle. |
| * |
| * NOTE: This is public ONLY so that extension factories can create correct types of |
| * proxies in consistent manner from a value object. |
| * |
| * It is important that this is called |
| * from within a transaction only because otherwise the value could have invalid data |
| * by the time we try to get the data out of it. |
| */ |
| public IBeanProxy getBeanProxy(Commands.ValueObject value) throws ThrowableProxy, CommandException { |
| switch (value.type) { |
| // Null result. |
| case (byte) Commands.VOID_TYPE: |
| return null; |
| // A constant object was received. |
| case Commands.OBJECT: |
| IREMConstantBeanTypeProxy constantBeanType = null; |
| try { |
| constantBeanType = (IREMConstantBeanTypeProxy) getBeanType(value.classID); |
| if (constantBeanType == null) |
| return null; // Cannot find the type to create it. |
| } catch (ClassCastException e) { |
| // It wasn't a constant type, so we can't create it. Return null. |
| ProxyPlugin.getPlugin().getLogger().log(new Status(IStatus.WARNING, ProxyPlugin.getPlugin().getBundle().getSymbolicName(), 0, "", e)); //$NON-NLS-1$ |
| return null; |
| } |
| |
| return constantBeanType.newBeanProxy(value); |
| |
| // An existing object_id was returned, the object should exist. If it doesn't |
| // then submit the info command to try to recreate it correctly. |
| case Commands.OBJECT_ID: |
| Integer objectID = new Integer(value.objectID); |
| IBeanProxy proxy = retrieveProxy(objectID, true); |
| if (proxy != null) |
| return proxy; |
| |
| // Not found, need to try to recreate it. |
| IREMConnection connect = fRegistry.getFreeConnection(); |
| try { |
| getObjectInstanceData(connect, value.objectID, value); // Go and get the data |
| } catch (CommandErrorException e) { |
| if (e.isRecoverable()) { |
| ProxyPlugin.getPlugin().getLogger().log( |
| new Status( |
| IStatus.WARNING, |
| ProxyPlugin.getPlugin().getBundle().getSymbolicName(), |
| 0, |
| "", //$NON-NLS-1$ |
| e)); |
| return null; |
| } else { |
| // Try one more time. |
| fRegistry.closeConnection(connect); |
| connect = null; |
| connect = fRegistry.getFreeConnection(); |
| try { |
| getObjectInstanceData(connect, value.objectID, value); // Go and get the data |
| } catch (CommandErrorException eAgain) { |
| fRegistry.closeConnection(connect); |
| connect = null; |
| throw eAgain; |
| } |
| } |
| } finally { |
| if (connect != null) |
| fRegistry.returnConnection(connect); |
| } |
| |
| return getBeanProxy(value); // Now process it to create the new data. |
| |
| // An new object id. Need to get the class type and let it create it. |
| case Commands.NEW_OBJECT_ID: |
| try { |
| IREMBeanTypeProxy newBeanType = getBeanType(value.classID); |
| IREMBeanProxy newProxy = newBeanType.newBeanProxy(new Integer(value.objectID)); |
| if (newProxy != null) |
| registerProxy(newProxy); |
| return newProxy; |
| } catch (CommandException e) { |
| // The server has created a new object, but we couldn't create/register a proxy for it. |
| // We need to release it so that the server can get rid of it. Otherwise it would hang |
| // around over there forever. |
| releaseID(value.objectID); |
| throw e; |
| } catch (RuntimeException e) { |
| // The server has created a new object, but we couldn't create/register a proxy for it. |
| // We need to release it so that the server can get rid of it. Otherwise it would hang |
| // around over there forever. |
| releaseID(value.objectID); |
| throw e; |
| } |
| |
| // An exception was thrown, create the ThrowableProxy and then throw it. |
| case Commands.THROW: |
| IREMBeanProxy newThrowProxy = null; |
| try { |
| IREMBeanTypeProxy newThrowType = getBeanType(value.classID); |
| newThrowProxy = newThrowType.newBeanProxy(new Integer(value.objectID)); |
| if (newThrowProxy != null) |
| registerProxy(newThrowProxy); |
| } catch (CommandException e) { |
| // The server has created a new object, but we couldn't create/register a proxy for it. |
| // We need to release it so that the server can get rid of it. Otherwise it would hang |
| // around over there forever. |
| releaseID(value.objectID); |
| throw e; |
| } catch (RuntimeException e) { |
| // The server has created a new object, but we couldn't create/register a proxy for it. |
| // We need to release it so that the server can get rid of it. Otherwise it would hang |
| // around over there forever. |
| releaseID(value.objectID); |
| throw e; |
| } |
| // It really should be a throwable, but if not, just return it. |
| if (newThrowProxy instanceof ThrowableProxy) |
| throw (ThrowableProxy) newThrowProxy; |
| else |
| return newThrowProxy; |
| |
| // It is one of the standard kinds, which are Constant types |
| default: |
| IREMConstantBeanTypeProxy standardBeanType = null; |
| try { |
| standardBeanType = (IREMConstantBeanTypeProxy) getBeanType(value.type); |
| if (standardBeanType == null) |
| return null; // Cannot find the type to create it. |
| } catch (ClassCastException e) { |
| // It wasn't a standard type, so we can't create it. Return null. |
| ProxyPlugin.getPlugin().getLogger().log(new Status(IStatus.WARNING, ProxyPlugin.getPlugin().getBundle().getSymbolicName(), 0, "", e)); //$NON-NLS-1$ |
| return null; |
| } |
| return standardBeanType.newBeanProxy(value); |
| } |
| } |
| |
| /** |
| * Process the error exception. Get the data from it and turn it into proxy data. |
| * If it is a THROW, then it will throw the Throwable instead. |
| * |
| * NOTE: It is public ONLY so that extension factories can process errors in |
| * an consistent manner. |
| * |
| * It is important that this be called only within a transaction. |
| */ |
| public void processErrorReturn(CommandErrorException e) throws CommandException, ThrowableProxy { |
| int code = e.getErrorCode(); |
| Object data = null; |
| if (code == Commands.THROWABLE_SENT) |
| data = getBeanProxy(e.getValue()); // It is Throw sent, so let the throw from getBeanProxy continue on out. (But as a safety, we still try to get the data. |
| else { |
| try { |
| data = getBeanProxy(e.getValue()); |
| } catch (ThrowableProxy t) { |
| // But we want to keep throwables in this case. They are just data for the command error. |
| data = t; |
| } |
| } |
| throw new CommandErrorException(MessageFormat.format(ProxyRemoteMessages.RemoteCmd_EXC_, new Object[] {new Integer(code)}), code, e.getValue(), data); // Create a new one and throw it containing the proxied data. //$NON-NLS-1$ |
| } |
| |
| |
| /** |
| * Get a beantype where the id passed in is the classID of the beantype. |
| * If not found, then go get it loaded. If it can't be found, then we will |
| * release the id because it means we have an id from the server, but we |
| * can't create a proxy for it, so don't keep the server holding it. |
| * NOTE: This is public ONLY so that extension factories can create correct types |
| * in a consistent manner from the id. |
| * |
| * It is important that this be called only from within a transaction. |
| */ |
| public IREMBeanTypeProxy getBeanType(int id) throws CommandException { |
| IREMBeanTypeProxy beanType = null; |
| try { |
| Integer classID = new Integer(id); |
| beanType = (IREMBeanTypeProxy) retrieveProxy(classID, false); |
| if (beanType == null) |
| beanType = fBeanTypeProxyFactory.createBeanTypeProxy(classID); // We don't have it, need to go to the factory so that it can go query what it needs |
| if (beanType == null) |
| return null; // Cannot find the type to create it. |
| } catch (ClassCastException e) { |
| // It wasn't a bean type, so we can't create it. Return null. |
| ProxyPlugin.getPlugin().getLogger().log(new Status(IStatus.WARNING, ProxyPlugin.getPlugin().getBundle().getSymbolicName(), 0, "", e)); //$NON-NLS-1$ |
| } finally { |
| if (beanType == null) |
| releaseID(id); // Couldn't create a proxy, so release the id. |
| } |
| return beanType; |
| } |
| |
| |
| /** |
| * Return a proxy wrapping the primitive integer |
| */ |
| public IIntegerBeanProxy createBeanProxyWith(int aPrimitiveInteger) { |
| |
| return fBeanTypeProxyFactory.intType.createIntegerBeanProxy(aPrimitiveInteger); |
| } |
| |
| /** |
| * Return a proxy wrapping the primitive byte |
| */ |
| public INumberBeanProxy createBeanProxyWith(byte aPrimitiveByte) { |
| |
| return fBeanTypeProxyFactory.byteType.createByteBeanProxy(aPrimitiveByte); |
| } |
| |
| /** |
| * Return a proxy wrapping the primitive char |
| */ |
| public ICharacterBeanProxy createBeanProxyWith(char aPrimitiveChar) { |
| |
| return fBeanTypeProxyFactory.charType.createCharacterBeanProxy(aPrimitiveChar); |
| } |
| |
| /** |
| * Return a proxy wrapping the primitive short |
| */ |
| public INumberBeanProxy createBeanProxyWith(short aPrimitiveShort) { |
| |
| return fBeanTypeProxyFactory.shortType.createShortBeanProxy(aPrimitiveShort); |
| } |
| |
| /** |
| * Return a proxy wrapping the primitive long |
| */ |
| public INumberBeanProxy createBeanProxyWith(long aPrimitiveLong) { |
| |
| return fBeanTypeProxyFactory.longType.createLongBeanProxy(aPrimitiveLong); |
| } |
| /** |
| * Return a proxy wrapping the primitive double |
| */ |
| public INumberBeanProxy createBeanProxyWith(double aPrimitiveDouble) { |
| |
| return fBeanTypeProxyFactory.doubleType.createDoubleBeanProxy(aPrimitiveDouble); |
| } |
| /** |
| * Return a proxy wrapping the primitive float |
| */ |
| public INumberBeanProxy createBeanProxyWith(float aPrimitiveFloat) { |
| |
| return fBeanTypeProxyFactory.floatType.createFloatBeanProxy(aPrimitiveFloat); |
| } |
| |
| /** |
| * createBeanProxyWith method comment. |
| */ |
| public IBooleanBeanProxy createBeanProxyWith(Boolean aBoolean) { |
| return fBeanTypeProxyFactory.booleanClass.createBooleanBeanProxy(aBoolean); |
| } |
| /** |
| * Return a proxy that wraps the Integer argument |
| */ |
| public IIntegerBeanProxy createBeanProxyWith(Integer anInteger) { |
| |
| return fBeanTypeProxyFactory.integerClass.createIntegerBeanProxy(anInteger); |
| } |
| /** |
| * createBeanProxyWith method comment. |
| */ |
| public INumberBeanProxy createBeanProxyWith(Number aNumber) { |
| REMAbstractNumberBeanTypeProxy type = (REMAbstractNumberBeanTypeProxy) fBeanTypeProxyFactory.getBeanTypeProxy(aNumber.getClass().getName()); |
| return type.createNumberBeanProxy(aNumber); |
| } |
| /** |
| * Return a proxy for the argument |
| */ |
| public IStringBeanProxy createBeanProxyWith(String aString) { |
| |
| return fBeanTypeProxyFactory.stringClass.createStringBeanProxy(aString); |
| |
| } |
| /** |
| * Return a proxy for the argument |
| */ |
| public ICharacterBeanProxy createBeanProxyWith(Character aCharacter) { |
| |
| return fBeanTypeProxyFactory.characterClass.createCharacterBeanProxy(aCharacter); |
| |
| } |
| /** |
| * createBeanProxyWith method comment. |
| */ |
| public IBooleanBeanProxy createBeanProxyWith(boolean aPrimitiveBoolean) { |
| return fBeanTypeProxyFactory.booleanType.createBooleanBeanProxy(aPrimitiveBoolean); |
| } |
| |
| /** |
| * Create an array bean proxy. |
| * |
| * - (int, new int[2] {3, 4}) will create: |
| * int [3] [4] |
| * |
| * - (int[], new int[1] {1}) |
| * int [1] |
| * |
| * - (int[], new int[2] {2,3}) |
| * int [2] [3] |
| * |
| * |
| * - (int[], null) or (int[], new int[0]) or (int, null) or (int, new int[0]) |
| * int [0]... |
| * or |
| * (int[][]..., null) or (int[][]..., new int[0]) |
| * int[0][]... |
| * This is because an array instance with no specified dimensions is not valid. |
| * |
| * - (int[][], new int[1] {3}) |
| * int[3][] |
| */ |
| public IArrayBeanProxy createBeanProxyWith(IBeanTypeProxy type, int[] dimensions) throws ThrowableProxy { |
| if (type.isArray()) |
| return ((REMArrayBeanTypeProxy) type).createBeanProxyWith(dimensions); // Already an array type, just pass it on. |
| else { |
| // It is not an array type, so we need to get an array of this type and dimensions. |
| REMArrayBeanTypeProxy arrayType = (REMArrayBeanTypeProxy) fBeanTypeProxyFactory.getBeanTypeProxy(type.getTypeName(), dimensions.length); |
| return arrayType.createBeanProxyWith(dimensions); |
| } |
| } |
| /** |
| * Create a one-dimensional array. |
| * The result will be the same as calling |
| * createBeanProxyWith(IBeanTypeProxy type, new int[1] {x}) |
| * where 'x' is the value passed in as the dimension. |
| */ |
| public IArrayBeanProxy createBeanProxyWith(IBeanTypeProxy type, int dimension) throws ThrowableProxy { |
| return createBeanProxyWith(type, new int[] {dimension}); |
| } |
| |
| /** |
| * Retrieve the proxy from the mapping table. Handle already GC'd. |
| * If this returns null, it is important that the caller tries to recreate |
| * it since the id is still valid on the server. |
| */ |
| private IBeanProxy retrieveProxy(Integer objectID, boolean incrementUseCnt) { |
| synchronized (fIDToProxiesMap) { |
| ProxyRef ref = (ProxyRef) fIDToProxiesMap.get(objectID); |
| if (ref != null) { |
| Object bp = ref.get(); |
| if (ref.isEnqueued() || bp == null) { |
| // It's waiting to be removed, or has been removed. i.e. GC'd, so just remove it from the map, next processQueue will remove it from the queue. |
| fIDToProxiesMap.remove(objectID); |
| ref.clear(); // This is so that when the processQueue see's it, |
| // it won't send a release request to the server |
| // since it will be recreated when this method returns. |
| return null; |
| } else { |
| if (incrementUseCnt) |
| ref.incrUseCnt(); |
| return (IBeanProxy) bp; |
| } |
| } else |
| return null; |
| } |
| } |
| |
| /** |
| * Start Transaction: During the time between start/stop transaction, |
| * proxies will not be cleaned up. This prevents the case of a two step |
| * transaction where the returned ID from the remote vm is for a proxy |
| * that is about to be cleaned up, and then having that proxy disappear |
| * when going for the data for it. |
| * |
| * Note: It is IMPERITIVE that the start/stop is used in the following way: |
| * factory.startTransaction(); |
| * try { |
| * do your stuff... |
| * } finally { |
| * factory.stopTransaction(); |
| * } |
| * |
| * This way it can never accidently leave it in a locked state. |
| */ |
| public void startTransaction() { |
| synchronized (fIDToProxiesMap) { |
| transactionLockCount++; |
| } |
| } |
| |
| public boolean inTransaction() { |
| synchronized (fIDToProxiesMap) { |
| return transactionLockCount != 0; |
| } |
| } |
| |
| /** |
| * Stop Transaction: During the time between start/stop transaction, |
| * proxies will not be cleaned up. This prevents the case of a two step |
| * transaction where the returned ID from the remote vm is for a proxy |
| * that is about to be cleaned up, and then having that proxy disappear |
| * when going for the data for it. |
| * |
| * Note: It is IMPERITIVE that the start/stop is used in the following way: |
| * factory.startTransaction(); |
| * try { |
| * do your stuff... |
| * } finally { |
| * factory.stopTransaction(); |
| * } |
| * |
| * This way it can never accidently leave it in a locked state. |
| */ |
| public void stopTransaction() { |
| synchronized (fIDToProxiesMap) { |
| if (--transactionLockCount < 0) |
| transactionLockCount = 0; // Shouldn't occur, but just in case. |
| } |
| } |
| |
| /** |
| * Terminate the factory. If this is being terminated, then the server is being terminated too. |
| * So just go through all of the proxies and release them, but don't send any notification to |
| * the server since the server is subsequently just going to throw them away when it terminates. |
| * <p> |
| * This can't run async, so wait is a suggestion here. |
| */ |
| public void terminateFactory(boolean wait) { |
| synchronized (fIDToProxiesMap) { |
| Iterator itr = fIDToProxiesMap.values().iterator(); |
| while (itr.hasNext()) { |
| ProxyRef ref = (ProxyRef) itr.next(); |
| if (ref != null) { |
| Object bp = ref.get(); |
| // If not cleaned up and not enqueued, release it. |
| if (bp != null && !ref.isEnqueued()) |
| ((IREMBeanProxy) bp).release(); |
| } |
| } |
| |
| fIDToProxiesMap.clear(); |
| queue = null; // Don't bother processing the queue, don't need to now. |
| } |
| } |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IStandardBeanProxyFactory#createExpression() |
| */ |
| public IExpression createExpression() { |
| return new REMExpression(this.fRegistry); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IStandardBeanProxyFactory#createBeanProxyFrom(java.lang.String) |
| */ |
| public IBeanProxy createBeanProxyFrom(String initializationString) throws ThrowableProxy, ClassCastException, InstantiationException { |
| try { |
| return createBeanProxy(fBeanTypeProxyFactory.voidType, initializationString); |
| } catch (CommandException e) { |
| ProxyPlugin.getPlugin().getLogger().log(new Status(IStatus.WARNING, ProxyPlugin.getPlugin().getBundle().getSymbolicName(), 0, "", e)); //$NON-NLS-1$ } |
| } |
| return null; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.jem.internal.proxy.core.IStandardBeanProxyFactory#convertToPrimitiveBeanProxy(org.eclipse.jem.internal.proxy.core.IBeanProxy) |
| */ |
| public IBeanProxy convertToPrimitiveBeanProxy(IBeanProxy nonPrimitiveProxy) { |
| if (nonPrimitiveProxy == null) |
| return null; |
| if (!nonPrimitiveProxy.isValid()) |
| return nonPrimitiveProxy; |
| IREMBeanTypeProxy type = (IREMBeanTypeProxy) nonPrimitiveProxy.getTypeProxy(); |
| // Step into the internals. The ID is a constant int, so we can use a switch stmt. |
| switch (type.getID().intValue()) { |
| case Commands.BOOLEAN_CLASS: |
| return this.createBeanProxyWith(((IBooleanBeanProxy) nonPrimitiveProxy).booleanValue()); |
| case Commands.BYTE_CLASS: |
| return this.createBeanProxyWith(((INumberBeanProxy) nonPrimitiveProxy).byteValue()); |
| case Commands.CHARACTER_CLASS: |
| return this.createBeanProxyWith(((ICharacterBeanProxy) nonPrimitiveProxy).charValue()); |
| case Commands.DOUBLE_CLASS: |
| return this.createBeanProxyWith(((INumberBeanProxy) nonPrimitiveProxy).doubleValue()); |
| case Commands.FLOAT_CLASS: |
| return this.createBeanProxyWith(((INumberBeanProxy) nonPrimitiveProxy).floatValue()); |
| case Commands.INTEGER_CLASS: |
| return this.createBeanProxyWith(((INumberBeanProxy) nonPrimitiveProxy).intValue()); |
| case Commands.LONG_CLASS: |
| return this.createBeanProxyWith(((INumberBeanProxy) nonPrimitiveProxy).longValue()); |
| case Commands.SHORT_CLASS: |
| return this.createBeanProxyWith(((INumberBeanProxy) nonPrimitiveProxy).shortValue()); |
| default: |
| return nonPrimitiveProxy; |
| } |
| } |
| |
| |
| public IBeanProxy getIVMServerProxy() { |
| return vmServerProxy; |
| } |
| } |
| |
| |