//
// RemoteClusterDataImpl.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
/* Cluster Design Ideas
Everything is via RMI - no 'local' Impl
a Data object is partitioned if any Field in it has a
partitioned domain
interfaces:
Thing
Data
RemoteData (extends Remote, Data, RemoteThing)
RemoteClusterData
RemoteClientData
RemoteClientTuple (extends RemoteTupleIface)
RemoteClientField (extends RemoteField)
RemoteClientPartitionedField (extends RemoteField)
RemoteNodeData
RemoteNodeTuple (extends RemoteTupleIface)
RemoteNodeField (extends RemoteField)
RemoteNodePartitionedField (extends RemoteField)
classes:
UnicastRemoteObject
RemoteThingImpl
RemoteDataImpl
RemoteClusterDataImpl
RemoteClientDataImpl
RemoteClientTupleImpl
RemoteClientFieldImpl
RemoteClientPartitionedFieldImpl
RemoteNodeDataImpl
RemoteNodeTupleImpl
RemoteNodeFieldImpl
RemoteNodePartitionedFieldImpl
RemoteClientPartitionedFieldImpl.getDomainSet() return UnionSet
of getDomainSet() returns from each node
add TupleIface extends Data (Tuple implements TupleIface)
and RemoteTupleIface extends TupleIface
a non-partitioned Data object is local on the client
that is, a DataImpl
a partitioned Data object is a RemoteClientDataImpl on the
cient connected to RemodeNodeDataImpl's on the nodes
NodeAgent, Serializable class sent from client to each node
gets a Thread on arrival at node, return value from send of
NodeAgent is RemoteAgentContact (and Impl)
values from NodeAgent back declared Serializable
abstract class NodeAgent implements Serializable, Runnable
void sendToClient(Serializable message)
invokes RemoteClientAgent.sendToClient(message)
RemoteAgentContactImpl getRemoteAgentContact()
interface RemoteAgentContact extends Remote
class RemoteAgentContactImpl implements RemoteAgentContact
interface RemoteClientAgent extends Remote
void sendToClient(Serializable message)
abstract class RemoteClientAgentImpl implements RemoteClientAgent
class DefaultNodeRendererAgent extends NodeAgent
void run()
interface RemoteNodeData
RemoteAgentContact sendAgent(NodeAgent agent)
NodeRendererJ3D(NodeAgent agent)
NodeRendererJ3D.doTransform()
invokes agent.sendToClient(VisADGroup branch)
see page 60 of Java Enterprise in a Nutshell
no easy way to load RMI classes - security issues
partitioned data on client has similar data trees on
client and nodes
leaf node on client is:
DataImpl
Field with partitioned domain (RemoteClientPartitionedFieldImpl)
non-leaf node on client is:
Tuple (RemoteClientTupleImpl)
Field with non-partitioned domain (RemoteClientFieldImpl)
leaf tree-nodes on cluster-node is:
Field with partitioned domain
(RemoteNodePartitionedFieldImpl adapting FlatField)
non-leaf tree-nodes on cluster-node is:
Tuple (RemoteNodeTupleImpl)
Field with non-partitioned domain (RemoteNodeFieldImpl)
Field with partitioned domain
(RemoteNodePartitionedFieldImpl adapting FieldImpl)
every object in data tree on client connects to objects
in data trees on nodes
may use DisplayImplJ3D on nodes for graphics, with api = TRANSFORM_ONLY
and DisplayRenderer = NodeDisplayRendererJ3D (extends
TransformOnlyDisplayRendererJ3D) doesn't render to screen
uses special DisplayImplJ3D constructor signature (conflict?)
for cluster - modified version of collaborative Display
NodeRendererJ3D extends DefaultRendererJ3D, with
ShadowNode*TypeJ3D - addToGroup() etc to leave as Serializable
note must replace 'Image image' in VisADAppearance
ClientRendererJ3D extends DefaultRendererJ3D, not even using
ShadowTypes, but assembling VisADSceneGraphs from nodes
may also need way for client to signal implicit resolution
reduction to nodes - custom DataRenderers with custon ShadowTypes
whose doTransforms resample down, then call super.doTransform()
with downsampled data
Control field in ScalarMap is marked transient and dglo9.txt
says it should be. But can use the getSaveString() and
setSaveString() methods of Control to transmit Control states.
cluster design should include a native VisAD Data Model on
binary files, via serialization, for an implementation of
FileFlatField on nodes
also need to support FileFlatFields
*/
/*
DisplayImpl.syncRemoteData()
. . .
if (!cluster) waitForTasks(); // WLH 11 April 2001
only needed for testing client and nodes in same JVM
BUT, dglo should make this waitForTasks() more precise
*/
/*
possible deadlock in ThreadPool, if all running ActionImpls
are waiting for other ActionImpls to run
*/
/* VisAD Data Model on various file formats
Data instance method for write
Data static method for read
a parameter to these methods is a file-format-specific
implementation of a FileIO interface, that is used for
low level I/O (should deal with missing data in
file-format-specific way)
other interfaces for constructing appropriate file-format-
specific structures for Tuple, Field, FlatField, Set, Real,
Text, RealTuple, CoordinateSystem, Unit, ErrorEstimate
get review from Steve on this
*/
package visad.cluster;
import visad.*;
import java.rmi.*;
/**
RemoteClusterDataImpl is the super class for cluster
client and node Data.<P>
*/
public abstract class RemoteClusterDataImpl extends RemoteDataImpl
implements RemoteClusterData {
/** Set that defines partition of Data across cluster;
values in partitionSet's domain RealTupleType are
partitioned according to:
jvmTable[partitionSet.valueToIndex()] */
private Set partitionSet = null;
/** domain dimension of partitionSet */
private int dimension = -1;
/** lookup table for RemoteClusterData objects on nodes, last
entry is on client (for non-distributed data) */
private RemoteClusterData[] jvmTable = null;
/** used for testing equality */
private RemoteClusterData me = null;
public RemoteClusterDataImpl() throws RemoteException {
super(null); // RemoteDataImpl.AdaptedData =
// RemoteThingImpl.AdaptedThing = null
// but adapt a ThingImpl and a RemoteThingImpl
// used for over-riding RemoteThingImpl methods
adaptedThingImpl = new ThingImpl();
adaptedRemoteThingImpl = new RemoteThingImpl(adaptedThingImpl);
me = this;
}
RemoteClusterData[] getTable() {
return jvmTable;
}
/** return RemoteClusterData for JVM where data resides;
may be RemoteClusterData for client for non-partitioned data;
may be null for partitioned data outside partitoning */
public RemoteClusterData getClusterData(RealTuple domain)
throws RemoteException, VisADException {
if (domain == null || partitionSet == null || jvmTable == null) {
throw new ClusterException("null domain or setup not done");
}
if (dimension != domain.getDimension()) {
// return client (last entry) for non-partitoned data
return jvmTable[jvmTable.length - 1];
}
// "eval" partitionSet at domain
// first extract values from domain
double[][] vals = new double[dimension][1];
for (int i=0; i<dimension; i++) {
vals[i][0] = ((Real) domain.getComponent(i)).getValue();
}
// test whether domain and partitionSet CoordinateSystems match
RealTupleType out = ((SetType) partitionSet.getType()).getDomain();
CoordinateSystem coord_out = partitionSet.getCoordinateSystem();
RealTupleType in = (RealTupleType) domain.getType();
CoordinateSystem coord_in = domain.getCoordinateSystem();
if (!CoordinateSystem.canConvert(out, coord_out, in, coord_in)) {
// return client (last entry) for non-partitoned data
return jvmTable[jvmTable.length - 1];
}
// if only one, then just return it
if (partitionSet.getLength() == 1) {
return jvmTable[0];
}
// transform coordinates and convert units
vals = CoordinateSystem.transformCoordinates(
((SetType) partitionSet.getType()).getDomain(),
partitionSet.getCoordinateSystem(),
partitionSet.getSetUnits(), null,
(RealTupleType) domain.getType(),
domain.getCoordinateSystem(),
domain.getTupleUnits(), null, vals);
try {
// convert transformed values to a partitionSet index
int[] indices = partitionSet.doubleToIndex(vals);
// return jvmTable entry
return (indices[0] < 0) ? null : jvmTable[indices[0]];
}
catch (SetException e) {
return null;
}
}
public void setupClusterData(Set ps, RemoteClusterData[] table)
throws RemoteException, VisADException {
/* WLH 4 Sept 2001
if (ps == null || table == null) {
throw new ClusterException("ps and table must be non-null");
}
*/
if (table == null) {
throw new ClusterException("table must be non-null");
}
if (ps != null) {
if ((ps.getLength() + 1) > table.length) {
throw new ClusterException("table.length (" + table.length +") must " +
" >= ps.length + 1 (" + (ps.getLength() + 1) +
")");
}
partitionSet = ps;
dimension = ps.getDimension();
}
else {
partitionSet = null;
dimension = -1;
}
jvmTable = table;
}
public Set getPartitionSet() {
return partitionSet;
}
public boolean clusterDataEquals(RemoteClusterData cd)
throws RemoteException {
return (cd == me); // seems to work - but does it really?
}
/** parent logic, looosely copied from DataImpl */
private RemoteClusterDataImpl parent = null;
public void setParent(RemoteClusterDataImpl p) {
parent = p;
}
public void notifyReferences()
throws VisADException, RemoteException {
adaptedThingImpl.notifyReferences();
// recursively propogate data change to parent
if (parent != null) parent.notifyReferences();
}
/** over-ride methods of RemoteThingImpl, but note these
are for notifyReferences(), which currently does nothing
for RemoteThingImpl */
private ThingImpl adaptedThingImpl = null;
// adaptedRemoteThingImpl constructed from adaptedThingImpl
private RemoteThingImpl adaptedRemoteThingImpl = null;
public void addReference(ThingReference r) throws VisADException {
adaptedRemoteThingImpl.addReference(r);
}
public void removeReference(ThingReference r) throws VisADException {
adaptedRemoteThingImpl.removeReference(r);
}
public DataImpl local() throws VisADException, RemoteException {
throw new ClusterException("no local() method for cluster data");
}
/* MUST OVER-RIDE
methods that acccess AdaptedThing and AdaptedData
from RemoteThingImpl:
public void addReference(ThingReference r) throws VisADException;
public void removeReference(ThingReference r) throws VisADException;
from RemoteDataImpl:
public DataImpl local() throws VisADException, RemoteException;
public MathType getType() throws VisADException, RemoteException;
public boolean isMissing() throws VisADException, RemoteException;
public Data binary(Data data, int op, int sampling_mode, int error_mode)
throws VisADException, RemoteException;
public Data binary(Data data, int op, MathType new_type,
int sampling_mode, int error_mode )
throws VisADException, RemoteException;
public Data unary(int op, int sampling_mode, int error_mode)
throws VisADException, RemoteException;
public Data unary(int op, MathType new_type,
int sampling_mode, int error_mode)
throws VisADException, RemoteException;
public double[][] computeRanges(RealType[] reals)
throws VisADException, RemoteException;
public DataShadow computeRanges(ShadowType type, int n)
throws VisADException, RemoteException;
public DataShadow computeRanges(ShadowType type, DataShadow shadow)
throws VisADException, RemoteException;
public Data adjustSamplingError(Data error, int error_mode)
throws VisADException, RemoteException;
public String longString() throws VisADException, RemoteException;
public String longString(String pre)
throws VisADException, RemoteException;
END MUST OVER-RIDE */
public static void main(String[] args)
throws RemoteException, VisADException {
Real r = new Real(0);
RemoteClientTupleImpl cd = new RemoteClientTupleImpl(new Data[] {r});
RemoteClientTupleImpl cd2 = new RemoteClientTupleImpl(new Data[] {r});
System.out.println(cd.equals(cd)); // true
System.out.println(cd.equals(cd2)); // false
System.out.println(cd.clusterDataEquals(cd)); // true
System.out.println(cd.clusterDataEquals(cd2)); // false
System.exit(0);
}
}