blob: 2f29fb6ca5db4e2af16f134484bbce6686d337db [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package flex.messaging.io;
import java.util.List;
import java.io.Externalizable;
import java.io.Serializable;
import flex.messaging.MessageException;
import flex.messaging.io.amf.ASObject;
import flex.messaging.log.LogCategories;
import flex.messaging.log.Log;
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
*
*/
public abstract class AbstractProxy implements PropertyProxy, Serializable
{
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} */
public Object getDefaultInstance()
{
return defaultInstance;
}
/** {@inheritDoc} */
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.
*
* @param className the class name.
* @return a Class object for the named class.
*/
public static Class getClassFromClassName(String className)
{
TypeMarshallingContext typeContext = TypeMarshallingContext.getTypeMarshallingContext();
return ClassUtil.createClass(className, typeContext.getClassLoader());
}
/**
* 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
* for a type that is missing on the server, instead of throwing a server resource not found
* exception.
* @return the instance of the named class.
*/
public static Object createInstanceFromClassName(String className)
{
Class<?> desiredClass = getClassFromClassName(className);
return ClassUtil.createDefaultInstance(desiredClass, null, true /*validate*/);
}
/** {@inheritDoc} */
public Object createInstance(String className)
{
Object instance;
if (className == null || className.length() == 0)
{
instance = ClassUtil.createDefaultInstance(ASObject.class, null, true /*validate*/);
}
else if (className.startsWith(">")) // Handle [RemoteClass] (no server alias)
{
instance = ClassUtil.createDefaultInstance(ASObject.class, null, true /*validate*/);
((ASObject)instance).setType(className);
}
else
{
if (getSerializationContext().instantiateTypes || className.startsWith("flex."))
return createInstanceFromClassName(className);
// Just return type info with an ASObject...
instance = ClassUtil.createDefaultInstance(ASObject.class, null, true /*validate*/);
((ASObject)instance).setType(className);
}
return instance;
}
/** {@inheritDoc} */
public List getPropertyNames()
{
return getPropertyNames(getDefaultInstance());
}
/** {@inheritDoc} */
public Class getType(String propertyName)
{
return getType(getDefaultInstance(), propertyName);
}
/** {@inheritDoc} */
public Object getValue(String propertyName)
{
return getValue(getDefaultInstance(), propertyName);
}
/** {@inheritDoc} */
public void setValue(String propertyName, Object value)
{
setValue(getDefaultInstance(), propertyName, value);
}
/** {@inheritDoc} */
public void setAlias(String value)
{
alias = value;
}
/** {@inheritDoc} */
public String getAlias()
{
return alias;
}
/** {@inheritDoc} */
public void setDynamic(boolean value)
{
dynamic = value;
}
/** {@inheritDoc} */
public boolean isDynamic()
{
return dynamic;
}
/** {@inheritDoc} */
public boolean isExternalizable()
{
return externalizable;
}
/** {@inheritDoc} */
public void setExternalizable(boolean value)
{
externalizable = value;
}
/** {@inheritDoc} */
public boolean isExternalizable(Object instance)
{
return instance instanceof Externalizable;
}
/** {@inheritDoc} */
public SerializationContext getSerializationContext()
{
return context == null? SerializationContext.getSerializationContext() : context;
}
/** {@inheritDoc} */
public void setSerializationContext(SerializationContext value)
{
context = value;
}
/** {@inheritDoc} */
public void setIncludeReadOnly(boolean value)
{
includeReadOnly = value;
}
/** {@inheritDoc} */
public boolean getIncludeReadOnly()
{
if (includeReadOnly)
{
return true;
}
return getSerializationContext().includeReadOnly;
}
/** {@inheritDoc} */
public SerializationDescriptor getDescriptor()
{
return descriptor;
}
/** {@inheritDoc} */
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.
* @param instance current instance
* @return Object the instance after complete serialization
*/
public Object instanceComplete(Object instance)
{
return instance;
}
/**
* Returns the instance to serialize in place of the supplied instance.
* @param instance the instance to serialize
* @return Object the instance
*/
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 + "]";
return "[Proxy(proxyClass=" + getClass() + " descriptor=" + descriptor + "]";
}
protected void setCloneFieldsFrom(AbstractProxy source)
{
setDescriptor(source.getDescriptor());
setDefaultInstance(source.getDefaultInstance());
context = source.context;
includeReadOnly = source.includeReadOnly;
}
}