Author: peter_firmstone Date: Wed May 29 21:59:16 2013 New Revision: 1487652
URL: http://svn.apache.org/r1487652 Log: Update for Distributed Objects. Added: river/jtsk/skunk/qa_refactor/trunk/test/src/org/apache/river/api/io/SerialReflectionFactoryTest.java Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/DistributePermission.java river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/Distributed.java river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialReflectionFactory.java river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/net/Uri.java Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/DistributePermission.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/DistributePermission.java?rev=1487652&r1=1487651&r2=1487652&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/DistributePermission.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/DistributePermission.java Wed May 29 21:59:16 2013 @@ -24,7 +24,7 @@ import java.security.BasicPermission; * ObjectOutput * * @author peter - * @see SerialFactory + * @see SerialReflectionFactory * @see ObjectOutput */ public class DistributePermission extends BasicPermission{ Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/Distributed.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/Distributed.java?rev=1487652&r1=1487651&r2=1487652&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/Distributed.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/Distributed.java Wed May 29 21:59:16 2013 @@ -17,45 +17,82 @@ package org.apache.river.api.io; /** - * Distributed objects are immutable value objects with final fields that may - * be freely replicated. - * Distributed objects are not serialized, instead they are only created using a - * public constructor, public static factory method or builder object making them - * more suitable for security, validating class invariants and concurrent code - * that relies on immutability. - * <p> - * Distributed objects are free to evolve and may have completely different - * classes or be completely unequal after distribution to separate nodes, - * but must always share a common public interface or superclass for referential - * purposes. + * Distributed objects are suitable for use as immutable value objects with + * final fields that may be freely replicated, alternatively they are also + * suited as safely published thread safe mutable objects used + * to store service snapshots in a {@link net.jini.io.MarshalledInstance} for + * fail over replication to other nodes, or to upgrade a service. + * <p> + * Distributed objects are not serialized, instead they are only created using an + * accessible constructor, public static factory method or builder object making them + * more suitable for security; validating class invariants and concurrent code + * that relies on immutability and safe publication of fields using final or + * volatile. + * <p> + * Distributed Objects are created remotely with an AccessControlContext + * containing one ProtectionDomain with a CodeSource that has a null location + * and null Certificates. + * Only minimal permissions granted to any location by the administrator will apply. + * Minimal privilege is required to prevent remote instantiation + * of ClassLoader, Policy, SecurityManager, or any other type of object with + * security checks performed during construction. The developer is free to + * use privileged access, including login context from within constructors and + * methods. + * <p> + * The serial form of a Distributed object is managed by SerialReflectionFactory + * and is solely dependant on the classes, parameters and signatures of methods + * or constructors. + * <p> + * Distributed Objects with equal SerialReflectionFactory's shall be identical + * in Object form after un-marshaling within an identical jvm and one + * may be substituted for the other to reduce network traffic. + * <p> + * Distributed Objects that are equal in Object form are not guaranteed to be equal + * in serial form. The implementor may enforce serial form equality by ensuring + * identical methods of creation are used for equal objects and document it in + * javadoc. Distributed objects equal in Object form at one node should also be + * equal after un-marshaling to a second remote node even when serial form differs. + * <p> + * Distributed Objects (boomerangs) that are duplicated across + * nodes may not be equal when returning to a local node after construction and + * redistribution on different nodes. Later versions of code may elect to + * use different classes, constructors or method signatures that result in + * inequality. + * <p> + * Distributed objects while free to evolve and possibly having completely different + * classes or being completely unequal after distribution to separate nodes, + * must always share a common public interface or superclass for referential + * purposes, this may of course be Object, however if it is, it should be stated + * clearly in Javadoc to avoid ClassCastException's upon un-marshaling. * <p> * Distributed objects have no version, instead SerialReflectionFactory contains all * information required to distribute and recreate any Distributed Object using * reflection. For this reason, Distributed objects cannot be used as Entry - * objects, which is dependant on published serial form. It may be possible + * objects, as they are dependant on published serial form. It may be possible * in a later release to use Distributed objects as fields in Entry objects, this * is not supported presently. * <p> - * Distributed objects are value objects from a domain driven design perspective. + * Distributed objects are recommended for use as value objects in domain + * driven design. * <p> - * Although final is not enforced, all fields must be final, safe - * construction must be honored the this reference must not be allowed to + * Although final is not enforced, all fields should be final or volatile, safe + * construction must be honored 'this' must not be allowed to * escape during construction, distributed objects will be exposed to multiple - * threads on multiple nodes, without synchronization or transactions. + * threads on multiple nodes, without external synchronization. * <p> - * Distributed objects are thread safe and immutable. + * Distributed objects are thread safe. * <p> * Do not use Distributed if you don't intend to honor this contract, use * Serializable instead. * <p> - * Distributed Objects are created remotely using an AccessControlContext with one - * ProtectionDomain containing a CodeSource with a null location and null - * Certificates. Only permissions granted to any location will apply. - * Minimal privilege is required to prevent remote instantiation - * of ClassLoader, Policy, SecurityManager, or any other type of object with - * security checks performed during construction. + * Caveat:<br> + * Distributed Objects cannot be stored directly in a + * {@link java.rmi.MarshalledObject}, a {@link net.jini.io.MarshalledInstance} + * must first be created and converted, also a Distributed Object will + * returned as a {@link SerialReflectionFactory} when {@link java.rmi.MarshalledObject} + * is un-marshaled, the {@link java.rmi.MarshalledObject} must first be + * converted to {@link net.jini.io.MarshalledInstance} before un-marshaling. * <p> - * * @author Peter Firmstone. */ public interface Distributed { Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialReflectionFactory.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialReflectionFactory.java?rev=1487652&r1=1487651&r2=1487652&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialReflectionFactory.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialReflectionFactory.java Wed May 29 21:59:16 2013 @@ -23,7 +23,6 @@ import java.io.ObjectOutput; import java.io.Serializable; import java.io.StreamCorruptedException; import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.AccessControlContext; import java.security.AccessController; @@ -33,6 +32,7 @@ import java.security.PrivilegedActionExc import java.security.PrivilegedExceptionAction; import java.security.ProtectionDomain; import java.security.cert.Certificate; +import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; @@ -40,9 +40,12 @@ import java.util.logging.Logger; * Distributed form, required for reflective calls to instantiate objects remotely, * using a constructor, static method or an Object method. * - * This object must be Thread confined, it is not thread safe. + * This object must be Thread confined, it is not thread safe. It should be + * created on demand, it is primarily for use by {@link DistributedObjectInputStream} + * and {@link DistributedObjectOutputStream}, it is created by {@link Distributed} + * Object implementations and {@link DistributedObjectInputStream} * - * Internal state is guarded, arrays are not defensively coped. + * Internal state is guarded, arrays are not defensively copied. * * This is compatible with Version 2 of the Java Serialization Protocol. * @@ -80,11 +83,15 @@ public final class SerialReflectionFacto private static final byte OBJECT = 8; private static final byte NULL = 9; + // Serial Form private Object classOrObject; private String method; private Class [] parameterTypes; private Object [] parameters; - private final boolean constructed; // default value is false. + + // Private local object state. + private int hash; + private boolean constructed; // default value is false. /** * Public method provided for java serialization framework. @@ -147,6 +154,12 @@ public final class SerialReflectionFacto throw new IllegalArgumentException("Array lengths don't match, or arrays are too long," + " parameter array limit 127, " + "you need to see a shrink if you need this many parameters"); + int hash = 7; + hash = 89 * hash + (this.classOrObject != null ? this.classOrObject.hashCode() : 0); + hash = 89 * hash + (this.method != null ? this.method.hashCode() : 0); + hash = 89 * hash + Arrays.hashCode(this.parameterTypes); + hash = 89 * hash + Arrays.deepHashCode(this.parameters); + this.hash = hash; } Object create() throws IOException { @@ -196,6 +209,7 @@ public final class SerialReflectionFacto // Inherit documentation public void writeExternal(ObjectOutput out) throws IOException { distributable.checkGuard(null); + if (! constructed) throw new IOException("Attempt to write blank SerialReflectionFactory"); out.writeObject(classOrObject); out.writeObject(method); /* don't clone arrays for defensive copies, it's up to constructing @@ -309,6 +323,7 @@ public final class SerialReflectionFacto * will never be shared with other threads and will be replaced by * a fully constructed thread safe immutable object. */ if (constructed) throw new IllegalStateException("Object already constructed"); + constructed = true; /* Don't defensively copy arrays, the object is used immediately after * deserialization to construct the Distributed Object, the fields are * not accessed again, it is up to creator methods themselves to @@ -322,5 +337,33 @@ public final class SerialReflectionFacto for (int i = 0; i < len; i++){ parameters[i] = readObject(in); } + int hash = 7; + hash = 89 * hash + (this.classOrObject != null ? this.classOrObject.hashCode() : 0); + hash = 89 * hash + (this.method != null ? this.method.hashCode() : 0); + hash = 89 * hash + Arrays.deepHashCode(this.parameterTypes); + hash = 89 * hash + Arrays.deepHashCode(this.parameters); + this.hash = hash; + } + + // equals and hashcode are implemented to avoid sending duplicates in + // object streams. + @Override + public int hashCode() { + return hash; + } + + @Override + public boolean equals(Object o){ + if (!(o instanceof SerialReflectionFactory)) return false; + if ( hash != o.hashCode()) return false; + SerialReflectionFactory other = (SerialReflectionFactory) o; + if ( classOrObject == null && other.classOrObject != null) return false; + if ( classOrObject != null && ! classOrObject.equals(other.classOrObject)) return false; + if ( method == null && other.method != null) return false; + if ( method != null && ! method.equals(other.method)) return false; + if (!Arrays.equals(parameterTypes, other.parameterTypes)) return false; + if (!Arrays.deepEquals(parameters, other.parameters)) return false; + return true; + // A locally constructed instance may be equal to a deserialized one. } } Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/net/Uri.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/net/Uri.java?rev=1487652&r1=1487651&r2=1487652&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/net/Uri.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/net/Uri.java Wed May 29 21:59:16 2013 @@ -1921,7 +1921,7 @@ public final class Uri implements Compar private String getHashString() { StringBuilder result = new StringBuilder(); if (scheme != null) { - result.append(scheme.toLowerCase()); + result.append(toAsciiLowerCase(scheme)); result.append(':'); } if (opaque) { @@ -1935,7 +1935,7 @@ public final class Uri implements Compar if (userinfo != null) { result.append(userinfo + "@"); //$NON-NLS-1$ } - result.append(host.toLowerCase()); + result.append(toAsciiLowerCase(host)); if (port != -1) { result.append(":" + port); //$NON-NLS-1$ } @@ -1944,7 +1944,7 @@ public final class Uri implements Compar if (path != null) { if (fileSchemeCaseInsensitiveOS){ - result.append(toAsciiUpperCase(path.toCharArray())); + result.append(toAsciiUpperCase(path)); } else { result.append(path); } Added: river/jtsk/skunk/qa_refactor/trunk/test/src/org/apache/river/api/io/SerialReflectionFactoryTest.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/test/src/org/apache/river/api/io/SerialReflectionFactoryTest.java?rev=1487652&view=auto ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/test/src/org/apache/river/api/io/SerialReflectionFactoryTest.java (added) +++ river/jtsk/skunk/qa_refactor/trunk/test/src/org/apache/river/api/io/SerialReflectionFactoryTest.java Wed May 29 21:59:16 2013 @@ -0,0 +1,107 @@ +/* + * 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.river.api.io; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import junit.framework.Assert; +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * + * @author peter + */ +public class SerialReflectionFactoryTest { + + private final SerialReflectionFactory stringInstance; + private final String str; + + public SerialReflectionFactoryTest() { + str = "Fat Bear"; + Class[] cl = {(new char [0]).getClass()}; + Object [] chars = {str.toCharArray()}; + stringInstance = new SerialReflectionFactory(str.getClass(), null, cl , chars); + } + + /** + * Test of hashCode method, of class SerialReflectionFactory. + */ + @Test + public void testHashCode() throws IOException { + System.out.println("hashCode"); + int result = stringInstance.create().hashCode(); + int expResult = str.hashCode(); + assertEquals(expResult, result); + + } + + /** + * Test of equals method, of class SerialReflectionFactory. + */ + @Test + public void testEquals() throws IOException { + System.out.println("equals"); + String expResult = str; + Class[] cl = {(new char [0]).getClass()}; + Object [] chars = {str.toCharArray()}; + // More than one way to create a string. + Object secondInstance = new SerialReflectionFactory(str.getClass(), null, cl, chars ); + SerialReflectionFactory thirdInstance = + new SerialReflectionFactory(new StringBuilder(str), "toString", null, null ); + Object result = stringInstance.create(); + Assert.assertEquals(stringInstance, secondInstance); + // Demonstrate that equal objects can have different serial form. + Assert.assertNotSame(stringInstance, thirdInstance); + Assert.assertEquals(expResult, result); + result = thirdInstance.create(); + Assert.assertEquals(expResult, result); + + } + + /** + * Test of writeExternal method, of class SerialReflectionFactory. + */ + @Test + public void testWriteExternal() throws Exception { + System.out.println("writeExternal"); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ObjectOutputStream outst = new ObjectOutputStream(out); + outst.writeObject(stringInstance); + ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())); + Object result = in.readObject(); + assertEquals(stringInstance, result); + } + + /** + * Test of readExternal method, of class SerialReflectionFactory. + */ + @Test + public void testReadExternal() throws Exception { + System.out.println("readExternal"); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ObjectOutputStream outst = new ObjectOutputStream(out); + outst.writeObject(stringInstance); + ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())); + Object result = in.readObject(); + assertEquals(result, stringInstance); + } +}
