Author: peter_firmstone Date: Wed Feb 27 08:50:56 2013 New Revision: 1450681
URL: http://svn.apache.org/r1450681 Log: Clean and simple replacement for Serializable - Distributed objects. Added: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/ 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/DistributedObjectInputStream.java river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/DistributedObjectOutputStream.java river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialFactory.java Added: 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=1450681&view=auto ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/DistributePermission.java (added) +++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/DistributePermission.java Wed Feb 27 08:50:56 2013 @@ -0,0 +1,32 @@ +/* + * 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.security.BasicPermission; + +/** + * + * @author peter + */ +public class DistributePermission extends BasicPermission{ + private static final long serialVersionUID = 1L; + + public DistributePermission(){ + super("DISTRIBUTE"); + } + +} \ No newline at end of file Added: 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=1450681&view=auto ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/Distributed.java (added) +++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/Distributed.java Wed Feb 27 08:50:56 2013 @@ -0,0 +1,52 @@ +/* + * 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.Serializable; + +/** + * 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. + * <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. + * <p> + * Distributed objects have no version, instead SerialFactory contains all + * information required to distribute and recreate any Distributed Object. + * <p> + * Distributed object all have a common serial form, defined by SerialFactory. + * <p> + * Distributed objects are value objects in domain driven design. + * <p> + * Remote objects are entity or service objects in domain driven design context. + * <p> + * Although final is not enforced, all fields must be final and safe + * construction must be honored, distributed objects will be exposed to multiple + * threads on multiple nodes, without synchronization or transactions. + * <p> + * Do not use Distributed if you don't intend to honor this contract, use + * Serializable instead. + * + * @author Peter Firmstone. + */ +public interface Distributed { + SerialFactory substitute(); +} Added: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/DistributedObjectInputStream.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/DistributedObjectInputStream.java?rev=1450681&view=auto ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/DistributedObjectInputStream.java (added) +++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/DistributedObjectInputStream.java Wed Feb 27 08:50:56 2013 @@ -0,0 +1,76 @@ +/* + * 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.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * + * @author + */ +public class DistributedObjectInputStream extends ObjectInputStream { + + public static ObjectInputStream create(InputStream in) throws IOException{ + DistributedObjectInputStream result = new DistributedObjectInputStream(in); + AccessController.doPrivileged(new EnableResolveObject(result)); + return result; + } + + /** + * Caller must have SerializablePermission("enableSubstitution") to call + * this method. + * + * @param in + * @throws IOException + */ + protected DistributedObjectInputStream(InputStream in) throws IOException{ + super(in); + try { + super.enableResolveObject(true); + } catch (SecurityException e){ + // Ignore, will be called from privileged context if create method used. + } + } + + private void enableResolveObject(){ + super.enableResolveObject(true); + } + + protected final Object resolveObject(Object o) throws IOException{ + if (o instanceof SerialFactory) return ((SerialFactory)o).create(); + return o; + } + + private static class EnableResolveObject implements PrivilegedAction{ + private final DistributedObjectInputStream in; + + EnableResolveObject(DistributedObjectInputStream in){ + this.in = in; + } + + @Override + public Object run() { + in.enableResolveObject(); + return null; + } + + } +} Added: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/DistributedObjectOutputStream.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/DistributedObjectOutputStream.java?rev=1450681&view=auto ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/DistributedObjectOutputStream.java (added) +++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/DistributedObjectOutputStream.java Wed Feb 27 08:50:56 2013 @@ -0,0 +1,65 @@ +/* + * 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.IOException; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * + * @author peter + */ +public class DistributedObjectOutputStream extends ObjectOutputStream { + + public static ObjectOutputStream create(OutputStream out) throws IOException{ + DistributedObjectOutputStream result = new DistributedObjectOutputStream(out); + AccessController.doPrivileged(new EnableReplaceObject(result)); + return result; + } + + protected DistributedObjectOutputStream (OutputStream out) throws IOException{ + super(out); + super.enableReplaceObject(true); + } + + protected final Object replaceObject(Object o){ + if (o instanceof Distributed) return ((Distributed)o).substitute(); + return o; + } + + private void enableReplaceObject(){ + super.enableReplaceObject(true); + } + + private static class EnableReplaceObject implements PrivilegedAction{ + private final DistributedObjectOutputStream out; + + EnableReplaceObject(DistributedObjectOutputStream out){ + this.out = out; + } + + @Override + public Object run() { + out.enableReplaceObject(); + return null; + } + + } +} Added: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialFactory.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialFactory.java?rev=1450681&view=auto ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialFactory.java (added) +++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialFactory.java Wed Feb 27 08:50:56 2013 @@ -0,0 +1,217 @@ +/* + * 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.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.BasicPermission; +import java.security.Guard; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Distributed form, required for Object reconstruction, using constructor, + * static factory method instantiation or Object builder instantiation. + * + * This object must be Thread confined, it is not thread safe. + * + * Internal state is guarded. + * + * @author Peter Firmstone. + * @see Distributed + * @see DistributePermission + */ +public final class SerialFactory implements Externalizable { + private static final long serialVersionUID = 1L; + /* Guard private state */ + private static final Guard distributable = new DistributePermission(); + + private Object classOrObject; + private String method; + private Class [] parameterTypes; + private Object [] parameters; + private final boolean constructed; // default value is false. + + public SerialFactory(){ + constructed = false; + } + + /** + * + * + * + * @param factoryClassOrObject will be used for constructor, factory static method, + * or builder Object. + * @param methodName name of static factory method, null if using a constructor. + * @param parameterTypes Type signature of method or constructor + * @param parameters Object to be passed to constructor. + */ + public SerialFactory(Object factoryClassOrObject, String methodName, Class[] parameterTypes, Object [] parameters){ + classOrObject = factoryClassOrObject; + method = methodName; + this.parameterTypes = parameterTypes; + this.parameters = parameters; + constructed = true; + } + + Object create() throws IOException { + Method m; + Constructor c; + Class clazz; + boolean object; + if (classOrObject instanceof Class) { + clazz = (Class) classOrObject; + object = false; + } + else { + clazz = classOrObject.getClass(); + object = true; + } + try { + if (method != null){ + m = clazz.getMethod(method, parameterTypes); + if (object) return m.invoke(classOrObject, parameters); + return m.invoke(null, parameters); + } else { + c = clazz.getConstructor(parameterTypes); + return c.newInstance(parameters); + } + } catch (InstantiationException ex) { + throw new IOException(ex); + } catch (IllegalAccessException ex) { + throw new SecurityException(ex); + } catch (IllegalArgumentException ex) { + throw new IOException(ex); + } catch (InvocationTargetException ex) { + throw new IOException(ex); + } catch (NoSuchMethodException ex) { + throw new IOException(ex); + } + } + + @Override + public void writeExternal(ObjectOutput out) throws IOException { + distributable.checkGuard(null); + out.writeObject(classOrObject); + out.writeObject(method); + /* don't clone arrays for defensive copies, it's up to constructing + * object to do so if needs to. + */ + out.writeObject(parameterTypes); + out.writeObject(parameters); + } + + @Override + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + if (constructed) throw new IllegalStateException("Object already constructed"); + /* Don't defensively copy arrays, the object is used immediately after + * deserialization to construct the Distributed Object, the fields are + * not accessed again. + * + * DistributedObjectOutputStream. + */ + classOrObject = in.readObject(); + method = (String) in.readObject(); + parameterTypes = (Class[]) in.readObject(); + parameters = (Object[]) in.readObject(); + + // All this hurts performance for little benefit. + // Read in before changing accessibility of fields. +// Object clas = in.readObject(); +// Object methName = in.readObject(); +// Object paramTypes = in.readObject(); +// Object param = in.readObject(); +// final String [] fieldNames = {"clazz", "method", "parameterTypes", "parameters"}; +// Field [] fields = null; +// try { +// fields = AccessController.doPrivileged(new Action(fieldNames)); +// } catch (PrivilegedActionException ex) { +// Exception e = ex.getException(); +// if (e instanceof NoSuchFieldException) throw new ClassNotFoundException("No such field", e); +// if (e instanceof SecurityException ) throw (SecurityException)e; +// throw new IOException("Unable to instantiate fields", e); +// } +// // Don't worry about defensive copy arrays, the constructor or factory +// // method will be called soon. +// try { +// if (clas instanceof Class) fields[0].set(this, clas); +// if (methName instanceof String) fields[1].set(this, methName); +// if (paramTypes instanceof Class[]) fields[2].set(this,paramTypes); +// if (param instanceof Object[]) fields[3].set(this, param); +// } catch (IllegalArgumentException ex) { +// Logger.getLogger(SerialFactory.class.getName()).log(Level.SEVERE, null, ex); +// } catch (IllegalAccessException ex) { +// Logger.getLogger(SerialFactory.class.getName()).log(Level.SEVERE, null, ex); +// } +// try { +// AccessController.doPrivileged(new RestoreProtection(fields)); +// } catch (PrivilegedActionException ex) { +// Exception e = ex.getException(); +// if (e instanceof SecurityException ) throw (SecurityException)e; +// throw new IOException("Unable to restore access control on final fields", e); +// } + } + +// private class Action implements PrivilegedExceptionAction<Field[]>{ +// private final String [] names; +// +// Action(String [] names){ +// this.names = names; +// } +// +// @Override +// public Field[] run() throws Exception { +// int l = names.length; +// Field [] result = new Field[l]; +// for (int i = 0; i < l; i++){ +// result [i] = SerialFactory.class.getDeclaredField(names[i]); +// result [i].setAccessible(true); +// } +// return result; +// } +// +// } +// +// private class RestoreProtection implements PrivilegedExceptionAction<Boolean>{ +// private final Field [] fields; +// +// RestoreProtection(Field [] f){ +// fields = f; +// } +// @Override +// public Boolean run() throws Exception { +// int l = fields.length; +// for (int i = 0; i < l; i++){ +// fields[i].setAccessible(false); +// } +// return Boolean.TRUE; +// } +// +// } + + + +}
