All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.viaoa.sync.OASyncCombinedClient Maven / Gradle / Ivy

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.ds.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;
            }
        };

        RemoteMultiplexerClient rmc = sc.getRemoteMultiplexerClient();
        ClientSession session = new ClientSession();
        session.syncClient = sc;
        hmClientSession.put(rmc, session);
        
        return sc;
    }
    
    
    public OASyncClient getCurrentThreadSyncClient() {
        RemoteMultiplexerClient 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) {

        RemoteMultiplexerClient 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) {
        
        RemoteMultiplexerClient 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