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

com.viaoa.object.OAObjectSiblingDelegate Maven / Gradle / Ivy

package com.viaoa.object;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.ConcurrentHashMap;

import com.viaoa.hub.Hub;
import com.viaoa.hub.HubDetailDelegate;
import com.viaoa.util.OANotExist;
import com.viaoa.util.OAPropertyPath;
import com.viaoa.util.OAString;
import com.viaoa.util.OAThrottle;

/**
 * Find the closet siblings objects that need the same property loaded.
 * Used by DS and CS to be able to get extra data per request to server/datasource, and increase performance.
 * @author vvia
 */
public class OAObjectSiblingDelegate {

    private final static long MaxMs = 25; // max ms for finding
    
    private static final OAThrottle throttle = new OAThrottle(250);
    
    
    /**
     * Used to find any siblings that also need the same property loaded.
     */
    public static OAObjectKey[] getSiblings(final OAObject mainObject, final String property, final int maxAmount) {
        return getSiblings(mainObject, property, maxAmount, null);
    }
    
    /**
     * 
     * @param mainObject
     * @param property
     * @param maxAmount
     * @param hmIgnore ignore list, because they are "inflight" with other concurrent requests
     * @return list of keys that are siblings
     */
    public static OAObjectKey[] getSiblings(final OAObject mainObject, final String property, final int maxAmount, ConcurrentHashMap hmIgnore) {
        long msStarted = System.currentTimeMillis();
        OAObjectKey[] keys = _getSiblings(mainObject, property, maxAmount, hmIgnore, msStarted);
        long x = (System.currentTimeMillis()-msStarted);         
        if (throttle.check() || x > (MaxMs*2)) {
            if (OAObject.getDebugMode()) {
                System.out.println((throttle.getCheckCount())+") OAObjectSiblingDelegate "+x+"ms, obj="+mainObject.getClass().getSimpleName()+", prop="+property+", hmIgnore="+(hmIgnore==null?0:hmIgnore.size())+", alRemove="+keys.length);
            }
        }
        return keys;
    }
    public static OAObjectKey[] _getSiblings(final OAObject mainObject, final String property, final int maxAmount, ConcurrentHashMap hmIgnore, final long msStarted) {
        if (mainObject == null || OAString.isEmpty(property) || maxAmount < 1) return null;

        if (hmIgnore == null) hmIgnore = new ConcurrentHashMap<>();
        
        final OALinkInfo linkInfo = OAObjectInfoDelegate.getLinkInfo(mainObject.getClass(), property);
        
        // set by Finder, HubMerger, HubGroupBy, LoadReferences, etc - where it will be loading from a Root Hub using a PropertyPath
        Hub getDetailHub = OAThreadLocalDelegate.getGetDetailHub();
        String getDetailPropertyPath = OAThreadLocalDelegate.getGetDetailPropertyPath();

        OAPropertyPath ppGetDetailPropertyPath = null;
        if (getDetailHub != null && getDetailPropertyPath != null) {
            try {
                ppGetDetailPropertyPath = new OAPropertyPath(getDetailHub.getObjectClass(), getDetailPropertyPath);
            }
            catch (Exception e) {
                getDetailHub = null;
                getDetailPropertyPath = null;
            }
        }
        
        String ppPrefix = null;
        boolean bValid = false;
        if (ppGetDetailPropertyPath != null) {
            // see if property is in the detailPP
            boolean b = false;
            for (OALinkInfo li : ppGetDetailPropertyPath.getLinkInfos()) {
                if (property.equalsIgnoreCase(li.getName())) {
                    bValid = true;
                    break;
                }
                if (b) {
                    // found mainObj, but next prop was not found
                    b = false;
                    OALinkInfo lix = OAObjectInfoDelegate.getLinkInfo(mainObject.getClass(), property);
                    if (lix != null) {
                        bValid = true;
                        break;
                    }
                }
                if (mainObject.getClass().equals(li.getToClass())) {
                    b = true;
                }
                
                if (ppPrefix == null) ppPrefix = li.getName();
                else ppPrefix += "." + li.getName();
            }
            if (b) {
                OALinkInfo lix = OAObjectInfoDelegate.getLinkInfo(mainObject.getClass(), property);
                if (lix != null) {
                    bValid = true;
                }
            }
            
            if (!bValid) {
                // see if property is off of the detailPP
                ppPrefix = null;
                for (OALinkInfo li : ppGetDetailPropertyPath.getLinkInfos()) {
                    Class c = li.getToClass();
                    OALinkInfo lix = OAObjectInfoDelegate.getLinkInfo(c, mainObject.getClass());
                    if (lix != null) {
                        if (!lix.getPrivateMethod()) bValid = true;
                        break;
                    }
                    if (ppPrefix == null) ppPrefix = li.getName();
                    else ppPrefix += "." + li.getName();
                }
            }
        }
        
        if (!bValid && getDetailHub != null && !getDetailHub.getObjectClass().equals(mainObject.getClass())) {
            // need to get to mainObject.class
            Class c = getDetailHub.getObjectClass();
            OALinkInfo li = OAObjectInfoDelegate.getLinkInfo(c, mainObject.getClass());
            if (li == null || li.getPrivateMethod()) {
                getDetailHub = null;
                ppPrefix = null;
                bValid = false;
            }
            else {
                ppPrefix = li.getName();
                bValid = true;
            }
        }

        final ArrayList alObjectKey = new ArrayList<>();
        final HashMap hsKeys = new HashMap<>();
        
        Hub hub = null;
        OAPropertyPath ppReverse = null;
        
        if (getDetailHub != null && ppPrefix != null) {
            OAPropertyPath ppForward = new OAPropertyPath(getDetailHub.getObjectClass(), ppPrefix);
            OALinkInfo[] lis = ppForward.getLinkInfos();
            boolean b = true;
            if (lis != null) {
                for (OALinkInfo li : lis) {
                    if (li.getType() != OALinkInfo.TYPE_MANY) {
                        b = false;
                        break;
                    }
                }
            }
            if (b) {
                ppReverse = ppForward.getReversePropertyPath();
            }
        }

        OAObject objInHub = mainObject;
        int ppReversePos = -1;

        OALinkInfo lix = null;
        if (ppReverse != null) {
            OALinkInfo[] lis = ppReverse.getLinkInfos();
            if (lis != null && lis.length > 0) lix = lis[0];
            hub = findBestSiblingHub(mainObject, lix);
            ppPrefix = null;  
        }
        else if (getDetailHub != null) {
            hub = getDetailHub;
            if (ppPrefix != null) {
                OAFinder f = new OAFinder(ppPrefix) {
                    @Override
                    protected boolean isUsed(OAObject obj) {
                        return obj == mainObject;
                    }
                };
                f.setUseOnlyLoadedData(true);
                if (f.findFirst(hub) == null) {
                    objInHub = null;
                }
                else {
                    objInHub = (OAObject) hub.getAt(f.getRootHubPos());
                }
            }
        }
        else {
            hub = findBestSiblingHub(mainObject, null);
            ppPrefix = null;  
        }

        int max = maxAmount;
        if (hub == null || getDetailHub == hub) {
        }
        else if (ppReverse != null) {
        }
        else if (hub.getMasterHub() != null) {
            max *= .90;
        }
        else if (hub.getMasterObject() != null) {
            max *= .80;
        }
        else {
            Hub[] hubs = OAObjectHubDelegate.getHubReferences(mainObject);
            if (hubs != null && hubs.length > 1) {
                max *= .75;
            }
        }
            
        final HashSet hsHubVisited = new HashSet<>();
        final HashMap hmTypeOneObjKey = new HashMap<>();
        
        final OACascade cascade = new OACascade();
        
        for (int cnt=0 ; hub!=null; cnt++) {
            if (hsHubVisited.contains(hub)) break;
            hsHubVisited.add(hub);
            
            int startPosHubRoot = hub.getPos(objInHub);
            int x = max;
            for (int i=0; i<=cnt; i++) {
                x /= 2;
            }
            x = Math.min(x, 25);
            startPosHubRoot = Math.max(0, startPosHubRoot - x);
            
            findSiblings(alObjectKey, hub, startPosHubRoot, ppPrefix, property, linkInfo, mainObject, hmTypeOneObjKey, hmIgnore, max, cascade, msStarted, cnt);
            if (alObjectKey.size() >= max) break;

            if (msStarted > 0) {
                long lx = (System.currentTimeMillis()-msStarted);
                if (lx > MaxMs) { //  && !OAObject.getDebugMode()) {
                    break;
                }
            }
            if (cnt > 3) break;
            if (cascade.getVisitCount() > 500) break;
            
            // find next hub to use
            
            lix = HubDetailDelegate.getLinkInfoFromMasterHubToDetail(hub);
            if (lix == null || lix.getToClass() == null) break;  // could be using GroupBy as hub
            
            
            objInHub = hub.getMasterObject();
            
            Hub hubx = null;
            if (ppReverse != null && objInHub != null) {
                OALinkInfo[] lis = ppReverse.getLinkInfos();

                if (ppReversePos < 0) {
                    ppReversePos = 0;
                    if (ppPrefix == null) ppPrefix = lix.getName();
                    else ppPrefix = lix.getName() + "." + ppPrefix;
                }                
                
                OALinkInfo liz = (lis == null || lis.length <= ppReversePos) ? null : lis[ppReversePos];
                if (liz != null && liz.getToClass().equals(objInHub.getClass())) {
                    // could be recursive
                    OALinkInfo lizRecursive = OAObjectInfoDelegate.getObjectInfo(liz.getToClass()).getRecursiveLinkInfo(OALinkInfo.TYPE_ONE);
                    if (lizRecursive != null) {
                        hubx = findBestSiblingHub(objInHub, lizRecursive);
                        if (hubx != null && HubDetailDelegate.getLinkInfoFromDetailToMaster(hubx) != lizRecursive) {
                            hubx = null;
                        }
                    }
                    if (hubx == null) {
                        ppReversePos++;
                        liz = (lis == null || lis.length <= ppReversePos) ? null : lis[ppReversePos];
                        hubx = findBestSiblingHub(objInHub, liz);
                        if (hubx != null && liz != null) {
                            if (ppPrefix == null) ppPrefix = liz.getName();
                            else ppPrefix = liz.getName() + "." + ppPrefix;
                        }
                    }
                    hub = hubx;
                }
            }
            
            if (hubx == null && hub != null) {
                if (ppPrefix == null) ppPrefix = lix.getName();
                else ppPrefix = lix.getName() + "." + ppPrefix;
                
                hubx = hub.getMasterHub();
                if (hubx != null) {
                    hub = hubx;
                }
                else {
                    if (objInHub == null) break;
                    hub = findBestSiblingHub(objInHub, null);
                }
            }
        }
        
        int x = alObjectKey.size();
        OAObjectKey[] keys = new OAObjectKey[x];
        alObjectKey.toArray(keys);
        
        return keys;
    }
    
    
    protected static void findSiblings(
            final ArrayList alFoundObjectKey, 
            final Hub hubRoot, final int startPosHubRoot, final String finderPropertyPath, final String origProperty, 
            final OALinkInfo linkInfo, 
            final OAObject mainObject, 
            final HashMap hmTypeOneObjKey, // for calling thread, refobjs already looked at
            final ConcurrentHashMap hmIgnore,  // for all threads
            final int max,
            final OACascade cascade,
            final long msStarted,
            final int runCount
            ) 
    {
        
        final String property = origProperty.toUpperCase();
        final boolean bIsMany = (linkInfo != null) && (linkInfo.getType() == OALinkInfo.TYPE_MANY);
        boolean b = !bIsMany && (linkInfo != null) && (linkInfo.isOne2One());
        if (b) {
            OALinkInfo rli = linkInfo.getReverseLinkInfo();
            if (!linkInfo.getPrivateMethod() && rli != null && rli.getPrivateMethod()) b = false;
        }
        final boolean bNormalOne2One = b; 
        
        
        final Class clazz = (linkInfo == null) ? null : linkInfo.getToClass();
        
        OAFinder f = new OAFinder(finderPropertyPath) {
            @Override
            protected boolean isUsed(OAObject oaObject) {
                if (oaObject == mainObject) {
                    return false;
                }

                Object propertyValue = OAObjectPropertyDelegate.getProperty(oaObject, property, true, true);

                if (bIsMany) {
                    if (propertyValue instanceof Hub) return false; 
                }
                else if (linkInfo != null && propertyValue instanceof OAObject) {
                    return false;
                }
                else if (linkInfo != null && propertyValue instanceof OAObjectKey) {
                    if (hmTypeOneObjKey.containsKey((OAObjectKey) propertyValue)) return false;
                    hmTypeOneObjKey.put((OAObjectKey) propertyValue, null);
                    if (OAObjectCacheDelegate.get(clazz, (OAObjectKey) propertyValue) != null) return false;
                }
                else if (linkInfo != null) {
                    if (!bNormalOne2One) return false;
                }
                else if (linkInfo == null) {  // must be blob
                    if (!(propertyValue instanceof OANotExist)) return false;
                }
                
                hmIgnore.put(oaObject.getGuid(), Boolean.TRUE);
                OAObjectKey ok = oaObject.getObjectKey();
                if (ok.guid == 0) {
                    ok.guid = oaObject.getGuid();
                }
                alFoundObjectKey.add(ok);
                if (alFoundObjectKey.size() >= max) {
                    stop();
                }
                if (runCount > 0 && cascade.getVisitCount() > 500) {
                    stop();
                }

                return false; // always returns
            }
            @Override
            protected void find(Object obj, int pos) {
                super.find(obj, pos);
                if (msStarted > 0) {
                    long lx = (System.currentTimeMillis()-msStarted);
                    if (lx > MaxMs) { // && !OAObject.getDebugMode()) {
                        stop();
                    }
                }
                if (runCount > 0 && cascade.getVisitCount() > 500) {
                    stop();
                }
            }
        };
        f.setUseOnlyLoadedData(true);
        f.setCascade(cascade);
        OAObject objx = null;
        if (startPosHubRoot > 0) objx = (OAObject) hubRoot.getAt(startPosHubRoot-1);
        f.find(hubRoot, objx);
    }
    
    
    // find the Hub that has the best set of siblings
    public static Hub findBestSiblingHub(OAObject masterObject, OALinkInfo liToMaster) {
        Hub[] hubs = OAObjectHubDelegate.getHubReferences(masterObject);
        
        int siblingHits = 0;
        Hub siblingHub = null;
        
        for (int i=0; (hubs != null && i < hubs.length); i++) {
            Hub hub = hubs[i];
            if (hub == null) continue;

            if (liToMaster != null && HubDetailDelegate.getLinkInfoFromDetailToMaster(hub) == liToMaster) {
                siblingHub = hub;
                break;
            }

            int hits = 1;
            if (hub.getMasterHub() != null) hits += 3;
            else if (hub.getMasterObject() != null) hits += 2;
            
            if (hits > siblingHits) {
                siblingHits = hits;
                siblingHub = hub;
            }
            else if (hits == siblingHits) {
                if (hub.getSize() > siblingHub.getSize()) siblingHub = hub;
            }
        }
        return siblingHub;
    }
}    




© 2015 - 2025 Weber Informatics LLC | Privacy Policy