/*************************************************************************
*
* ADOBE CONFIDENTIAL __________________
*
* Copyright 2002 - 2007 Adobe Systems Incorporated All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains the property of Adobe Systems Incorporated and its suppliers, if any. The intellectual and technical concepts contained herein are
* proprietary to Adobe Systems Incorporated and its suppliers and may be covered by U.S. and Foreign Patents, patents in process, and are protected by trade secret or copyright law. Dissemination of
* this information or reproduction of this material is strictly forbidden unless prior written permission is obtained from Adobe Systems Incorporated.
**************************************************************************/
package flex.messaging.io;
import java.io.Externalizable;
import java.io.Serializable;
import java.util.List;
import flex.messaging.MessageException;
import flex.messaging.io.amf.ASObject;
import flex.messaging.log.Log;
import flex.messaging.log.LogCategories;
import flex.messaging.log.Logger;
import flex.messaging.util.ClassUtil;
/**
* Simple abstract implementation of PropertyProxy's common properties. Specific sub-classes need to provide the full implementation focusing on the retrieval of the instance traits or
* "list of properties" and a specific value for a given property name.
*
* @see flex.messaging.io.PropertyProxy
* @exclude
*/
public abstract class AbstractProxy implements PropertyProxy, Serializable
{
/**
*
*/
private static final long serialVersionUID = 1L;
protected Object defaultInstance;
protected String alias;
protected boolean dynamic;
protected boolean externalizable;
protected boolean includeReadOnly;
protected SerializationDescriptor descriptor;
protected SerializationContext context;
protected static final String LOG_CATEGORY = LogCategories.ENDPOINT_TYPE;
private static final int CONVERSION_ERROR = 10006;
protected AbstractProxy(Object defaultInstance)
{
this.defaultInstance = defaultInstance;
if (defaultInstance != null)
{
alias = defaultInstance.getClass().getName();
}
}
/** {@inheritDoc} */
@Override
public Object getDefaultInstance()
{
return defaultInstance;
}
/** {@inheritDoc} */
@Override
public void setDefaultInstance(Object instance)
{
defaultInstance = instance;
}
/**
* A utility method which returns the Class from the given Class name using the current type context's class loader with createASObjectForMissingType=false.
*
* @param className
* the class name.
* @return a Class object for the named class.
*/
public static Class getClassFromClassName(String className)
{
return getClassFromClassName(className, false);
}
/**
* A utility method which returns the Class from the given Class name using the current type context's class loader.
*
* @param className
* the class name.
* @param createASObjectForMissingType
* determines whether an ASObject is created for a type that is not found on the server, instead of throwing an error.
*
* @return a Class object for the named class.
*/
public static Class getClassFromClassName(String className, boolean createASObjectForMissingType)
{
TypeMarshallingContext typeContext = TypeMarshallingContext.getTypeMarshallingContext();
try
{
return ClassUtil.createClass(className, typeContext.getClassLoader());
}
catch (MessageException me)
{
// Type was not found.
if (me.getCode().startsWith(MessageException.CODE_SERVER_RESOURCE_UNAVAILABLE))
{
if (createASObjectForMissingType) // Return ASObject instead.
return ASObject.class;
}
throw me; // Rethrow.
}
}
/**
* A utility method which creates an instance from a given class name. It assumes the class has a zero arg constructor.
*
* @param className
* the class name
* @return the instance of the named class.
*/
public static Object createInstanceFromClassName(String className)
{
Class desiredClass = getClassFromClassName(className);
return ClassUtil.createDefaultInstance(desiredClass, null);
}
/** {@inheritDoc} */
@Override
public Object createInstance(String className)
{
Object instance;
if (className == null || className.length() == 0)
{
instance = new ASObject();
}
else if (className.startsWith(">")) // Handle [RemoteClass] (no server alias)
{
instance = new ASObject();
((ASObject) instance).setType(className);
}
else
{
SerializationContext context = getSerializationContext();
if (context.instantiateTypes || className.startsWith("flex."))
{
return createInstanceFromClassName(className);
}
else
{
// Just return type info with an ASObject...
instance = new ASObject();
((ASObject) instance).setType(className);
}
}
return instance;
}
/** {@inheritDoc} */
@Override
public List getPropertyNames()
{
return getPropertyNames(getDefaultInstance());
}
/** {@inheritDoc} */
@Override
public Class getType(String propertyName)
{
return getType(getDefaultInstance(), propertyName);
}
/** {@inheritDoc} */
@Override
public Object getValue(String propertyName)
{
return getValue(getDefaultInstance(), propertyName);
}
/** {@inheritDoc} */
@Override
public void setValue(String propertyName, Object value)
{
setValue(getDefaultInstance(), propertyName, value);
}
/** {@inheritDoc} */
@Override
public void setAlias(String value)
{
alias = value;
}
/** {@inheritDoc} */
@Override
public String getAlias()
{
return alias;
}
/** {@inheritDoc} */
@Override
public void setDynamic(boolean value)
{
dynamic = value;
}
/** {@inheritDoc} */
@Override
public boolean isDynamic()
{
return dynamic;
}
/** {@inheritDoc} */
@Override
public boolean isExternalizable()
{
return externalizable;
}
/** {@inheritDoc} */
@Override
public void setExternalizable(boolean value)
{
externalizable = value;
}
/** {@inheritDoc} */
@Override
public boolean isExternalizable(Object instance)
{
return instance instanceof Externalizable;
}
/** {@inheritDoc} */
@Override
public SerializationContext getSerializationContext()
{
if (context == null)
{
return SerializationContext.getSerializationContext();
}
return context;
}
/** {@inheritDoc} */
@Override
public void setSerializationContext(SerializationContext value)
{
context = value;
}
/** {@inheritDoc} */
@Override
public void setIncludeReadOnly(boolean value)
{
includeReadOnly = value;
}
/** {@inheritDoc} */
@Override
public boolean getIncludeReadOnly()
{
return includeReadOnly;
}
/** {@inheritDoc} */
@Override
public SerializationDescriptor getDescriptor()
{
return descriptor;
}
/** {@inheritDoc} */
@Override
public void setDescriptor(SerializationDescriptor descriptor)
{
this.descriptor = descriptor;
}
/**
* This is called after the serialization finishes. We return the same object here... this is an opportunity to replace the instance we use once we have gathered all of the state into a temporary
* object.
*/
@Override
public Object instanceComplete(Object instance)
{
return instance;
}
/**
* Returns the instance to serialize in place of the supplied instance.
*/
@Override
public Object getInstanceToSerialize(Object instance)
{
return instance;
}
/** {@inheritDoc} */
@Override
public Object clone()
{
try
{
AbstractProxy clonedProxy = (AbstractProxy) super.clone();
clonedProxy.setCloneFieldsFrom(this);
return clonedProxy;
}
catch (CloneNotSupportedException e)
{
if (Log.isError())
{
Logger log = Log.getLogger(LOG_CATEGORY);
log.error("Failed to clone a property proxy: " + toString());
}
MessageException ex = new MessageException();
ex.setMessage(CONVERSION_ERROR);
throw ex;
}
}
/**
* A string including the default instance, class and descriptor info
*
* @return debug string.
*/
@Override
public String toString()
{
if (defaultInstance != null)
return "[Proxy(inst=" + defaultInstance + ") proxyClass=" + getClass() + " descriptor=" + descriptor + "]";
else
return "[Proxy(proxyClass=" + getClass() + " descriptor=" + descriptor + "]";
}
protected void setCloneFieldsFrom(AbstractProxy source)
{
setDescriptor(source.getDescriptor());
setDefaultInstance(source.getDefaultInstance());
context = source.context;
includeReadOnly = source.includeReadOnly;
}
}