com.viaoa.sync.OASyncCombinedClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of oa-core Show documentation
Show all versions of oa-core Show documentation
Object Automation library
The newest version!
/* Copyright 1999 Vince Via [email protected]
Licensed 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 com.viaoa.sync;
import java.util.Comparator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.viaoa.datasource.OADataSource;
import com.viaoa.object.OALinkInfo;
import com.viaoa.object.OAObject;
import com.viaoa.object.OAObjectCacheDelegate;
import com.viaoa.object.OAObjectDelegate;
import com.viaoa.object.OAObjectInfo;
import com.viaoa.object.OAObjectInfoDelegate;
import com.viaoa.object.OAObjectKey;
import com.viaoa.object.OAObjectPropertyDelegate;
import com.viaoa.object.OAObjectSerializer;
import com.viaoa.object.OAThreadLocalDelegate;
import com.viaoa.remote.multiplexer.*;
import com.viaoa.sync.remote.RemoteSyncInterface;
// 20151103 not completed, on hold
/**
* This is used to have multiple servers all combined into a single combined instance.
* This needs to run as a separate java instance, that has a oasyncclient connection for each of
* individual server instances, and a oasyncclient connection to the combined server.
*
* It's assumed that each has the same object model, but that they each have their
* own instances. The object keys are only unique to each server, so the combined server
* will have a new unique key, and this class will handle the mapping between the two.
*
* How this works is by using the oasyncclients to redirect requests/messages to the server at the "other" side.
*
* Note: all of the OASyncClients need to be created from this object, so that it can redirect.
*
* Overview:
* This will combine objects from many servers into one. The objects will have a different objectId
* on the source then what is created on the combined server - example: each server could have an Employee#1
* and the combined server will have Employee 1,2,3,4...
* This class will map between the source and the combined.
* It will then act as a client between them all and send messages from one to the other. When it does this,
* it will need to use the map to get the correct objectId to use.
* OAObjects readResolve from the source servers will change the objId for the combined server and then store
* in a map. Any changes that affect the objId will then update the map.
* Example: Emp objects from a source server will be be sent to the combined server, and have new objectId assigned
* on the combined server.
* Any changes to these objects on the combined server will then be sent (through this class) to the source server.
* Any changes on the source will be sent to the combined server. If the id is changed, then the map will be updated.
*
* @author vvia
*/
public class OASyncCombinedClient {
private static Logger LOG = Logger.getLogger(OASyncCombinedClient.class.getName());
// connection to the combined server.
private OASyncClient syncClient;
// mapping between the object on each server and the combined server
private ConcurrentHashMap hmClientSession = new ConcurrentHashMap();
private class ClientSession {
OASyncClient syncClient;
ConcurrentHashMap hmClassToMapper = new ConcurrentHashMap();
private final Object NextGuidLock = new Object();
private int nextGuid;
private int maxNextGuid;
int getNextGuid() {
int x = 0;
synchronized (NextGuidLock) {
if (nextGuid == maxNextGuid) {
try {
nextGuid = syncClient.getRemoteServer().getNextFiftyObjectGuids();
maxNextGuid = nextGuid + 50;
}
catch (Exception ex) {
LOG.log(Level.WARNING, "", ex);
}
}
x = nextGuid++;
}
return x;
}
}
private class Mapper {
ConcurrentHashMap hmClientToServer = new ConcurrentHashMap();
ConcurrentHashMap hmServerToClient = new ConcurrentHashMap();
}
/**
*
*/
public OASyncCombinedClient() {
// OASyncDelegate.setSyncCombinedClient(this);
}
/**
* Find the client that is the source for the object on the combinedServer.
*/
private ClientSession getClientSession(Class c, OAObjectKey okServer) {
for (Map.Entry me : hmClientSession.entrySet()) {
Mapper m = me.getValue().hmClassToMapper.get(c);
if (m == null) continue;
if (m.hmServerToClient.get(okServer) != null) return me.getValue();
}
return null;
}
/**
* SyncClient that is connected to combined server
* @param hostName
* @param port
*/
public OASyncClient getCombinedSyncClient(Package packagex, String hostName, int port) {
if (syncClient != null) return syncClient;
syncClient = new OASyncClient(packagex, hostName, port, true) {
RemoteSyncInterface remoteSync;
// redirect changes from combined server to the correct server
@Override
public RemoteSyncInterface getRemoteSyncImpl() throws Exception {
if (remoteSync != null) return remoteSync;
remoteSync = new RemoteSyncInterface() {
RemoteSyncInterface getRemoteSyncInterface(ClientSession cs) {
try {
return cs.syncClient.getRemoteSync();
}
catch (Exception e) {
}
return null;
}
@Override
public boolean sort(Class objectClass, OAObjectKey objectKey, String hubPropertyName, String propertyPaths, boolean bAscending, Comparator comp) {
return true;
}
@Override
public boolean removeFromHub(Class objectClass, OAObjectKey objectKey, String hubPropertyName, Class objectClassX, OAObjectKey objectKeyX) {
ClientSession cs = getClientSession(objectClass, objectKey);
if (cs == null) return false;
Mapper m = cs.hmClassToMapper.get(objectClass);
if (m == null) return false;
OAObjectKey k1 = m.hmServerToClient.get(objectKey);
if (k1 == null) return false;
m = cs.hmClassToMapper.get(objectClassX);
if (m == null) return false;
OAObjectKey k2 = m.hmServerToClient.get(objectKeyX);
if (k2 == null) return false;
RemoteSyncInterface rs = getRemoteSyncInterface(cs);
if (rs == null) return false;
rs.removeFromHub(objectClass, k1, hubPropertyName, objectClassX, k2);
return true;
}
@Override
public boolean removeAllFromHub(Class objectClass, OAObjectKey objectKey, String hubPropertyName) {
ClientSession cs = getClientSession(objectClass, objectKey);
if (cs == null) return false;
Mapper m = cs.hmClassToMapper.get(objectClass);
if (m == null) return false;
OAObjectKey k1 = m.hmServerToClient.get(objectKey);
if (k1 == null) return false;
RemoteSyncInterface rs = getRemoteSyncInterface(cs);
if (rs == null) return false;
rs.removeAllFromHub(objectClass, k1, hubPropertyName);
return true;
}
@Override
public boolean propertyChange(final Class objectClass, final OAObjectKey origServerKey, final String propertyName, Object newValue, final boolean bIsBlob) {
//qqqqqqq check to see if objectId is changed, if so then use the old value to find match
// and update the hm with new valeu
//qqqqqq dont send pkey changes
if (propertyName == null) return false;
ClientSession clientSession = getClientSession(objectClass, origServerKey);
if (clientSession == null) return false;
final Mapper mapper = clientSession.hmClassToMapper.get(objectClass);
if (mapper == null) return false;
OAObjectKey clientKey = mapper.hmServerToClient.get(origServerKey);
if (clientKey == null) return false;
final OAObjectInfo oi = OAObjectInfoDelegate.getOAObjectInfo(objectClass);
if (oi == null) return false;
if (oi.isIdProperty(propertyName)) {
// dont send pkey changes
// update key with new value, replace old with new in mapper
OAObjectKey newServerKey = new OAObjectKey(new Object[] {newValue}, origServerKey.getGuid(), origServerKey.isNew());
mapper.hmServerToClient.remove(origServerKey);
mapper.hmServerToClient.put(newServerKey, clientKey);
}
else if (propertyName.equalsIgnoreCase("new")) {
if (!(newValue instanceof Boolean)) return false;
mapper.hmServerToClient.remove(origServerKey);
OAObjectKey newServerKey = new OAObjectKey(origServerKey.getObjectIds(), origServerKey.getGuid(), ((Boolean)newValue).booleanValue());
mapper.hmServerToClient.put(newServerKey, clientKey);
}
else if (propertyName.equalsIgnoreCase("changed")) {
return false;
}
else {
// new value might be another oaObject
// change it's key/etc and set to oaObjKey instead
if (newValue instanceof OAObject) {
OAObject objValue = (OAObject) newValue;
// see if it already exists, then change the value to match orig
Mapper m = getMapper(clientSession, objValue.getClass());
OAObjectKey clientNewValueKey = m.hmServerToClient.get(objValue.getObjectKey());
if (clientNewValueKey == null) {
// new object, does not exist on the source server
OAObjectKey k1 = objValue.getObjectKey();
// need to change key
OAObjectCacheDelegate.removeObject(objValue);
OAObjectDelegate.setAsNewObject(objValue, clientSession.getNextGuid());
// need to add it to mapper
OAObjectKey k2 = objValue.getObjectKey();
m.hmServerToClient.put(k1, k2);
m.hmClientToServer.put(k2, k1);
}
else {
newValue = clientNewValueKey; // send key only
}
}
else if (newValue instanceof OAObjectKey) {
OAObjectKey ok = (OAObjectKey) newValue;
OALinkInfo li = oi.getLinkInfo(propertyName);
if (li == null) return false;
Mapper m3 = clientSession.hmClassToMapper.get(li.getToClass());
if (m3 == null) return false;
OAObjectKey ok2 = m3.hmServerToClient.get(ok);
if (ok2 == null) {
// create new to send
}
else {
newValue = ok2;
}
}
final RemoteSyncInterface remoteSyncInterface = getRemoteSyncInterface(clientSession);
if (remoteSyncInterface == null) return false;
remoteSyncInterface.propertyChange(objectClass, clientKey, propertyName, newValue, bIsBlob);
}
return true;
}
@Override
public boolean moveObjectInHub(Class objectClass, OAObjectKey objectKey, String hubPropertyName, int posFrom, int posTo) {
return false;
}
@Override
public boolean insertInHub(Class masterObjectClass, OAObjectKey masterObjectKey, String hubPropertyName, Object obj, int pos) {
OAObjectKey k1 = getClientToServerKey(masterObjectClass, masterObjectKey);
if (k1 == null) return false;
try {
syncClient.getRemoteSync().insertInHub(masterObjectClass, k1, hubPropertyName, obj, pos);
}
catch (Exception e) {
LOG.log(Level.WARNING, "", e);
}
return true;
}
@Override
public void clearHubChanges(Class masterObjectClass, OAObjectKey masterObjectKey, String hubPropertyName) {
}
@Override
public boolean addToHub(Class masterObjectClass, OAObjectKey masterObjectKey, String hubPropertyName, Object obj) {
OAObjectKey k1 = getClientToServerKey(masterObjectClass, masterObjectKey);
if (k1 == null) return false;
try {
syncClient.getRemoteSync().addToHub(masterObjectClass, k1, hubPropertyName, obj);
}
catch (Exception e) {
LOG.log(Level.WARNING, "", e);
}
return true;
}
@Override
public boolean addNewToHub(Class masterObjectClass, OAObjectKey masterObjectKey, String hubPropertyName, OAObjectSerializer obj) {
return addToHub(masterObjectClass, masterObjectKey, hubPropertyName, obj.getObject());
}
@Override
public void refresh(Class masterObjectClass, OAObjectKey masterObjectKey, String hubPropertyName) {
ClientSession cs = getClientSession(masterObjectClass, masterObjectKey);
if (cs == null) return;
Mapper m = cs.hmClassToMapper.get(masterObjectClass);
if (m == null) return;
OAObjectKey k1 = m.hmServerToClient.get(masterObjectKey);
if (k1 == null) return;
RemoteSyncInterface rs = getRemoteSyncInterface(cs);
if (rs == null) return;
rs.refresh(masterObjectClass, masterObjectKey, hubPropertyName);
}
};
return remoteSync;
}
};
return syncClient;
}
//qqqqqq create a dsCombinedClient that will send requests to this
// save, getRef obj/hub ...
public OASyncClient createSyncClient(Package packagex, String hostName, int port) {
OASyncClient sc = new OASyncClient(packagex, hostName, port, false) {
RemoteSyncInterface remoteSync;
// redirect changes from one server to the combined server
@Override
public RemoteSyncInterface getRemoteSyncImpl() throws Exception {
if (remoteSync != null) return remoteSync;
remoteSync = new RemoteSyncInterface() {
@Override
public boolean sort(Class objectClass, OAObjectKey objectKey, String hubPropertyName, String propertyPaths, boolean bAscending, Comparator comp) {
return true;
}
@Override
public boolean removeFromHub(Class objectClass, OAObjectKey objectKey, String hubPropertyName, Class objectClassX, OAObjectKey objectKeyX) {
OAObjectKey k1 = getClientToServerKey(objectClass, objectKey);
if (k1 == null) return false;
OAObjectKey k2 = getClientToServerKey(objectClassX, objectKeyX);
if (k2 == null) return false;
try {
syncClient.getRemoteSync().removeFromHub(objectClass, k1, hubPropertyName, objectClassX, k2);
}
catch (Exception e) {
LOG.log(Level.WARNING, "", e);
}
return true;
}
@Override
public boolean removeAllFromHub(Class objectClass, OAObjectKey objectKey, String hubPropertyName) {
OAObjectKey k1 = getClientToServerKey(objectClass, objectKey);
if (k1 == null) return false;
try {
syncClient.getRemoteSync().removeAllFromHub(objectClass, k1, hubPropertyName);
}
catch (Exception e) {
LOG.log(Level.WARNING, "", e);
}
return true;
}
@Override
public boolean propertyChange(Class objectClass, OAObjectKey origKey, String propertyName, Object newValue, boolean bIsBlob) {
OAObjectKey k1 = getClientToServerKey(objectClass, origKey);
if (k1 == null) return false;
//qqqqqq could be pkey change
try {
syncClient.getRemoteSync().propertyChange(objectClass, k1, propertyName, newValue, bIsBlob);
}
catch (Exception e) {
LOG.log(Level.WARNING, "", e);
}
return true;
}
@Override
public boolean moveObjectInHub(Class objectClass, OAObjectKey objectKey, String hubPropertyName, int posFrom, int posTo) {
return false;
}
@Override
public boolean insertInHub(Class masterObjectClass, OAObjectKey masterObjectKey, String hubPropertyName, Object obj, int pos) {
OAObjectKey k1 = getClientToServerKey(masterObjectClass, masterObjectKey);
if (k1 == null) return false;
try {
syncClient.getRemoteSync().insertInHub(masterObjectClass, k1, hubPropertyName, obj, pos);
}
catch (Exception e) {
LOG.log(Level.WARNING, "", e);
}
return true;
}
@Override
public void clearHubChanges(Class masterObjectClass, OAObjectKey masterObjectKey, String hubPropertyName) {
}
@Override
public boolean addToHub(Class masterObjectClass, OAObjectKey masterObjectKey, String hubPropertyName, Object obj) {
OAObjectKey k1 = getClientToServerKey(masterObjectClass, masterObjectKey);
if (k1 == null) return false;
try {
syncClient.getRemoteSync().addToHub(masterObjectClass, k1, hubPropertyName, obj);
}
catch (Exception e) {
LOG.log(Level.WARNING, "", e);
}
return true;
}
@Override
public boolean addNewToHub(Class masterObjectClass, OAObjectKey masterObjectKey, String hubPropertyName, OAObjectSerializer obj) {
return addToHub(masterObjectClass, masterObjectKey, hubPropertyName, obj.getObject());
}
@Override
public void refresh(Class masterObjectClass, OAObjectKey masterObjectKey, String hubPropertyName) {
OAObjectKey k1 = getClientToServerKey(masterObjectClass, masterObjectKey);
if (k1 == null) return;
try {
syncClient.getRemoteSync().refresh(masterObjectClass, k1, hubPropertyName);
}
catch (Exception e) {
LOG.log(Level.WARNING, "", e);
}
}
};
return remoteSync;
}
};
OARemoteMultiplexerClient rmc = sc.getRemoteMultiplexerClient();
ClientSession session = new ClientSession();
session.syncClient = sc;
hmClientSession.put(rmc, session);
return sc;
}
public OASyncClient getCurrentThreadSyncClient() {
OARemoteMultiplexerClient rmc = null;//OAThreadLocalDelegate.getRemoteMultiplexerClient();
if (rmc == null) {
return null;
}
ClientSession session = hmClientSession.get(rmc);
if (session == null) {
return null;
}
return session.syncClient;
}
private Mapper getMapper(ClientSession cs, Class c) {
Mapper mapper = cs.hmClassToMapper.get(c);
if (mapper == null) {
synchronized (cs.hmClassToMapper) {
mapper = cs.hmClassToMapper.get(c);
if (mapper == null) {
mapper = new Mapper();
cs.hmClassToMapper.put(c, mapper);
}
}
}
return mapper;
}
/**
* Called from OAObjectSerialization.resolveObject, to get the correct object that is used on the
* combined server.
* @param objClient
* @return null if this is not used, otherwise it will change the object with new Id for combined server.
*/
public OAObject resolveObject(final OAObject objClient) {
OARemoteMultiplexerClient rmc = null;//OAThreadLocalDelegate.getRemoteMultiplexerClient();
if (rmc == null || rmc == syncClient.getRemoteMultiplexerClient()) {
//qqqqqqqqqqq from Server to Client(s) - there might not be any clients
return null;
}
ClientSession session = hmClientSession.get(rmc);
if (session == null) {
return null;
}
// from Client to Server
Mapper mapper = getMapper(session, objClient.getClass());
OAObject objServer;
OAObjectKey keyClient = objClient.getObjectKey();
OAObjectKey keyServer = mapper.hmClientToServer.get(keyClient);
// if null create new obj for server
if (keyServer == null) {
OAObjectDelegate.setAsNewObject(objClient);
objServer = objClient;
//qqqqq need to know when key is changed on server and then update the map
keyServer = objClient.getObjectKey();
mapper.hmClientToServer.put(keyClient, keyServer);
mapper.hmServerToClient.put(keyServer, keyClient);
// qqqqqq remap all of the props that are objkeys
OAObjectInfo oi = OAObjectInfoDelegate.getOAObjectInfo(objServer.getClass());
for (String prop : OAObjectPropertyDelegate.getPropertyNames(objServer)) {
Object objx = OAObjectPropertyDelegate.getProperty(objServer, prop);
if (!(objx instanceof OAObjectKey)) continue;
OAObjectKey k = (OAObjectKey) objx;
OALinkInfo li = oi.getLinkInfo(prop);
if (li == null) continue;
Class c = li.getToClass();
Mapper m = getMapper(session, c);
OAObjectKey k2 = mapper.hmClientToServer.get(k);
if (keyServer == null) {
k2 = new OAObjectKey(null, OAObjectDelegate.getNextGuid(), true);
mapper.hmClientToServer.put(k, k2);
mapper.hmServerToClient.put(k2, k);
}
OAObjectPropertyDelegate.setProperty(objServer, prop, k2);
}
}
else {
objServer = OAObjectCacheDelegate.get(objClient.getClass(), keyServer);
if (objServer == null) {
// get from original server
//qqqqqqqqq
}
}
return objServer;
}
//qqqqqqqqq also
// oi.getImportMatchProperties();
// get the key that was created for the combined server
public OAObjectKey getClientToServerKey(final Class c, final OAObjectKey keyClient) {
OARemoteMultiplexerClient rmc = null;//OAThreadLocalDelegate.getRemoteMultiplexerClient();
if (rmc == null || rmc == syncClient.getRemoteMultiplexerClient()) {
//qqqqqqqqqqq from Server to Client(s) - there might not be any clients
return null;
}
ClientSession session = hmClientSession.get(rmc);
if (session == null) {
return null;
}
Mapper mapper = session.hmClassToMapper.get(c);
if (mapper == null) {
synchronized (session.hmClassToMapper) {
mapper = session.hmClassToMapper.get(c);
if (mapper == null) {
mapper = new Mapper();
session.hmClassToMapper.put(c, mapper);
}
}
}
OAObjectKey keyServer = mapper.hmClientToServer.get(keyClient);
return keyServer;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy