| /** |
| * 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 |
| * <p/> |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * <p/> |
| * 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.yoko.rmi.impl; |
| |
| import static java.util.Arrays.asList; |
| import static java.util.Collections.unmodifiableSet; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.DataOutputStream; |
| import java.io.Externalizable; |
| import java.io.IOException; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectOutputStream; |
| import java.io.ObjectStreamClass; |
| import java.io.ObjectStreamField; |
| import java.io.PrintWriter; |
| import java.io.Serializable; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Modifier; |
| import java.security.AccessController; |
| import java.security.DigestOutputStream; |
| import java.security.MessageDigest; |
| import java.security.PrivilegedAction; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| import org.apache.yoko.rmi.util.StringUtil; |
| import org.omg.CORBA.AttributeDescription; |
| import org.omg.CORBA.Initializer; |
| import org.omg.CORBA.MARSHAL; |
| import org.omg.CORBA.ORB; |
| import org.omg.CORBA.OperationDescription; |
| import org.omg.CORBA.TypeCode; |
| import org.omg.CORBA.VM_NONE; |
| import org.omg.CORBA.ValueMember; |
| import org.omg.CORBA.ValueDefPackage.FullValueDescription; |
| import org.omg.CORBA.portable.InputStream; |
| import org.omg.CORBA.portable.OutputStream; |
| import org.omg.CORBA.portable.UnknownException; |
| import org.omg.SendingContext.CodeBase; |
| import org.omg.SendingContext.CodeBaseHelper; |
| import org.omg.SendingContext.RunTime; |
| |
| import sun.reflect.ReflectionFactory; |
| |
| class ValueDescriptor extends TypeDescriptor { |
| static final Logger logger = Logger.getLogger(ValueDescriptor.class.getName()); |
| |
| private boolean _is_externalizable; |
| |
| private boolean _is_serializable; |
| |
| private Method _write_replace_method; |
| |
| private Method _read_resolve_method; |
| |
| private Constructor _constructor; |
| |
| private Method _write_object_method; |
| |
| private Method _read_object_method; |
| |
| private Field _serial_version_uid_field; |
| |
| protected ValueDescriptor _super_descriptor; |
| |
| protected FieldDescriptor[] _fields; |
| |
| private ObjectDeserializer _object_deserializer; |
| |
| private boolean _is_immutable_value; |
| |
| private boolean _is_rmi_stub; |
| |
| private String _custom_repid; |
| |
| private static final Set<? extends Class<? extends Serializable>> _immutable_value_classes = unmodifiableSet(new HashSet<>(asList(Integer.class, |
| Character.class, Boolean.class, Byte.class, Long.class, Float.class, Double.class, Short.class))); |
| |
| private long _hash_code; |
| |
| ValueDescriptor(Class type, TypeRepository repository) { |
| super(type, repository); |
| } |
| |
| protected boolean isEnum() { return false; } |
| |
| @Override |
| protected String genRepId() { |
| return String.format("RMI:%s:%016X:%016X", StringUtil.convertToValidIDLNames(_java_class.getName()), |
| _hash_code, getSerialVersionUID()); |
| } |
| |
| private String genCustomRepId() { |
| return String.format("RMI:org.omg.custom.%s", getRepositoryID().substring(4)); |
| } |
| |
| public final String getCustomRepositoryID() { |
| if (_custom_repid == null) _custom_repid = genCustomRepId(); |
| return _custom_repid; |
| } |
| |
| protected long getSerialVersionUID() { |
| if (_serial_version_uid_field != null) { |
| |
| try { |
| return _serial_version_uid_field.getLong(null); |
| } catch (IllegalAccessException ex) { |
| // skip // |
| } |
| } |
| ObjectStreamClass serialForm = ObjectStreamClass.lookup(_java_class); |
| |
| return (serialForm != null) ? serialForm.getSerialVersionUID() : 0L; |
| } |
| |
| public void init() { |
| try { |
| init0(); |
| super.init(); |
| |
| if (_fields == null) { |
| throw new RuntimeException("fields==null after init!"); |
| } |
| |
| } catch (RuntimeException | Error ex) { |
| logger.log(Level.FINE, "runtime error in ValueDescriptor.init " + ex.getMessage(), ex); |
| } |
| } |
| |
| private void init0() { |
| final Class<?> type = _java_class; |
| final Class<?> superClass = type.getSuperclass(); |
| |
| _is_rmi_stub = RMIStub.class.isAssignableFrom(type); |
| _is_externalizable = Externalizable.class.isAssignableFrom(type); |
| _is_serializable = Serializable.class.isAssignableFrom(type); |
| |
| _is_immutable_value = _immutable_value_classes.contains(type); |
| |
| if ((superClass != null) && (superClass != Object.class)) { |
| TypeDescriptor superDesc = repo.getDescriptor(superClass); |
| |
| if (superDesc instanceof ValueDescriptor) { |
| _super_descriptor = (ValueDescriptor) superDesc; |
| } |
| |
| } |
| |
| AccessController.doPrivileged(new PrivilegedAction() { |
| public Object run() { |
| |
| for (Class<?> curr = type; curr != null; curr = curr.getSuperclass()) { |
| // |
| // get writeReplace, if any |
| // |
| try { |
| _write_replace_method = curr.getDeclaredMethod("writeReplace"); |
| _write_replace_method.setAccessible(true); |
| |
| break; |
| } catch (NoSuchMethodException ignored) { |
| } |
| } |
| |
| // |
| // Get readResolve, if present |
| // |
| try { |
| _read_resolve_method = type.getDeclaredMethod("readResolve"); |
| _read_resolve_method.setAccessible(true); |
| |
| } catch (NoSuchMethodException ignored) { |
| } |
| |
| // |
| // get readObject |
| // |
| try { |
| _read_object_method = type.getDeclaredMethod("readObject", ObjectInputStream.class); |
| _read_object_method.setAccessible(true); |
| } catch (NoSuchMethodException ignored) { |
| } |
| |
| // |
| // get readObject |
| // |
| try { |
| _write_object_method = type.getDeclaredMethod("writeObject", ObjectOutputStream.class); |
| _write_object_method.setAccessible(true); |
| } catch (NoSuchMethodException ignored) { |
| } |
| |
| // |
| // validate readObject |
| // |
| if ((_write_object_method == null) || !Modifier.isPrivate(_write_object_method.getModifiers()) |
| || Modifier.isStatic(_write_object_method.getModifiers()) || (_write_object_method.getDeclaringClass() != _java_class)) { |
| |
| _write_object_method = null; |
| |
| } |
| |
| // |
| // validate writeObject |
| // |
| if ((_read_object_method == null) || !Modifier.isPrivate(_read_object_method.getModifiers()) |
| || Modifier.isStatic(_read_object_method.getModifiers())) { |
| |
| _read_object_method = null; |
| } |
| |
| // |
| // get serialVersionUID field |
| // |
| try { |
| _serial_version_uid_field = type.getDeclaredField("serialVersionUID"); |
| if (Modifier.isStatic(_serial_version_uid_field.getModifiers())) { |
| _serial_version_uid_field.setAccessible(true); |
| } else { |
| _serial_version_uid_field = null; |
| } |
| } catch (NoSuchFieldException ex) { |
| // skip // |
| } |
| |
| // |
| // get serialPersistentFields field |
| // |
| ObjectStreamField[] serial_persistent_fields = null; |
| try { |
| Field _serial_persistent_fields_field = type.getDeclaredField("serialPersistentFields"); |
| _serial_persistent_fields_field.setAccessible(true); |
| |
| serial_persistent_fields = (ObjectStreamField[]) _serial_persistent_fields_field.get(null); |
| |
| } catch (IllegalAccessException | NoSuchFieldException ex) { |
| // skip // |
| } |
| |
| if (_is_externalizable) { |
| // |
| // Get the default constructor |
| // |
| try { |
| _constructor = type.getDeclaredConstructor(); |
| _constructor.setAccessible(true); |
| |
| } catch (NoSuchMethodException ex) { |
| logger.log(Level.WARNING, "Class " + type.getName() + " is not properly externalizable. " |
| + "It has not default constructor.", ex); |
| } |
| |
| } else if (_is_serializable && !type.isInterface()) { |
| |
| Class<?> initClass = type; |
| |
| while ((initClass != null) && Serializable.class.isAssignableFrom(initClass)) { |
| initClass = initClass.getSuperclass(); |
| } |
| |
| if (initClass == null) { |
| logger.warning("Class " + type.getName() + " is not properly serializable. " + "It has no non-serializable super-class"); |
| } else { |
| try { |
| Constructor init_cons = initClass.getDeclaredConstructor(); |
| |
| if (Modifier.isPublic(init_cons.getModifiers()) || Modifier.isProtected(init_cons.getModifiers())) { |
| // do nothing - it's accessible |
| |
| } else if (!samePackage(type, initClass)) { |
| logger.warning("Class " + type.getName() + " is not properly serializable. " |
| + "The default constructor of its first " + "non-serializable super-class (" + initClass.getName() |
| + ") is not accessible."); |
| } |
| |
| _constructor = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(type, init_cons); |
| |
| if (_constructor == null) { |
| logger.warning("Unable to get constructor for serialization for class " + java_name); |
| } else { |
| _constructor.setAccessible(true); |
| } |
| |
| } catch (NoSuchMethodException ex) { |
| logger.log(Level.WARNING, "Class " + type.getName() + " is not properly serializable. " |
| + "First non-serializable super-class (" + initClass.getName() + ") has no default constructor.", ex); |
| } |
| } |
| } |
| |
| if (serial_persistent_fields == null) { |
| |
| // |
| // Get relevant field definitions |
| // |
| |
| Field[] ff = type.getDeclaredFields(); |
| |
| if ((ff == null) || (ff.length == 0)) { |
| _fields = new FieldDescriptor[0]; |
| |
| } else { |
| List<FieldDescriptor> flist = new ArrayList<>(); |
| |
| for (Field f : ff) { |
| int mod = f.getModifiers(); |
| if (Modifier.isStatic(mod) || Modifier.isTransient(mod)) { |
| continue; |
| } |
| |
| f.setAccessible(true); |
| FieldDescriptor fd = FieldDescriptor.get(f, repo); |
| flist.add(fd); |
| } |
| |
| _fields = new FieldDescriptor[flist.size()]; |
| _fields = flist.toArray(_fields); |
| |
| // |
| // sort the fields |
| // |
| Arrays.sort(_fields); |
| } |
| |
| } else { |
| _fields = new FieldDescriptor[serial_persistent_fields.length]; |
| |
| for (int i = 0; i < serial_persistent_fields.length; i++) { |
| ObjectStreamField f = serial_persistent_fields[i]; |
| |
| FieldDescriptor fd = null; |
| |
| try { |
| Field rf = type.getField(f.getName()); |
| rf.setAccessible(true); |
| |
| if (rf.getType() == f.getType()) { |
| fd = FieldDescriptor.get(rf,repo); |
| } |
| } catch (SecurityException | NoSuchFieldException ex) { |
| } |
| |
| if (fd == null) { |
| fd = FieldDescriptor.get(type, f, repo); |
| } |
| _fields[i] = fd; |
| } |
| |
| // |
| // sort the fields (this is also the case for serial |
| // persistent |
| // fields, because they have to map to some foreign |
| // IDL). |
| // |
| Arrays.sort(_fields); |
| } |
| |
| // |
| // Compute the structural hash |
| // |
| _hash_code = computeHashCode(); |
| |
| // |
| // Setup the default deserializer |
| // |
| _object_deserializer = new ObjectDeserializer(ValueDescriptor.this); |
| |
| return null; |
| } |
| |
| }); |
| } |
| |
| private boolean samePackage(Class type, Class initClass) { |
| String pkg1 = getPackageName(type); |
| String pkg2 = getPackageName(initClass); |
| |
| return pkg1.equals(pkg2); |
| } |
| |
| private String getPackageName(Class type) { |
| String name = type.getName(); |
| int idx = name.lastIndexOf('.'); |
| return (idx == -1) ? "" : name.substring(0, idx); |
| } |
| |
| /** Read an instance of this value from a CDR stream */ |
| public Object read(org.omg.CORBA.portable.InputStream in) { |
| return ((org.omg.CORBA_2_3.portable.InputStream) in).read_value(); |
| } |
| |
| /** Write an instance of this value to a CDR stream */ |
| public void write(OutputStream out, Object value) { |
| ((org.omg.CORBA_2_3.portable.OutputStream) out).write_value((Serializable) value); |
| } |
| |
| public boolean isCustomMarshalled() { |
| return (_is_externalizable || (_write_object_method != null)); |
| } |
| |
| public boolean isChunked() { |
| if (isCustomMarshalled()) return true; |
| return (_super_descriptor != null) && _super_descriptor.isChunked(); |
| } |
| |
| public Serializable writeReplace(Serializable val) { |
| if (_write_replace_method != null) { |
| try { |
| return (Serializable) _write_replace_method.invoke(val); |
| |
| } catch (IllegalAccessException ex) { |
| throw (MARSHAL) new MARSHAL("cannot call " + _write_replace_method).initCause(ex); |
| |
| } catch (IllegalArgumentException ex) { |
| throw (MARSHAL) new MARSHAL(ex.getMessage()).initCause(ex); |
| |
| } catch (InvocationTargetException ex) { |
| throw (UnknownException) new UnknownException(ex.getTargetException()).initCause(ex.getTargetException()); |
| } |
| |
| } |
| |
| return val; |
| } |
| |
| public Serializable readResolve(Serializable val) { |
| if (_read_resolve_method != null) { |
| try { |
| return (Serializable) _read_resolve_method.invoke(val); |
| |
| } catch (IllegalAccessException ex) { |
| throw (MARSHAL) new MARSHAL("cannot call " + _read_resolve_method).initCause(ex); |
| |
| } catch (IllegalArgumentException ex) { |
| throw (MARSHAL) new MARSHAL(ex.getMessage()).initCause(ex); |
| |
| } catch (InvocationTargetException ex) { |
| throw (UnknownException) new UnknownException(ex.getTargetException()).initCause(ex.getTargetException()); |
| } |
| |
| } |
| |
| return val; |
| } |
| |
| public void writeValue(final OutputStream out, final Serializable value) { |
| try { |
| |
| ObjectWriter writer = (ObjectWriter) AccessController.doPrivileged(new PrivilegedAction() { |
| public Object run() { |
| try { |
| return new CorbaObjectWriter(out, value); |
| } catch (IOException ex) { |
| throw (MARSHAL) new MARSHAL(ex.getMessage()).initCause(ex); |
| } |
| } |
| }); |
| |
| writeValue(writer, value); |
| |
| } catch (IOException ex) { |
| throw (MARSHAL) new MARSHAL(ex.getMessage()).initCause(ex); |
| } |
| } |
| |
| protected void defaultWriteValue(ObjectWriter writer, Serializable val) throws IOException { |
| logger.finer("writing fields for " + _java_class); |
| FieldDescriptor[] fields = _fields; |
| |
| if (fields == null) { |
| return; |
| } |
| |
| for (int i = 0; i < fields.length; i++) { |
| logger.finer("writing field " + _fields[i].java_name); |
| |
| fields[i].write(writer, val); |
| } |
| } |
| |
| protected void writeValue(ObjectWriter writer, Serializable val) throws IOException { |
| |
| if (_is_externalizable) { |
| writer.invokeWriteExternal((Externalizable) val); |
| return; |
| } |
| |
| if (_super_descriptor != null) { |
| _super_descriptor.writeValue(writer, val); |
| } |
| |
| if (_write_object_method != null) { |
| |
| try { |
| writer.invokeWriteObject(this, val, _write_object_method); |
| } catch (IllegalAccessException | IllegalArgumentException ex) { |
| throw (MARSHAL) new MARSHAL(ex.getMessage()).initCause(ex); |
| } catch (InvocationTargetException ex) { |
| throw (UnknownException) new UnknownException(ex.getTargetException()).initCause(ex.getTargetException()); |
| } |
| |
| } else { |
| defaultWriteValue(writer, val); |
| } |
| |
| } |
| |
| private Serializable createBlankInstance() { |
| if (_constructor != null) { |
| |
| try { |
| return (Serializable) _constructor.newInstance(); |
| |
| } catch (IllegalAccessException ex) { |
| throw (MARSHAL) new MARSHAL("cannot call " + _constructor).initCause(ex); |
| |
| } catch (IllegalArgumentException | InstantiationException ex) { |
| throw (MARSHAL) new MARSHAL(ex.getMessage()).initCause(ex); |
| |
| } catch (InvocationTargetException ex) { |
| throw (UnknownException) new UnknownException(ex.getTargetException()).initCause(ex.getTargetException()); |
| |
| } catch (NullPointerException ex) { |
| logger.log(Level.WARNING, "unable to create instance of " + _java_class.getName(), ex); |
| logger.warning("constructor => " + _constructor); |
| |
| throw ex; |
| } |
| |
| } else { |
| return null; |
| } |
| } |
| |
| public Serializable readValue(final InputStream in, final Map<Integer, Object> offsetMap, final Integer offset) { |
| final Serializable value = createBlankInstance(); |
| |
| offsetMap.put(offset, value); |
| |
| try { |
| ObjectReader reader = (ObjectReader) AccessController.doPrivileged(new PrivilegedAction() { |
| public Object run() { |
| try { |
| return new CorbaObjectReader(in, offsetMap, value); |
| } catch (IOException ex) { |
| throw (MARSHAL) new MARSHAL(ex.getMessage()).initCause(ex); |
| } |
| } |
| }); |
| |
| readValue(reader, value); |
| |
| final Serializable resolved = readResolve(value); |
| if (value != resolved) { |
| offsetMap.put(offset, resolved); |
| } |
| return resolved; |
| |
| } catch (IOException ex) { |
| throw (MARSHAL) new MARSHAL(ex.getMessage()).initCause(ex); |
| } |
| |
| } |
| |
| void print(PrintWriter pw, Map<Object, Integer> recurse, Object val) { |
| if (val == null) { |
| pw.print("null"); |
| } |
| |
| Integer old = recurse.get(val); |
| if (old != null) { |
| pw.print("^" + old); |
| } else { |
| int key = System.identityHashCode(val); |
| recurse.put(val, key); |
| |
| pw.println(_java_class.getName() + "@" + Integer.toHexString(key) + "["); |
| |
| printFields(pw, recurse, val); |
| |
| pw.println("]"); |
| } |
| } |
| |
| void printFields(PrintWriter pw, Map recurse, Object val) { |
| pw.print("(" + getClass().getName() + ")"); |
| |
| if (_super_descriptor != null) { |
| _super_descriptor.printFields(pw, recurse, val); |
| } |
| |
| if (_fields == null) |
| return; |
| |
| for (int i = 0; i < _fields.length; i++) { |
| if (i != 0) { |
| pw.print("; "); |
| } |
| |
| _fields[i].print(pw, recurse, val); |
| } |
| |
| } |
| |
| protected void defaultReadValue(ObjectReader reader, Serializable value) throws IOException { |
| // System.out.println ("defaultReadValue "+getJavaClass()); |
| |
| if (_fields == null) { |
| // System.out.println ("fields == null for "+getJavaClass ()); |
| return; |
| } |
| |
| logger.fine("reading fields for " + _java_class.getName()); |
| |
| for (FieldDescriptor _field : _fields) { |
| |
| logger.fine("reading field " + _field.java_name + " of type " + _field.getType().getName() + " using " + _field.getClass().getName()); |
| |
| try { |
| _field.read(reader, value); |
| } catch (MARSHAL ex) { |
| if (ex.getMessage() != null) |
| throw ex; |
| |
| String msg = String.format("%s, while reading %s.%s", ex, java_name, _field.java_name); |
| throw (MARSHAL) new MARSHAL(msg, ex.minor, ex.completed).initCause(ex); |
| } |
| } |
| } |
| |
| Map readFields(ObjectReader reader) throws IOException { |
| if ((_fields == null) || (_fields.length == 0)) { |
| return Collections.EMPTY_MAP; |
| } |
| |
| logger.finer("reading fields for " + _java_class.getName()); |
| |
| Map map = new HashMap(); |
| |
| for (FieldDescriptor _field : _fields) { |
| |
| logger.finer("reading field " + _field.java_name); |
| |
| _field.readFieldIntoMap(reader, map); |
| } |
| |
| return map; |
| } |
| |
| void writeFields(ObjectWriter writer, Map fieldMap) throws IOException { |
| if ((_fields == null) || (_fields.length == 0)) { |
| return; |
| } |
| |
| logger.finer("writing fields for " + _java_class.getName()); |
| |
| for (FieldDescriptor _field : _fields) { |
| |
| logger.finer("writing field " + _field.java_name); |
| |
| _field.writeFieldFromMap(writer, fieldMap); |
| } |
| |
| } |
| |
| /** |
| * This methods reads the fields of a single class slice. |
| */ |
| protected void readValue(ObjectReader reader, Serializable value) throws IOException { |
| if (_is_externalizable) { |
| try { |
| reader.readExternal((Externalizable) value); |
| } catch (ClassNotFoundException e) { |
| throw new IOException("cannot instantiate class", e); |
| } |
| return; |
| } |
| |
| if (_super_descriptor != null) { |
| _super_descriptor.readValue(reader, value); |
| } |
| |
| // check whether the class (not its ancestors) does any custom marshalling |
| if (_write_object_method != null) { |
| // read custom marshalling value header |
| byte cmsfVersion = reader.readByte(); // custom marshal stream format version |
| boolean dwoCalled = reader.readBoolean(); // was defaultWriteObject() called? |
| logger.log(Level.FINE, "Reading value in streamFormatVersion=" + cmsfVersion + " defaultWriteObject=" + dwoCalled); |
| |
| if (cmsfVersion == 2) { |
| // use a wrapped reader to open the secondary custom valuetype |
| ObjectReader wrapper = new CustomMarshaledObjectReader(reader); |
| readSerializable(_read_object_method == null ? reader : wrapper, value); |
| // invoke close to skip to the end of the secondary custom valuetype |
| wrapper.close(); |
| return; |
| } |
| } |
| |
| readSerializable(reader, value); |
| |
| } |
| |
| private void readSerializable(ObjectReader reader, Serializable value) throws IOException { |
| if (_read_object_method != null) { |
| try { |
| reader.setCurrentValueDescriptor(this); |
| _read_object_method.invoke(value, reader); |
| reader.setCurrentValueDescriptor(null); |
| |
| } catch (IllegalAccessException | IllegalArgumentException ex) { |
| throw (MARSHAL) new MARSHAL(ex.getMessage()).initCause(ex); |
| } catch (InvocationTargetException ex) { |
| throw (UnknownException) new UnknownException(ex.getTargetException()).initCause(ex.getTargetException()); |
| } |
| |
| } else { |
| defaultReadValue(reader, value); |
| } |
| } |
| |
| protected long computeHashCode() { |
| Class type = _java_class; |
| |
| if (_is_externalizable) { |
| return 1L; |
| } |
| |
| if (!Serializable.class.isAssignableFrom(type)) { |
| return 0; |
| } |
| |
| long hash = 0L; |
| try { |
| ByteArrayOutputStream barr = new ByteArrayOutputStream(512); |
| MessageDigest md = MessageDigest.getInstance("SHA"); |
| DigestOutputStream digestout = new DigestOutputStream(barr, md); |
| DataOutputStream out = new DataOutputStream(digestout); |
| |
| Class superType = type.getSuperclass(); |
| if (superType != null) { |
| TypeDescriptor desc = repo.getDescriptor(superType); |
| out.writeLong(desc.getHashCode()); |
| } |
| |
| if (_write_object_method == null) |
| out.writeInt(1); |
| else |
| out.writeInt(2); |
| |
| FieldDescriptor[] fds = new FieldDescriptor[_fields.length]; |
| System.arraycopy(_fields, 0, fds, 0, _fields.length); |
| |
| if (fds.length > 1) |
| Arrays.sort(fds, compareByName); |
| |
| for (FieldDescriptor f : fds) { |
| out.writeUTF(f.java_name); |
| out.writeUTF(makeSignature(f.getType())); |
| } |
| |
| /* |
| * Field[] fields = type.getDeclaredFields (); if (fields.length > |
| * 1) java.util.Arrays.sort (fields, compareByName); for(int i = 0; |
| * i < fields.length; i++) { Field f = fields[i]; int mod = |
| * f.getModifiers (); if (!Modifier.isTransient(mod) && |
| * !Modifier.isStatic (mod)) { out.writeUTF(f.getName()); |
| * out.writeUTF( makeSignature (f.getType ())); } } |
| */ |
| |
| out.flush(); |
| |
| byte[] data = md.digest(); |
| int end = Math.min(8, data.length); |
| for (int j = 0; j < end; j++) { |
| hash += (long) (data[j] & 0xff) << (j * 8); |
| } |
| } catch (Exception ex) { |
| throw new RuntimeException("cannot compute RMI hash code", ex); |
| } |
| |
| return hash; |
| } |
| |
| private static final Comparator compareByName = new Comparator() { |
| public int compare(Object f1, Object f2) { |
| String n1 = ((FieldDescriptor) f1).java_name; |
| String n2 = ((FieldDescriptor) f2).java_name; |
| return n1.compareTo(n2); |
| } |
| }; |
| |
| long getHashCode() { |
| return _hash_code; |
| } |
| |
| protected ValueMember[] _value_members = null; |
| |
| private ValueMember[] getValueMembers() { |
| getTypeCode(); // ensure recursion through typecode for non-array types |
| |
| if (_value_members == null) { |
| _value_members = new ValueMember[_fields.length]; |
| for (int i = 0; i < _fields.length; i++) { |
| _value_members[i] = _fields[i].getValueMember(repo); |
| } |
| } |
| |
| return _value_members; |
| } |
| |
| TypeCode getTypeCode() { |
| if (_type_code != null) |
| return _type_code; |
| |
| ORB orb = ORB.init(); |
| _type_code = orb.create_recursive_tc(getRepositoryID()); |
| |
| TypeCode _base = ((_super_descriptor == null) ? null : _super_descriptor.getTypeCode()); |
| |
| Class javaClass = _java_class; |
| if (javaClass.isArray()) { |
| TypeDescriptor desc = repo.getDescriptor(javaClass.getComponentType()); |
| _type_code = desc.getTypeCode(); |
| _type_code = orb.create_sequence_tc(0, _type_code); |
| _type_code = orb.create_value_box_tc(getRepositoryID(), "Sequence", _type_code); |
| } else { |
| _type_code = orb.create_value_tc(getRepositoryID(), javaClass.getSimpleName(), VM_NONE.value, _base, getValueMembers()); |
| } |
| |
| return _type_code; |
| } |
| |
| private static final OperationDescription[] ZERO_OPERATIONS = {}; |
| private static final AttributeDescription[] ZERO_ATTRIBUTES = {}; |
| private static final Initializer[] ZERO_INITIALIZERS = {}; |
| private static final String[] ZERO_STRINGS = {}; |
| |
| FullValueDescription getFullValueDescription() { |
| FullValueDescription fvd = new FullValueDescription(); |
| fvd.name = _java_class.getName(); |
| fvd.id = getRepositoryID(); |
| fvd.is_abstract = false; |
| fvd.is_custom = isCustomMarshalled(); |
| fvd.defined_in = ""; |
| fvd.version = "1.0"; |
| fvd.operations = ZERO_OPERATIONS; |
| fvd.attributes = ZERO_ATTRIBUTES; |
| fvd.members = getValueMembers(); |
| fvd.initializers = ZERO_INITIALIZERS; |
| fvd.supported_interfaces = ZERO_STRINGS; |
| fvd.abstract_base_values = ZERO_STRINGS; |
| fvd.is_truncatable = false; |
| fvd.base_value = ((_super_descriptor == null) ? "" : _super_descriptor.getRepositoryID()); |
| fvd.type = getTypeCode(); |
| return fvd; |
| } |
| |
| class ObjectDeserializer { |
| |
| ObjectDeserializer super_descriptor; |
| |
| String repository_id; |
| |
| final FieldDescriptor[] fields; |
| |
| ObjectDeserializer(ValueDescriptor desc) { |
| fields = desc._fields; |
| repository_id = desc.getRepositoryID(); |
| |
| if (desc._super_descriptor != null) { |
| super_descriptor = desc._super_descriptor._object_deserializer; |
| } |
| } |
| |
| ObjectDeserializer(FullValueDescription desc, RunTime runtime) throws IOException { |
| Class myClass = _java_class; |
| ValueMember[] members = desc.members; |
| fields = new FieldDescriptor[members.length]; |
| for (int i = 0; i < members.length; i++) { |
| Class type = getClassFromTypeCode(members[i].type); |
| fields[i] = FieldDescriptor.get(myClass, type, members[i].name, null, repo); |
| } |
| |
| if (!"".equals(desc.base_value)) { |
| Class clz = ValueHandlerImpl.getClassFromRepositoryID(desc.base_value); |
| TypeDescriptor tdesc = repo.getDescriptor(clz); |
| |
| if ((tdesc instanceof ValueDescriptor)) { |
| super_descriptor = ((ValueDescriptor) tdesc).getObjectDeserializer(desc.base_value, runtime); |
| } |
| } |
| } |
| } |
| |
| private ObjectDeserializer getObjectDeserializer(String repositoryID, RunTime runtime) throws IOException { |
| if (repositoryID.equals(getRepositoryID())) { |
| return _object_deserializer; |
| } |
| |
| CodeBase codebase = CodeBaseHelper.narrow(runtime); |
| if (codebase == null) { |
| throw new IOException("cannot narrow RunTime -> CodeBase"); |
| } |
| |
| FullValueDescription desc = codebase.meta(repositoryID); |
| |
| return new ObjectDeserializer(desc, codebase); |
| } |
| |
| private static Class getClassFromTypeCode(TypeCode tc) { |
| return null; |
| } |
| |
| public boolean copyWithinState() { |
| return !(_is_immutable_value | _is_rmi_stub); |
| } |
| |
| Object copyObject(Object orig, CopyState state) { |
| |
| if (_is_immutable_value || _is_rmi_stub) { |
| return orig; |
| } |
| |
| Serializable oorig = (Serializable) orig; |
| |
| logger.finer("copying " + orig); |
| |
| oorig = writeReplace(oorig); |
| |
| ValueDescriptor wdesc; |
| if (oorig == orig) { |
| wdesc = this; |
| } else { |
| wdesc = (ValueDescriptor) repo.getDescriptor(oorig.getClass()); |
| |
| logger.finer("writeReplace -> " + _java_class.getName()); |
| } |
| |
| return wdesc.copyObject2(oorig, state); |
| } |
| |
| /** |
| * this is called after write-replace on the type descriptor of the correct |
| * type for writing |
| */ |
| private Serializable copyObject2(Serializable oorig, CopyState state) { |
| |
| // create instance of copied object, and register |
| Serializable copy = createBlankInstance(); |
| state.put(oorig, copy); |
| |
| // write original object |
| ObjectWriter writer = writeObject(oorig, state); |
| |
| // read into copy |
| return readObject(writer, copy); |
| } |
| |
| private ObjectWriter writeObject(Serializable oorig, CopyState state) { |
| try { |
| ObjectWriter writer = state.createObjectWriter(oorig); |
| writeValue(writer, oorig); |
| return writer; |
| } catch (IOException ex) { |
| String msg = String.format("%s writing %s", ex, _java_class.getName()); |
| throw (MARSHAL) new MARSHAL(msg).initCause(ex); |
| } |
| } |
| |
| private Serializable readObject(ObjectWriter writer, Serializable copy) { |
| try { |
| ObjectReader reader = writer.getObjectReader(copy); |
| readValue(reader, copy); |
| return readResolve(copy); |
| } catch (IOException ex) { |
| String msg = String.format("%s reading instance of %s", ex, _java_class.getName()); |
| throw (MARSHAL) new MARSHAL(msg).initCause(ex); |
| } |
| } |
| |
| void writeMarshalValue(PrintWriter pw, String outName, String paramName) { |
| pw.print(outName); |
| pw.print('.'); |
| pw.print("write_value"); |
| |
| // this ValueDescriptor could represent an Abstract Value, |
| // in which case we need to cast the first argument. |
| // We'll just always do that, because most of the time |
| // HotSpot will remove this cast anyway. |
| |
| pw.print("((java.io.Serializable)"); |
| |
| pw.print(paramName); |
| pw.print(','); |
| MethodDescriptor.writeJavaType(pw, _java_class); |
| pw.print(".class)"); |
| } |
| |
| void writeUnmarshalValue(PrintWriter pw, String inName) { |
| pw.print(inName); |
| pw.print('.'); |
| pw.print("read_value"); |
| pw.print('('); |
| MethodDescriptor.writeJavaType(pw, _java_class); |
| pw.print(".class)"); |
| } |
| |
| void addDependencies(Set<Class<?>> classes) { |
| Class c = _java_class; |
| |
| if ((c == Object.class) || classes.contains(c)) |
| return; |
| |
| classes.add(c); |
| |
| if (c.getSuperclass() != null) { |
| TypeDescriptor desc = repo.getDescriptor(c.getSuperclass()); |
| desc.addDependencies(classes); |
| } |
| |
| Class[] ifaces = c.getInterfaces(); |
| for (Class iface : ifaces) { |
| TypeDescriptor desc = repo.getDescriptor(iface); |
| desc.addDependencies(classes); |
| } |
| |
| if (_fields != null) { |
| for (FieldDescriptor _field : _fields) { |
| if (_field.isPrimitive()) |
| continue; |
| |
| TypeDescriptor desc = repo.getDescriptor(_field.type); |
| desc.addDependencies(classes); |
| } |
| } |
| } |
| } |