diff src/org/dancres/blitz/mangler/MangledEntry.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children 27ca8522be85
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/dancres/blitz/mangler/MangledEntry.java	Sat Mar 21 11:00:06 2009 +0000
@@ -0,0 +1,265 @@
+package org.dancres.blitz.mangler;
+
+import java.io.*;
+
+import com.sun.jini.proxy.MarshalledWrapper;
+import net.jini.entry.AbstractEntry;
+
+/**
+   <p>Represents a packaged up Entry ready for unpacking or passing to the
+   server for matching.  We include null fields as well so as to ensure
+   we have a complete, ordered, list of fields which allows as to build
+   a composite hash to speed searching under some circumstances.</p>
+
+   <p>Integrity checking starts here.  If MangledEntry detects that integrity
+   checking was active when it was unpacked from the stream (see
+   <code>readObject()</code> in this class) it makes a note of the fact.
+   Later, this is interrogated by EntryMangler (see
+   <code>needsIntegrityCheck</code>) and handled accordingly.</p>
+
+   @todo Fix up disk usage on null template match - see NULL_TEMPLATE
+ */
+public class MangledEntry implements Externalizable, net.jini.core.entry.Entry {
+
+    static final long serialVersionUID = 462890915488647301L;
+
+    private String[] theParents;
+    private MangledField[] theFields;
+    private String theType;
+    private String theCodebase;
+    private boolean isWildcard;
+    private boolean isSnapshot;
+
+    /**
+     * Set to <code>true</code> in <code>readObject</code> method
+     * (called when we're deserialized).  When we unpack the contents using
+     * EntryMangler, we check this flag and perform integrity checks if
+     * required.
+     */
+    private transient boolean checkIntegrity = false;
+
+    /**
+     * As all entry instances are ultimately rooted at java.lang.Object we
+     * can simply search from java.lang.Object downwards when we receive
+     * a null-template query.  This will cause a little extra disk I/O but
+     * nevermind for now.
+     */
+    public static final MangledEntry NULL_TEMPLATE =
+        new MangledEntry("java.lang.Object", null, new MangledField[0],
+            new String[0], true);
+
+    public MangledEntry() {
+
+    }
+
+    MangledEntry(String aType, String aCodebase,
+                 MangledField[] aListOfFields, String[] aListOfParents,
+                 boolean doWildcard) {
+        this(aType, aCodebase, aListOfFields, aListOfParents,
+            doWildcard, false);
+    }
+
+    MangledEntry(String aType, String aCodebase,
+                 MangledField[] aListOfFields, String[] aListOfParents,
+                 boolean doWildcard, boolean doSnapshot) {
+        theType = aType;
+        theCodebase = aCodebase;
+        theFields = aListOfFields;
+        theParents = aListOfParents;
+        isWildcard = doWildcard;
+        isSnapshot = doSnapshot;
+    }
+
+    public void writeExternal(ObjectOutput objectOutput) throws IOException {
+        objectOutput.writeObject(theParents);
+        objectOutput.writeInt(theFields.length);
+        for (int i = 0; i < theFields.length; i++) {
+            objectOutput.writeInt(theFields[i].getContent().length);
+            objectOutput.writeInt(theFields[i].getAnnotations().length);
+            objectOutput.write(theFields[i].getContent());
+            objectOutput.write(theFields[i].getAnnotations());
+            objectOutput.writeUTF(theFields[i].getName());
+            objectOutput.writeInt(theFields[i].hashCode());
+        }
+
+        objectOutput.writeUTF(theType);
+        objectOutput.writeUTF((theCodebase == null) ? "" : theCodebase);
+        objectOutput.writeBoolean(isWildcard);
+        objectOutput.writeBoolean(isSnapshot);
+    }
+
+    public void readExternal(ObjectInput objectInput) throws IOException,
+        ClassNotFoundException {
+
+        theParents = (String[]) objectInput.readObject();
+        theFields = new MangledField[objectInput.readInt()];
+
+        for (int i = 0; i < theFields.length; i++) {
+            int myObjectSize = objectInput.readInt();
+            int myAnnotSize = objectInput.readInt();
+
+            byte[] myContent = new byte[myObjectSize];
+            byte[] myAnnot = new byte[myAnnotSize];
+
+            objectInput.readFully(myContent);
+            objectInput.readFully(myAnnot);
+
+            theFields[i] = new MangledField(objectInput.readUTF(),
+                myContent, myAnnot, objectInput.readInt());
+        }
+
+        theType = objectInput.readUTF();
+        String myCodebase = objectInput.readUTF();
+        theCodebase = (myCodebase.length() == 0) ? null : myCodebase;
+        isWildcard = objectInput.readBoolean();
+        isSnapshot = objectInput.readBoolean();
+    }
+
+    public int sizeOf() {
+        int myFieldTotal = 0;
+
+        for (int i = 0; i < theFields.length; i++) {
+            myFieldTotal += theFields[i].sizeOf();
+        }
+
+        int myParentsTotal = 0;
+
+        for (int i = 0; i < theParents.length; i++) {
+            myParentsTotal += theParents[i].length();
+        }
+
+        int myCodebaseLength = 0;
+
+        if (theCodebase != null)
+            myCodebaseLength = theCodebase.length();
+
+        return theType.length() + myCodebaseLength + 4 + myParentsTotal +
+            myFieldTotal;
+    }
+
+    /**
+     * In the case of a template, this indicates that none of it's fields
+     * have specific values so any match will do.
+     */
+    public boolean isWildcard() {
+        return isWildcard;
+    }
+
+    public String[] tearOffParents() {
+        return theParents;
+    }
+
+    public MangledField[] getFields() {
+        return theFields;
+    }
+
+    public MangledField getField(int anOffset) {
+        return theFields[anOffset];
+    }
+
+    public String getType() {
+        return theType;
+    }
+
+    public String getCodebase() {
+        return theCodebase;
+    }
+
+    public int getNumFields() {
+        return theFields.length;
+    }
+
+    public boolean isSnapshot() {
+        return isSnapshot;
+    }
+
+    /**
+     * @param anEntry the Entry to test against.  The instance on which this
+     *                method is called is implicitly treated as the template.
+     */
+    public boolean match(MangledEntry anEntry) {
+        if (isWildcard)
+            return true;
+
+        MangledField[] myEntryFields = anEntry.getFields();
+
+        for (int i = 0; i < theFields.length; i++) {
+            if (!theFields[i].isNull()) {
+                if (!theFields[i].matches(myEntryFields[i]))
+                    return false;
+            }
+        }
+
+        return true;
+    }
+
+    public int hashCode() {
+        int myHash = 0;
+
+        for (int i = 0; i < theFields.length; i++) {
+            myHash ^= theFields.hashCode();
+        }
+
+        return myHash;
+    }
+
+    public boolean equals(Object anObject) {
+        if (anObject instanceof MangledEntry) {
+            MangledEntry myOther = (MangledEntry) anObject;
+
+            if (myOther.theType.equals(theType)) {
+                return match(myOther);
+            }
+        }
+
+        return false;
+    }
+
+    public void dump(PrintStream aStream) {
+        aStream.println("Type: " + theType);
+        aStream.println("Codebase: " + theCodebase);
+        aStream.print("Parents: ");
+
+        if (theParents != null) {
+            for (int i = 0; i < theParents.length; i++) {
+                aStream.print(theParents[i] + ", ");
+            }
+            aStream.println();
+        }
+
+        aStream.println("Fields:");
+        for (int i = 0; i < theFields.length; i++) {
+            aStream.println("  " + theFields[i].getName() + ": " +
+                theFields[i].hashCode());
+        }
+    }
+
+    boolean needsIntegrityCheck() {
+        return checkIntegrity;
+    }
+
+    public net.jini.core.entry.Entry get()
+        throws net.jini.core.entry.UnusableEntryException {
+        return EntryMangler.getMangler().unMangle(this);
+    }
+
+    public net.jini.core.entry.Entry getSnapshot() {
+        return this;
+    }
+
+
+    public String toString() {
+        String myEntryRep = "Unusable";
+
+        try {
+            myEntryRep =
+                AbstractEntry.toString(
+                    EntryMangler.getMangler().unMangle(this));
+        } catch (Exception anE) {
+            // Nothing to do
+            myEntryRep = myEntryRep + ": " + anE.getClass();
+        }
+
+        return myEntryRep;
+    }
+}
\ No newline at end of file