Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.sdmlib.replication.SharedSpace Maven / Gradle / Ivy
/*
Copyright (c) 2013 zuendorf
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.sdmlib.replication;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import org.sdmlib.StrUtil;
import org.sdmlib.replication.util.ReplicationChangeSet;
import org.sdmlib.replication.util.ReplicationChannelSet;
import org.sdmlib.replication.util.ReplicationNodeCreator;
import org.sdmlib.replication.util.ReplicationRootSet;
import org.sdmlib.replication.util.SharedSpaceCreator;
import org.sdmlib.replication.util.SharedSpaceSet;
import org.sdmlib.serialization.PropertyChangeInterface;
import de.uniks.networkparser.EntityUtil;
import de.uniks.networkparser.IdMap;
import de.uniks.networkparser.SimpleEvent;
import de.uniks.networkparser.interfaces.Entity;
import de.uniks.networkparser.interfaces.ObjectCondition;
import de.uniks.networkparser.interfaces.SendableEntity;
import de.uniks.networkparser.interfaces.SendableEntityCreator;
import de.uniks.networkparser.json.JsonObject;
import de.uniks.networkparser.json.JsonTokener;
import javafx.application.Platform;
import org.sdmlib.replication.ReplicationChannel;
import org.sdmlib.replication.ChangeHistory;
import org.sdmlib.replication.ReplicationNode;
/**
* @see ReplicationModel.java
*/
public class SharedSpace extends Thread implements PropertyChangeInterface, PropertyChangeListener, ObjectCondition, SendableEntity
{
public static final String JLOG = "jlog";
public static final String CURRENT_HISTORY_ID = "currentHistoryId";
public static final String TERMINATE = "terminate";
public static final String RESEND_ID_HISTORY_PREFIX = "resendIdHistoryPrefix";
public static final String RESEND_ID_HISTORY_NUMBER = "resendIdHistoryNumber";
private static final String LOWER_ID_PREFIX = "lowerIdPrefix";
private static final String LOWER_ID_NUMBER = "lowerIdNumber";
private LinkedBlockingQueue msgQueue = new LinkedBlockingQueue();
private boolean firstMessage = true;
private String serverIp;
private int serverPort;
private GUIListener listener = null;
private ReplicationRoot replicationRoot;
public SharedSpace()
{
}
public SharedSpace(String spaceId, String nodeId, String serverIp, int serverPort, IdMap map)
{
this.spaceId = spaceId;
this.nodeId = nodeId;
this.serverIp = serverIp;
this.serverPort = serverPort;
this.map = map;
}
public ReplicationRoot plainInit()
{
map.with(ReplicationNodeCreator.createIdMap("i"));
map.with((ObjectCondition)this);
setReplicationRoot(new ReplicationRoot());
map.put(SharedSpace.REPLICATION_ROOT, getReplicationRoot());
return getReplicationRoot();
}
public SharedSpace init(PropertyChangeListener laneListener)
{
plainInit();
setName("Lane" + nodeId);
ReplicationChannel channel = createChannels().withConnect(serverIp, serverPort);
channel.setName("ReplicationChannel" + nodeId);
channel.start();
channel.sendSpaceConnectionRequest(spaceId);
waitForCurrentHistoryId();
map.withTimeStamp(this.lastChangeId);
// if (map.getCounter() instanceof SimpleIdCounter)
// {
// ((SimpleIdCounter) map.getCounter()).withNumber(this.lastChangeId);
// }
remoteTaskBoard = new RemoteTaskBoard();
map.put(REMOTE_TASK_BOARD_ROOT, remoteTaskBoard);
if (laneListener != null)
{
remoteTaskBoard.getPropertyChangeSupport().addPropertyChangeListener(laneListener);
replicationRoot.addPropertyChangeListener(laneListener);
}
return this;
}
public void enqueueMsg(ReplicationChannel channel, String msg)
{
try
{
if (firstMessage)
{
firstMessage = false;
JsonObject jsonObject = new JsonObject().withValue(msg);
if (jsonObject.get(CURRENT_HISTORY_ID) != null)
{
long receivedId = Long.parseLong(jsonObject.getString(CURRENT_HISTORY_ID));
if (receivedId > this.lastChangeId)
{
this.lastChangeId = receivedId;
synchronized (this)
{
this.notifyAll();
}
}
return;
}
}
final ChannelMsg channelMsg = new ChannelMsg(channel, msg);
if (isJavaFXApplication())
{
Platform.runLater(new Runnable()
{
@Override
public void run()
{
handleMessage(channelMsg);
}
});
}
else if (this.listener!=null)
{
this.listener.enqueueMsg(this, channelMsg);
}
else
{
msgQueue.put(channelMsg);
}
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public void waitForCurrentHistoryId()
{
while (this.lastChangeId == 0)
{
try
{
synchronized (this)
{
wait();
}
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
@Override
public void run()
{
while (true)
{
try
{
ChannelMsg msg = msgQueue.take();
if (TERMINATE.equals(msg.msg))
{
for (ReplicationChannel c : getChannels())
{
c.send(TERMINATE);
}
break;
}
handleMessage(msg);
}
catch (Exception e)
{
// just try again
}
}
}
public static abstract class HookAction
{
public abstract void run(ReplicationChange change);
}
private LinkedHashSet beforeHandleMessageActions = new LinkedHashSet();
private LinkedHashSet afterHandleMessageActions = new LinkedHashSet();
public void addToBeforeHandleMessageActions(HookAction r)
{
this.beforeHandleMessageActions.add(r);
}
public void removeFromBeforeHandleMessageActions(HookAction r)
{
this.beforeHandleMessageActions.remove(r);
}
public void addToAfterHandleMessageActions(HookAction r) {
this.afterHandleMessageActions.add(r);
}
public void removeFromAfterHandleMessageActions(HookAction r) {
this.afterHandleMessageActions.remove(r);
}
private ReplicationChange previousChange = null;
public void handleMessage(ChannelMsg msg)
{
try
{
// reconstruct change
JsonObject jsonObject = new JsonObject().withValue(msg.msg);
this.isApplyingChangeMsg = true;
if (previousChange == null)
{
previousChange = new ReplicationChange();
}
// check for initial message
if (jsonObject.get("spaceId") != null)
{
// initial message, send current historyId
JsonObject jsonHistoryId = new JsonObject();
jsonHistoryId.put(CURRENT_HISTORY_ID, this.lastChangeId);
msg.channel.send(jsonHistoryId.toString());
// send my changes
previousChange.withHistoryIdNumber(0).withHistoryIdPrefix(" ");
sendAllChangesSince(previousChange, msg.channel);
return;
}
// handle resend request
if (jsonObject.get(RESEND_ID_HISTORY_NUMBER) != null)
{
previousChange.setHistoryIdNumber(jsonObject.getLong(RESEND_ID_HISTORY_NUMBER));
previousChange.setHistoryIdPrefix(jsonObject.getString(RESEND_ID_HISTORY_PREFIX));
sendAllChangesSince(previousChange, msg.channel);
return;
}
IdMap cmap = getChangeMap();
ReplicationChange change = (ReplicationChange) cmap.decode(jsonObject);
change.setChangeMsg(EntityUtil.unQuote(change.getChangeMsg()));
// is change already known?
if (getHistory().getChanges().contains(change))
{
// change already known, ignore
change.withLog("ignore change already known", this.getName());
return;
}
if (change.getHistoryIdNumber() <= -2)
{
System.out.println("Handling change\n" + change.toString());
}
// try to apply change
// is it a conflict?
String key = change.getTargetObjectId() + "|" + change.getTargetProperty();
Object oldChange = this.getHistory().getChangeMap().get(key);
if (change.getIsToManyProperty())
{
// no conflict, but consider ordering
if (oldChange == null)
{
// no conflict do it
applyChange(change, msg.channel);
}
else
{
ReplicationChangeSet oldChanges = (ReplicationChangeSet) oldChange;
// new change will be last, just apply it.
ReplicationChange higher = oldChanges.higher(change);
if (higher == null)
{
applyChange(change, msg.channel);
}
else
{
// undo higher changes, apply, redo higher changes
// find source object, property and earlier content object
String changeMsg = higher.getChangeMsg();
JsonObject higherJson = new JsonObject().withValue(changeMsg);
String sourceId = higherJson.getString(IdMap.ID);
Object sourceObject = map.getObject(sourceId);
JsonObject updateJson = (JsonObject) higherJson.get(SendableEntityCreator.UPDATE);
if (updateJson == null)
{
updateJson = (JsonObject) higherJson.get(SendableEntityCreator.REMOVE);
}
for (Iterator keyIter = updateJson.keyIterator(); keyIter.hasNext();)
{
String property = keyIter.next();
JsonObject targetJson = updateJson.getJsonObject(property);
String targetId = targetJson.getString(IdMap.ID);
Object targetObj = map.getObject(targetId);
// now remove targetObj and its successors from property
// collection
SendableEntityCreator creatorClass = map.getCreatorClass(sourceObject);
Collection collection = (Collection) creatorClass.getValue(sourceObject,
property);
LinkedList higherList = new LinkedList();
boolean found = false;
for (Object obj : collection)
{
if (obj == targetObj)
{
found = true;
}
if (found)
{
higherList.add(obj);
}
}
// remove higher elems from collection
for (Object obj : higherList)
{
creatorClass.setValue(sourceObject, property + SendableEntityCreator.REMOVE, obj, null);
}
// add new
applyChange(change, msg.channel);
// re-add higher elements
for (Object obj : higherList)
{
creatorClass.setValue(sourceObject, property, obj, null);
}
break;
}
}
}
}
else
{
// is new change later than old change?
if (oldChange == null || ((ReplicationChange) oldChange).compareTo(change) < 0)
{
applyChange(change, msg.channel);
}
else
{
// there is a newer change, but we may need to keep this one
// until
// we have synchronized with the sending node.
getHistory().addToChanges(change);
getHistory().addToObsoleteChanges(change);
}
}
}
finally
{
this.isApplyingChangeMsg = false;
}
}
public void sendAllChangesSince(ReplicationChange lower, ReplicationChannel channel)
{
if (lower == null)
{
lower = new ReplicationChange().withHistoryIdNumber(0).withHistoryIdPrefix(" ");
}
for (ReplicationChange change : getHistory().getChanges().tailSet(lower))
{
if (logLevel >= 1)
{
change.withLog("resending", getName());
}
sendChangeTo(channel, change);
}
}
private void sendChangeTo(ReplicationChannel channel, ReplicationChange change)
{
if (channel == null)
{
return;
}
IdMap cmap = getChangeMap();
JsonObject jsonObject = cmap.toJsonObject(change);
// add id of previous change to enable completeness check by receiver
ReplicationChange lower = getHistory().getChanges().lower(change);
if (lower != null)
{
jsonObject.put(LOWER_ID_NUMBER, lower.getHistoryIdNumber());
jsonObject.put(LOWER_ID_PREFIX, lower.getHistoryIdPrefix());
}
String line = jsonObject.toString();
channel.send(line);
}
private void applyChange(ReplicationChange change, ReplicationChannel sender)
{
applyChangeLocally(change);
sendNewChange(change);
// if the change is not the last, the sender might not have got some
// changes
for (ReplicationChange newerChange : getHistory().getChanges().tailSet(change, false))
{
sendChangeTo(sender, newerChange);
}
}
public void applyNoConflictChange(ReplicationChange change)
{
String key = change.getTargetObjectId() + "|" + change.getTargetProperty();
Object oldChange = this.getHistory().getChangeMap().get(key);
if (change.getIsToManyProperty())
{
// no conflict, apply
applyChangeLocally(change);
}
else
{
if (oldChange == null || ((ReplicationChange) oldChange).compareTo(change) < 0)
{
applyChangeLocally(change);
}
}
}
public void applyChangeLocally(ReplicationChange change)
{
// no conflict, apply change
JsonObject jsonUpdate = new JsonObject();
JsonTokener tokener = new JsonTokener();
String changeTxt = change.getChangeMsg();
// tokener.withBuffer(changeTxt);
tokener.parseToEntity(jsonUpdate);
for (HookAction r : beforeHandleMessageActions)
{
r.run(change);
}
try
{
this.setReadMessages(true);
map.decode(jsonUpdate);
} catch (Exception e) {
e.printStackTrace();
}
finally
{
this.setReadMessages(false);
}
getHistory().addChange(change);
// writeChange(change);
this.lastChangeId = Math.max(lastChangeId, change.getHistoryIdNumber());
change.withLog("change applied", this.getName());
for (HookAction r : afterHandleMessageActions)
{
r.run(change);
}
}
private File logFile = null;
public void setLogFile(File logFile)
{
this.logFile = logFile;
try
{
logFileWriter = new FileWriter(logFile, true);
}
catch (IOException e)
{
e.printStackTrace();
}
}
private boolean loadingHistory = false;
private void writeChange(ReplicationChange change)
{
if (loadingHistory)
{
return;
}
try
{
if (logFile == null)
{
boolean result = new File("./SharedSpace/").mkdirs();
logFile = new File("./SharedSpace/" + getSpaceId() + "_" + getNodeId() + ".json");
result = logFile.createNewFile();
}
logFileWriter = new FileWriter(logFile, true);
JsonObject jsonObject = getChangeMap().toJsonObject(change);
logFileWriter.write(jsonObject.toString() + "\n");
logFileWriter.flush();
logFileWriter.close();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void loadHistoryFromFile()
{
// remove old backup file
File backupFile = new File("./SharedSpace/" + getSpaceId() + "_" + getNodeId()
+ ".json.backup");
if (backupFile.exists())
{
backupFile.delete();
}
// move old history file to backup
File historyfile = new File("./SharedSpace/" + getSpaceId() + "_" + getNodeId() + ".json");
if (historyfile.exists())
{
historyfile.renameTo(backupFile);
try
{
BufferedReader in = new BufferedReader(new FileReader(backupFile));
String line = in.readLine();
while (line != null)
{
ChannelMsg msg = new ChannelMsg(null, line);
handleMessage(msg);
line = in.readLine();
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
public void loadHistoryFromFile(File file)
{
if (file.exists())
{
try
{
this.loadingHistory = true;
BufferedReader in = new BufferedReader(new FileReader(file));
String line = in.readLine();
while (line != null)
{
ChannelMsg msg = new ChannelMsg(null, line);
handleMessage(msg);
line = in.readLine();
}
in.close();
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
this.loadingHistory = false;
}
}
}
public void storeMyHistoryCompressed()
{
String loginName = logFile.getName();
loginName = loginName.split("\\.")[0];
// create backup log
File backupFile = new File(logFile.getAbsolutePath() + ".backup");
try
{
Files.copy(logFile.toPath(), backupFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
catch (IOException e)
{
e.printStackTrace();
}
// clear log file
try
{
new RandomAccessFile(logFile, "rw").setLength(0);
}
catch (IOException e)
{
e.printStackTrace();
}
// loop through history
for (ReplicationChange change : getHistory().getChanges())
{
// if my change
if (change.getHistoryIdPrefix().equals(loginName))
{
// add to xy.jlog file
writeChange(change);
}
}
}
public void loadHistoryFromDir(File logDir)
{
// loop through logDir and load all .jlog files
if (logDir.exists() && logDir.isDirectory())
{
ArrayList changeList = new ArrayList();
for (File file : logDir.listFiles())
{
String fileName = file.getName();
if (fileName.endsWith(JLOG))
{
// load all changes in list
try
{
BufferedReader in = new BufferedReader(new FileReader(file));
String line = in.readLine();
while (line != null)
{
JsonObject jsonObject = new JsonObject().withValue(line);
ReplicationChange change = (ReplicationChange) getChangeMap().decode(jsonObject);
change.setChangeMsg(EntityUtil.unQuote(change.getChangeMsg()));
changeList.add(change);
line = in.readLine();
}
in.close();
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// sort by history id and prefix
Collections.sort(changeList);
// apply in order
try
{
this.isApplyingChangeMsg = true;
this.loadingHistory = true;
for (ReplicationChange change : changeList)
{
applyChangeLocally(change);
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
this.isApplyingChangeMsg = false;
this.loadingHistory = false;
}
}
}
private boolean isApplyingChangeMsg = false;
public boolean isApplyingChangeMsg()
{
return isApplyingChangeMsg;
}
public void setApplyingChangeMsg(boolean isApplyingChangeMsg)
{
this.isApplyingChangeMsg = isApplyingChangeMsg;
}
private int logLevel = 0;
static public int msgNo = 0;
@Override
public boolean update(Object event) {
if (isApplyingChangeMsg)
{
// ignore
return true;
}
SimpleEvent simpleEvent = (SimpleEvent) event;
Entity source = simpleEvent.getEntity();
ReplicationChange change = new ReplicationChange()
.withHistoryIdPrefix(nodeId)
.withHistoryIdNumber(getNewHistoryIdNumber())
.withTargetObjectId((String) source.getValue(IdMap.ID))
.withChangeMsg(source.toString());
Object object = source.getValue(SendableEntityCreator.UPDATE);
if (object == null)
{
object = source.getValue(SendableEntityCreator.REMOVE);
}
if (object != null)
{
JsonObject jsonUpdate = (JsonObject) object;
for (Iterator iter = jsonUpdate.keyIterator(); iter.hasNext();)
{
String prop = iter.next();
change.withTargetProperty(prop);
break;
}
}
Object targetObject = map.getObject(change.getTargetObjectId());
SendableEntityCreator creator = map.getCreatorClass(targetObject);
Object value = creator.getValue(targetObject, change.getTargetProperty());
if (value != null && value instanceof Collection)
{
change.setIsToManyProperty(true);
}
if (logLevel >= Task.DO_LOG)
{
change.withLog("change recorded", this.getName());
}
getHistory().addChange(change);
writeChange(change);
sendNewChange(change);
return true;
}
private IdMap changeMap = null;
private void sendNewChange(ReplicationChange change)
{
IdMap cmap = getChangeMap();
JsonObject jsonObject = cmap.toJsonObject(change);
// add id of previous change to enable completeness check by receiver
ReplicationChange lower = getHistory().getChanges().lower(change);
if (lower != null)
{
jsonObject.put(LOWER_ID_NUMBER, lower.getHistoryIdNumber());
jsonObject.put(LOWER_ID_PREFIX, lower.getHistoryIdPrefix());
}
String line = jsonObject.toString();
for (ReplicationChannel channel : this.getChannels())
{
channel.send(line);
}
}
public long getNewHistoryIdNumber()
{
lastChangeId++;
return lastChangeId;
}
public long getNewHistoryIdNumber(int increment)
{
lastChangeId += increment;
return lastChangeId;
}
// ==========================================================================
public IdMap getChangeMap()
{
if (changeMap == null)
{
changeMap = ReplicationNodeCreator.createIdMap(nodeId);
}
return changeMap;
}
public Object get(String attrName)
{
if (PROPERTY_SPACEID.equalsIgnoreCase(attrName))
{
return getSpaceId();
}
if (PROPERTY_NODE.equalsIgnoreCase(attrName))
{
return getNode();
}
if (PROPERTY_CHANNELS.equalsIgnoreCase(attrName))
{
return getChannels();
}
if (PROPERTY_HISTORY.equalsIgnoreCase(attrName))
{
return getHistory();
}
if (PROPERTY_LASTCHANGEID.equalsIgnoreCase(attrName))
{
return getLastChangeId();
}
if (PROPERTY_NODEID.equalsIgnoreCase(attrName))
{
return getNodeId();
}
return null;
}
// ==========================================================================
public boolean set(String attrName, Object value)
{
if (PROPERTY_SPACEID.equalsIgnoreCase(attrName))
{
setSpaceId((String) value);
return true;
}
if (PROPERTY_NODE.equalsIgnoreCase(attrName))
{
setNode((ReplicationNode) value);
return true;
}
if (PROPERTY_CHANNELS.equalsIgnoreCase(attrName))
{
addToChannels((ReplicationChannel) value);
return true;
}
if ((PROPERTY_CHANNELS + SendableEntityCreator.REMOVE).equalsIgnoreCase(attrName))
{
removeFromChannels((ReplicationChannel) value);
return true;
}
if (PROPERTY_HISTORY.equalsIgnoreCase(attrName))
{
setHistory((ChangeHistory) value);
return true;
}
if (PROPERTY_LASTCHANGEID.equalsIgnoreCase(attrName))
{
setLastChangeId(Long.parseLong(value.toString()));
return true;
}
if (PROPERTY_NODEID.equalsIgnoreCase(attrName))
{
setNodeId((String) value);
return true;
}
return false;
}
// ==========================================================================
protected PropertyChangeSupport listeners = new PropertyChangeSupport(this);
public PropertyChangeSupport getPropertyChangeSupport()
{
return listeners;
}
public boolean addPropertyChangeListener(PropertyChangeListener listener)
{
getPropertyChangeSupport().addPropertyChangeListener(listener);
return true;
}
public boolean addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
getPropertyChangeSupport().addPropertyChangeListener(propertyName, listener);
return true;
}
public boolean removePropertyChangeListener(PropertyChangeListener listener) {
if (listeners != null) {
listeners.removePropertyChangeListener(listener);
}
return true;
}
public boolean removePropertyChangeListener(String property, PropertyChangeListener listener) {
if (listeners != null) {
listeners.removePropertyChangeListener(property, listener);
}
return true;
}
// ==========================================================================
public void removeYou()
{
setNode(null);
removeAllFromChannels();
withoutChannels(this.getChannels().toArray(new ReplicationChannel[this.getChannels().size()]));
setHistory(null);
getPropertyChangeSupport().firePropertyChange("REMOVE_YOU", this, null);
}
// ==========================================================================
public static final String PROPERTY_SPACEID = "spaceId";
private String spaceId;
public String getSpaceId()
{
return this.spaceId;
}
public void setSpaceId(String value)
{
if (!StrUtil.stringEquals(this.spaceId, value))
{
String oldValue = this.spaceId;
this.spaceId = value;
getPropertyChangeSupport().firePropertyChange(PROPERTY_SPACEID, oldValue, value);
}
}
public SharedSpace withSpaceId(String value)
{
setSpaceId(value);
return this;
}
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(" SharedSpace");
sb.append(" ").append(this.getSpaceId());
sb.append(" ").append(this.getNodeId());
return sb.substring(1);
}
public static final SharedSpaceSet EMPTY_SET = new SharedSpaceSet();
/********************************************************************
*
* many one
* SharedSpace ----------------------------------- ReplicationNode
* sharedSpaces node
*
*/
public static final String PROPERTY_NODE = "node";
private ReplicationNode node = null;
public ReplicationNode getNode()
{
return this.node;
}
public boolean setNode(ReplicationNode value)
{
boolean changed = false;
if (this.node != value)
{
ReplicationNode oldValue = this.node;
if (this.node != null)
{
this.node = null;
oldValue.withoutSharedSpaces(this);
}
this.node = value;
if (value != null)
{
value.withSharedSpaces(this);
}
getPropertyChangeSupport().firePropertyChange(PROPERTY_NODE, oldValue, value);
changed = true;
}
return changed;
}
public SharedSpace withNode(ReplicationNode value)
{
setNode(value);
return this;
}
public ReplicationNode createNode()
{
ReplicationNode value = new ReplicationNode();
withNode(value);
return value;
}
/********************************************************************
*
* one many
* SharedSpace ----------------------------------- ReplicationChannel
* sharedSpace channels
*
*/
public static final String PROPERTY_CHANNELS = "channels";
private ReplicationChannelSet channels = null;
private IdMap map;
public IdMap getMap()
{
return map;
}
public void setMap(IdMap map)
{
this.map = map;
}
public ReplicationChannelSet getChannels()
{
if (this.channels == null)
{
return ReplicationChannel.EMPTY_SET;
}
return this.channels;
}
public boolean addToChannels(ReplicationChannel value)
{
boolean changed = false;
if (value != null)
{
if (this.channels == null)
{
this.channels = new ReplicationChannelSet();
}
changed = this.channels.add(value);
if (changed)
{
value.withSharedSpace(this);
getPropertyChangeSupport().firePropertyChange(PROPERTY_CHANNELS, null, value);
}
}
return changed;
}
public boolean removeFromChannels(ReplicationChannel value)
{
boolean changed = false;
if ((this.channels != null) && (value != null))
{
changed = this.channels.remove(value);
if (changed)
{
value.setSharedSpace(null);
getPropertyChangeSupport().firePropertyChange(PROPERTY_CHANNELS, value, null);
}
}
return changed;
}
public SharedSpace withChannels(ReplicationChannel value)
{
addToChannels(value);
return this;
}
public SharedSpace withoutChannels(ReplicationChannel value)
{
removeFromChannels(value);
return this;
}
public void removeAllFromChannels()
{
LinkedHashSet tmpSet = new LinkedHashSet(
this.getChannels());
for (ReplicationChannel value : tmpSet)
{
this.removeFromChannels(value);
}
}
/**
* @return Return the created Channel
* @see ReplicationObjectScenarioForCoverage.java
*/
public ReplicationChannel createChannels()
{
ReplicationChannel value = new ReplicationChannel();
withChannels(value);
return value;
}
/**
* @param hostName The Hostname
* @param replicationServerPort The Port of the ReplicationChannel
*@return the ReplicationChannel
* @see ReplicationObjectScenarioForCoverage.java
*/
public ReplicationChannel createChannels(String hostName, int replicationServerPort)
{
ReplicationChannel channel = this.createChannels();
channel.setName("ReplicationChannel" + this.getNodeId() + "Server");
channel.withConnect(hostName, replicationServerPort);
return channel;
}
public void withMap(IdMap map)
{
this.map = map;
map.with((ObjectCondition)this);
}
@Override
public void propertyChange(PropertyChangeEvent evt)
{
// System.out.println(evt);
}
// ==========================================================================
public static final String PROPERTY_HISTORY = "history";
private ChangeHistory history;
public ChangeHistory getHistory()
{
if (history == null)
{
history = new ChangeHistory();
}
return this.history;
}
public void setHistory(ChangeHistory value)
{
if (this.history != value)
{
ChangeHistory oldValue = this.history;
this.history = value;
getPropertyChangeSupport().firePropertyChange(PROPERTY_HISTORY, oldValue, value);
}
}
public SharedSpace withHistory(ChangeHistory value)
{
setHistory(value);
return this;
}
// ==========================================================================
public static final String PROPERTY_LASTCHANGEID = "lastChangeId";
private long lastChangeId;
public long getLastChangeId()
{
return this.lastChangeId;
}
public void setLastChangeId(long value)
{
if (this.lastChangeId != value)
{
long oldValue = this.lastChangeId;
this.lastChangeId = value;
getPropertyChangeSupport().firePropertyChange(PROPERTY_LASTCHANGEID, oldValue, value);
}
}
public SharedSpace withLastChangeId(long value)
{
setLastChangeId(value);
return this;
}
// ==========================================================================
public static final String PROPERTY_NODEID = "nodeId";
private String nodeId;
private FileWriter logFileWriter;
public String getNodeId()
{
return this.nodeId;
}
public void setNodeId(String value)
{
if (!StrUtil.stringEquals(this.nodeId, value))
{
String oldValue = this.nodeId;
this.nodeId = value;
getPropertyChangeSupport().firePropertyChange(PROPERTY_NODEID, oldValue, value);
}
}
public SharedSpace withNodeId(String value)
{
setNodeId(value);
return this;
}
public T glueObjectsAtId(String id, T newObj)
{
// id already in use?
Object oldObj = map.getObject(id);
if (oldObj == null)
{
map.put(id, newObj);
return newObj;
}
else
{
String newKey = map.getKey(newObj);
// transfer attributes from newObj to oldObj
// use the newer change
SendableEntityCreator creator = map.getCreatorClass(oldObj);
for (String prop : creator.getProperties())
{
Object value = creator.getValue(newObj, prop);
if (value != null && value instanceof Collection)
{
// add all elements to oldObj
for (Object elem : (Collection) value)
{
creator.setValue(oldObj, prop, elem, "");
}
}
else if (value != null)
{
creator.setValue(oldObj, prop, value, "");
}
}
return (T) oldObj;
}
}
public static final String REMOTE_TASK_BOARD_ROOT = "taskFlowBoardRoot";
public static final String REPLICATION_ROOT = "replicationRoot";
private RemoteTaskBoard remoteTaskBoard;
public RemoteTaskBoard getRemoteTaskBoard()
{
return remoteTaskBoard;
}
public void setRemoteTaskBoard(RemoteTaskBoard remoteTaskBoard)
{
this.remoteTaskBoard = remoteTaskBoard;
}
private boolean readMessages = false;
public void setReadMessages(boolean readMessages)
{
this.readMessages = readMessages;
}
public boolean isReadMessages()
{
return readMessages;
}
public SharedSpace withChannels(ReplicationChannel... value)
{
for (ReplicationChannel item : value)
{
addToChannels(item);
}
return this;
}
public SharedSpace withoutChannels(ReplicationChannel... value)
{
for (ReplicationChannel item : value)
{
removeFromChannels(item);
}
return this;
}
public Object getSharedObject(String objectName)
{
ReplicationRoot replicationRoot = (ReplicationRoot) map.getObject(REPLICATION_ROOT);
if(replicationRoot != null) {
ReplicationRootSet kids = replicationRoot.getKids();
for (ReplicationRoot kid : kids)
{
if(StrUtil.stringEquals(kid.getName(), objectName)) {
return kid.getApplicationObject();
}
}
}
return null;
}
public boolean isLoadingHistory()
{
return loadingHistory;
}
public void setLoadingHistory(boolean loadingHistory)
{
this.loadingHistory = loadingHistory;
}
public class ChannelMsg
{
public ChannelMsg(ReplicationChannel channel, String msg)
{
this.channel = channel;
this.msg = msg;
}
public ReplicationChannel channel;
public String msg;
}
//==========================================================================
public static final String PROPERTY_SOCKET = "socket";
private Socket socket;
public Socket getSocket()
{
return this.socket;
}
public void setSocket(Socket value)
{
if (this.socket != value)
{
Socket oldValue = this.socket;
this.socket = value;
getPropertyChangeSupport().firePropertyChange(PROPERTY_SOCKET, oldValue, value);
}
}
public SharedSpace withSocket(Socket value)
{
setSocket(value);
return this;
}
//==========================================================================
public static final String PROPERTY_TARGETNODEID = "targetNodeId";
private String targetNodeId;
public String getTargetNodeId()
{
return this.targetNodeId;
}
public void setTargetNodeId(String value)
{
if ( ! StrUtil.stringEquals(this.targetNodeId, value))
{
String oldValue = this.targetNodeId;
this.targetNodeId = value;
getPropertyChangeSupport().firePropertyChange(PROPERTY_TARGETNODEID, oldValue, value);
}
}
public SharedSpace withTargetNodeId(String value)
{
setTargetNodeId(value);
return this;
}
public SharedSpace withGUIListener(GUIListener listener){
this.listener = listener;
return this;
}
public static class MousePositionInfo
{
private double xPos;
private double yPos;
private String windowId;
public double getXPos()
{
return xPos;
}
public double getYPos()
{
return yPos;
}
public String getWindowId()
{
return windowId;
}
}
private Map mousePositions = new HashMap();
public void setMousePositionAndWindowIdForUser(String userId, double x, double y, String windowId)
{
MousePositionInfo info = mousePositions.get(userId);
if (info == null)
{
info = new MousePositionInfo();
mousePositions.put(userId, info);
}
info.xPos = x;
info.yPos = y;
info.windowId = windowId;
}
public SharedSpace.MousePositionInfo getMousePositionForUser(String userId, String windowId)
{
MousePositionInfo info = mousePositions.get(userId);
if (info != null && info.windowId.equals(windowId))
{
return info;
}
else
{
return null;
}
}
public ReplicationRoot getReplicationRoot()
{
return replicationRoot;
}
public void setReplicationRoot(ReplicationRoot replicationRoot)
{
this.replicationRoot = replicationRoot;
}
//==========================================================================
public static final String PROPERTY_JAVAFXAPPLICATION = "javaFXApplication";
private boolean javaFXApplication;
public boolean isJavaFXApplication()
{
return this.javaFXApplication;
}
public void setJavaFXApplication(boolean value)
{
if (this.javaFXApplication != value)
{
boolean oldValue = this.javaFXApplication;
this.javaFXApplication = value;
getPropertyChangeSupport().firePropertyChange(PROPERTY_JAVAFXAPPLICATION, oldValue, value);
}
}
public SharedSpace withJavaFXApplication(boolean value)
{
setJavaFXApplication(value);
return this;
}
public SharedSpace init(IdMap userModelIdMap, boolean javaFXApplication)
{
String userName = userModelIdMap.getSession();
this.withSpaceId(userName + "Space")
.withNodeId(userName + "Node")
.withJavaFXApplication(javaFXApplication);
this.withMap(userModelIdMap);
userModelIdMap.with(SharedSpaceCreator.createIdMap(null));
return this;
}
public void put(String string, Object object)
{
this.getMap().put(string, object);
}
public ChangeHistory createHistory()
{
ChangeHistory value = new ChangeHistory();
withHistory(value);
return value;
}
public boolean firePropertyChange(String propertyName, Object oldValue, Object newValue)
{
if (listeners != null) {
listeners.firePropertyChange(propertyName, oldValue, newValue);
return true;
}
return false;
}
}