/** * Return an <code>Entry</code> object built out of this <code>EntryRep</code> This is used by the * client-side proxy to convert the <code>EntryRep</code> it gets from the space server into the * actual <code>Entry</code> object it represents. * * @throws UnusableEntryException One or more fields in the entry cannot be deserialized, or the * class for the entry type itself cannot be deserialized. */ Entry entry() throws UnusableEntryException { ObjectInputStream objIn = null; try { ArrayList badFields = null; ArrayList except = null; realClass = ClassLoading.loadClass(codebase, className, null, integrity, null); if (findHash(realClass, false).longValue() != hash) throw throwNewUnusableEntryException( new IncompatibleClassChangeError(realClass + " changed")); Entry entryObj = (Entry) realClass.newInstance(); Field[] fields = getFields(realClass); /* * Loop through the fields, ensuring no primitives and * checking for wildcards. */ int nvals = 0; // index into this.values[] for (int i = 0; i < fields.length; i++) { Throwable nested = null; try { if (!usableField(fields[i])) continue; final MarshalledInstance val = values[nvals++]; Object value = (val == null ? null : val.get(integrity)); fields[i].set(entryObj, value); } catch (Throwable e) { nested = e; } if (nested != null) { // some problem occurred if (badFields == null) { badFields = new ArrayList(fields.length); except = new ArrayList(fields.length); } badFields.add(fields[i].getName()); except.add(nested); } } /* See if any fields have vanished from the class, * because of the hashing this should never happen but * throwing an exception that provides more info * (instead of AssertionError) seems harmless. */ if (nvals < values.length) { throw throwNewUnusableEntryException( entryObj, // should this be null? null, // array of bad-field names new Throwable[] { // array of exceptions new IncompatibleClassChangeError( "A usable field has been removed from " + entryObj.getClass().getName() + " since this EntryRep was created") }); } // if there were any bad fields, throw the exception if (badFields != null) { String[] bf = (String[]) badFields.toArray(new String[badFields.size()]); Throwable[] ex = (Throwable[]) except.toArray(new Throwable[bf.length]); throw throwNewUnusableEntryException(entryObj, bf, ex); } // everything fine, return the entry return entryObj; } catch (InstantiationException e) { /* * If this happens outside a per-field deserialization then * this is a complete failure The per-field ones are caught * inside the per-field loop. */ throw throwNewUnusableEntryException(e); } catch (ClassNotFoundException e) { // see above throw throwNewUnusableEntryException( "Encountered a " + "ClassNotFoundException while unmarshalling " + className, e); } catch (IllegalAccessException e) { // see above throw throwNewUnusableEntryException(e); } catch (RuntimeException e) { // see above throw throwNewUnusableEntryException( "Encountered a " + "RuntimeException while unmarshalling " + className, e); } catch (MalformedURLException e) { // see above throw throwNewUnusableEntryException( "Malformed URL " + "associated with entry of type " + className, e); } catch (MarshalException e) { // because we call findHash() w/ false, should never happen throw new AssertionError(e); } }
/** * Create a serialized form of the entry. If <code>validate</code> is <code>true</code>, basic * sanity checks are done on the class to ensure that it meets the requirements to be an <code> * Entry</code>. <code>validate</code> is <code>false</code> only when creating the stand-in * object for "match any", which is never actually marshalled on the wire and so which doesn't * need to be "proper". */ private EntryRep(Entry entry, boolean validate) throws MarshalException { realClass = entry.getClass(); if (validate) ensureValidClass(realClass); className = realClass.getName(); codebase = RMIClassLoader.getClassAnnotation(realClass); /* * Build up the per-field and superclass information through * the reflection API. */ final Field[] fields = getFields(realClass); int numFields = fields.length; // collect the usable field values in vals[0..nvals-1] MarshalledInstance[] vals = new MarshalledInstance[numFields]; int nvals = 0; for (int fnum = 0; fnum < fields.length; fnum++) { final Field field = fields[fnum]; if (!usableField(field)) continue; final Object fieldValue; try { fieldValue = field.get(entry); } catch (IllegalAccessException e) { /* In general between using getFields() and * ensureValidClass this should never happen, however * there appear to be a few screw cases and * IllegalArgumentException seems appropriate. */ final IllegalArgumentException iae = new IllegalArgumentException("Couldn't access field " + field); iae.initCause(e); throw throwRuntime(iae); } if (fieldValue == null) { vals[nvals] = null; } else { try { vals[nvals] = new MarshalledInstance(fieldValue); } catch (IOException e) { throw throwNewMarshalException( "Can't marshal field " + field + " with value " + fieldValue, e); } } nvals++; } // copy the vals with the correct length this.values = new MarshalledInstance[nvals]; System.arraycopy(vals, 0, this.values, 0, nvals); try { hash = findHash(realClass, true).longValue(); } catch (UnusableEntryException e) { // Will never happen when we pass true to findHash throw new AssertionError(e); } // Loop through the supertypes, making a list of all superclasses. ArrayList sclasses = new ArrayList(); ArrayList shashes = new ArrayList(); for (Class c = realClass.getSuperclass(); c != Object.class; c = c.getSuperclass()) { try { sclasses.add(c.getName()); shashes.add(findHash(c, true)); } catch (ClassCastException cce) { break; // not Serializable } catch (UnusableEntryException e) { // Will never happen when we pass true to findHash throw new AssertionError(e); } } superclasses = (String[]) sclasses.toArray(new String[sclasses.size()]); hashes = new long[shashes.size()]; for (int i = 0; i < hashes.length; i++) { hashes[i] = ((Long) shashes.get(i)).longValue(); } }