You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@river.apache.org by pe...@apache.org on 2013/05/29 23:59:16 UTC
svn commit: r1487652 - in /river/jtsk/skunk/qa_refactor/trunk:
src/org/apache/river/api/io/ src/org/apache/river/api/net/
test/src/org/apache/river/api/io/
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);
+ }
+}