blob: 06508da5b667c840c74a974b5a27922f63d84fe2 [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;
}
}