/*
* 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 org.apache.tuscany.sca.binding.ejb.java2idl;
import java.io.Externalizable;
import java.io.ObjectStreamField;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.rmi.Remote;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.SortedSet;
import java.util.TreeSet;
import org.osoa.sca.ServiceRuntimeException;
/**
* Value Type.
*/
public class ValueType extends ContainerType {
private static WorkCache cache = new WorkCache(ValueType.class);
/**
* Type of our superclass, of null if our superclass is java.lang.Object.
*/
ValueType superType;
/**
* Flags that this is an abstract value.
*/
private boolean abstractValue = false;
/**
* Flags that this implements java.io.Externalizable
.
*/
private boolean externalizable = false;
/**
* Flags that this has a writeObject()
method.
*/
private boolean hasWriteObjectMethod = false;
/**
* The serialPersistentFields of the value, or null
* if the value does not have this field.
*/
private ObjectStreamField[] serialPersistentFields;
/**
* The value members of this value class.
*/
private ValueMemberType[] members;
public static ValueType getValueType(Class cls) {
return (ValueType)cache.getType(cls);
}
protected ValueType(Class cls) {
super(cls);
}
protected void parse() {
super.parse();
if (javaClass == String.class)
throw new IllegalArgumentException("Cannot parse java.lang.String here: It is a " + "special case."); // 1.3.5.11
if (javaClass == Class.class)
throw new IllegalArgumentException("Cannot parse java.lang.Class here: It is a " + "special case."); // 1.3.5.10
if (Remote.class.isAssignableFrom(javaClass))
throw new IDLViolationException("Value type " + javaClass.getName() + " cannot implement java.rmi.Remote.",
"1.2.4");
if (javaClass.getName().indexOf('$') != -1)
throw new ServiceRuntimeException(javaClass.getName() + " is not supported (proxy or inner classes).");
externalizable = Externalizable.class.isAssignableFrom(javaClass);
if (!externalizable) {
// Look for serialPersistentFields field.
Field spf = null;
try {
spf = javaClass.getField("serialPersistentFields");
} catch (NoSuchFieldException ex) {
// ignore
}
if (spf != null) { // Right modifiers?
int mods = spf.getModifiers();
if (!Modifier.isFinal(mods) || !Modifier.isStatic(mods) || !Modifier.isPrivate(mods))
spf = null; // wrong modifiers
}
if (spf != null) { // Right type?
Class type = spf.getType();
if (type.isArray()) {
type = type.getComponentType();
if (type != ObjectStreamField.class)
spf = null; // Array of wrong type
} else
spf = null; // Wrong type: Not an array
}
if (spf != null) {
// We have the serialPersistentFields field
// Get this constant
try {
serialPersistentFields = (ObjectStreamField[])spf.get(null);
} catch (IllegalAccessException ex) {
throw new RuntimeException("Unexpected IllegalException: " + ex.toString());
}
// Mark this in the fields array
for (int i = 0; i < fields.length; ++i) {
if (fields[i] == spf) {
f_flags[i] |= F_SPFFIELD;
break;
}
}
}
// Look for a writeObject Method
Method wo = null;
try {
wo = javaClass.getMethod("writeObject", new Class[] {java.io.OutputStream[].class});
} catch (NoSuchMethodException ex) {
// ignore
}
if (wo != null) { // Right return type?
if (wo.getReturnType() != Void.TYPE)
wo = null; // Wrong return type
}
if (wo != null) { // Right modifiers?
int mods = spf.getModifiers();
if (!Modifier.isPrivate(mods))
wo = null; // wrong modifiers
}
if (wo != null) { // Right arguments?
Class[] paramTypes = wo.getParameterTypes();
if (paramTypes.length != 1)
wo = null; // Bad number of parameters
else if (paramTypes[0] != java.io.OutputStream.class)
wo = null; // Bad parameter type
}
if (wo != null) {
// We have the writeObject() method.
hasWriteObjectMethod = true;
// Mark this in the methods array
for (int i = 0; i < methods.length; ++i) {
if (methods[i] == wo) {
m_flags[i] |= M_WRITEOBJECT;
break;
}
}
}
}
// Map all fields not flagged constant or serialPersistentField.
SortedSet m = new TreeSet(new ValueMemberComparator());
for (int i = 0; i < fields.length; ++i) {
if (f_flags[i] != 0)
continue; // flagged
int mods = fields[i].getModifiers();
if (Modifier.isStatic(mods) || Modifier.isTransient(mods))
continue; // don't map this
ValueMemberType vma =
new ValueMemberType(fields[i].getName(), fields[i].getType(), Modifier.isPublic(mods));
m.add(vma);
}
members = new ValueMemberType[m.size()];
members = (ValueMemberType[])m.toArray(members);
// Get superclass analysis
Class superClass = javaClass.getSuperclass();
if (superClass == java.lang.Object.class)
superClass = null;
if (superClass == null)
superType = null;
else {
superType = getValueType(superClass);
}
if (!Serializable.class.isAssignableFrom(javaClass))
abstractValue = true;
fixupCaseNames();
}
/**
* Returns the superclass analysis, or null if this inherits from
* java.lang.Object.
*/
public ValueType getSuperType() {
return superType;
}
/**
* Returns true if this value is abstract.
*/
public boolean isAbstractValue() {
return abstractValue;
}
/**
* Returns true if this value is custom.
*/
public boolean isCustom() {
return externalizable || hasWriteObjectMethod;
}
/**
* Returns true if this value implements java.io.Externalizable.
*/
public boolean isExternalizable() {
return externalizable;
}
/**
* Return the value members of this value class.
*/
public ValueMemberType[] getMembers() {
return (ValueMemberType[])members.clone();
}
/**
* Analyse attributes. This will fill in the attributes
* array. Here we override the implementation in ContainerType and create an
* empty array, because for valuetypes we don't want to parse IDL attributes
* or operations (as in "rmic -idl -noValueMethods").
*/
protected void parseAttributes() {
attributes = new AttributeType[0];
}
/**
* Return a list of all the entries contained here.
*
* @param entries The list of entries contained here. Entries in this list
* are subclasses of AbstractType
.
*/
protected ArrayList getContainedEntries() {
ArrayList ret = new ArrayList(constants.length + attributes.length + members.length);
for (int i = 0; i < constants.length; ++i)
ret.add(constants[i]);
for (int i = 0; i < attributes.length; ++i)
ret.add(attributes[i]);
for (int i = 0; i < members.length; ++i)
ret.add(members[i]);
return ret;
}
/**
* A Comparator
for the field ordering specified at the end
* of section 1.3.5.6.
*/
private static class ValueMemberComparator implements Comparator {
public int compare(Object o1, Object o2) {
if (o1 == o2)
return 0;
ValueMemberType m1 = (ValueMemberType)o1;
ValueMemberType m2 = (ValueMemberType)o2;
boolean p1 = m1.getJavaClass().isPrimitive();
boolean p2 = m2.getJavaClass().isPrimitive();
if (p1 && !p2)
return -1;
if (!p1 && p2)
return 1;
return m1.getJavaName().compareTo(m2.getJavaName());
}
}
}