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

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

/* Copyright 1999-2015 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.object;

import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.viaoa.concurrent.OAExecutorService;
import com.viaoa.ds.OASelect;
import com.viaoa.hub.*;
import com.viaoa.util.*;

// 20170611
/*
 * This is used to load a property path in parallel using multiple threads.
 *
 * @param 
 *            type of hub or OAObject to use as the root (from)
 * @param 
 *            type of hub for the to class (to).
 * 
 *  example:
 * 
    OALoader l = new OALoader(CompanyPP.locations.employees);
    l.load(company);
    

    // recursive
    OALoader loader = new OALoader(5, ItemCategoryPP.itemCategories().items().products().pp);
    loader.load(ModelDelegate.getItemCategories());
    
    
 * 
 */
public class OALoader {
    private static Logger LOG = Logger.getLogger(OALoader.class.getName());
    private String strPropertyPath;
    private OAPropertyPath propertyPath;

    private OALinkInfo liRecursiveRoot;

    private OALinkInfo[] linkInfos;
    private OALinkInfo[] recursiveLinkInfos;
    private Method[] methods;

    private volatile boolean bStop;
    private boolean bSetup;

    private final int threadCount;
    private volatile OAExecutorService executorService;
    private final AtomicInteger aiThreadsUsed = new AtomicInteger(); 

    private final AtomicInteger aiVisitCnt = new AtomicInteger();
    private final AtomicInteger aiNotLoadedCnt = new AtomicInteger();
    
    private Hub hubFrom;
    
    private OACascade[] cascades;

    public OALoader(int threadCount, String propPath) {
        this.threadCount = Math.min(threadCount, 50);
        this.strPropertyPath = propPath;
    }

    /**
     * This is used to stop the current find that is in process. This can be used when overwriting the
     * onFound().
     */
    public void stop() {
        bStop = true;
    }

    public int getVisitCount() {
        return aiVisitCnt.get();
    }
    public int getNotLoadedCount() {
        return aiNotLoadedCnt.get();
    }

    /**
     */
    public void load(Hub hubRoot) {
        if (hubRoot == null) return;

        bStop = false;
        setup(hubRoot.getObjectClass());
        if (threadCount > 0) executorService = new OAExecutorService(threadCount, "OALoader");

        this.hubFrom = hubRoot;
        
        Hub hubHold = OAThreadLocalDelegate.getGetDetailHub();
        String ppHold = OAThreadLocalDelegate.getGetDetailPropertyPath();
        try {
            OAThreadLocalDelegate.setGetDetailHub(OALoader.this.hubFrom, OALoader.this.strPropertyPath);
            for (F obj : hubRoot) {
                _load(obj);
                if (bStop) break;
            }
            this.hubFrom = null;
        }
        finally {
            OAThreadLocalDelegate.resetGetDetailHub(hubHold, ppHold);
            onThreadDone(true);
        }
    }
    
    public void load(OASelect sel) {
        if (sel == null) return;

        bStop = false;
        setup(sel.getSelectClass());
        if (threadCount > 0) executorService = new OAExecutorService(threadCount, "OALoader");
        this.hubFrom = new Hub(sel.getSelectClass());

        Hub hubHold = OAThreadLocalDelegate.getGetDetailHub();
        String ppHold = OAThreadLocalDelegate.getGetDetailPropertyPath();
        try {
            OAThreadLocalDelegate.setGetDetailHub(OALoader.this.hubFrom, OALoader.this.strPropertyPath);
            for ( ;!bStop && (sel.hasMore() || hubFrom.size()>0); ) {
                for ( ;sel.hasMore() && hubFrom.size() < 200; ) {
                    if (bStop) break;
                    hubFrom.add(sel.next());
                }
                Object obj = hubFrom.getAt(0);
                hubFrom.remove(0);
                _load((F) obj);
            }        
        }
        finally {
            OAThreadLocalDelegate.resetGetDetailHub(hubHold, ppHold);
            onThreadDone(true);
        }
    }
    
    public void load(F objectRoot) {
        if (objectRoot == null) return;

        bStop = false;
        setup(objectRoot.getClass());
        if (threadCount > 0) executorService = new OAExecutorService(threadCount, "OALoader");

        hubFrom = new Hub(objectRoot.getClass());
        hubFrom.add(objectRoot);
        
        Hub hubHold = OAThreadLocalDelegate.getGetDetailHub();
        String ppHold = OAThreadLocalDelegate.getGetDetailPropertyPath();
        try {
            OAThreadLocalDelegate.setGetDetailHub(OALoader.this.hubFrom, OALoader.this.strPropertyPath);
            _load(objectRoot);
        }
        finally {
            OAThreadLocalDelegate.resetGetDetailHub(hubHold, ppHold);
            onThreadDone(true);
        }
    }
    
    private final AtomicBoolean abMainThreadRunning = new AtomicBoolean(true); 
    private void onThreadDone(boolean bMainThread) {
        if (bMainThread) abMainThreadRunning.set(false);
        else if (abMainThreadRunning.get()) return;
        
        if (aiThreadsUsed.get() == 0) {
            if (executorService != null) {  
                executorService.close();
                executorService = null;
            }
            this.hubFrom = null;
            this.cascades = null;
        }
    }
    
    public void waitUntilDone() {
        for (;;) {
            if (executorService == null) {
                if (!abMainThreadRunning.get()) break;
            }
            try {
                Thread.sleep(250);
            }
            catch (Exception e) {}
        }
    }
    
    
    protected void _load(F object) {
        if (object == null) return;

        _load(object, 0);
    }

    private void _load(final Object obj, final int pos) {
        if (obj == null) return;
        aiVisitCnt.incrementAndGet();
        
        if (obj instanceof Hub) {
            for (Object objx : (Hub) obj) {
                _load(objx, pos);
                if (bStop) break;
            }
            return;
        }

        if (!(obj instanceof OAObject)) return;

        if (pos > 0 && cascades != null && (linkInfos != null && (pos+1) < linkInfos.length)) {
            if (cascades[pos-1].wasCascaded((OAObject) obj, true)) return;
        }
        
        // check if recursive
        if (pos == 0) {
            if (liRecursiveRoot != null) {
                Object objx = liRecursiveRoot.getValue(obj);
                _load(objx, pos); // go up a level to then go through hub
                if (bStop) return;
            }
        }
        else if (recursiveLinkInfos != null && pos <= recursiveLinkInfos.length && (recursiveLinkInfos[pos - 1] != null)) {
            boolean bLoaded = recursiveLinkInfos[pos - 1].isLoaded(obj);
            boolean bLocked = executorService != null && recursiveLinkInfos[pos - 1].isLocked(obj);
            if (!bLoaded && !bLocked) aiNotLoadedCnt.incrementAndGet();
            
            if (executorService != null && !bLoaded && !bLocked && aiThreadsUsed.get() < threadCount) {
                int x = aiThreadsUsed.incrementAndGet();
                if (x <= threadCount) {
                    executorService.submit(new Runnable() {
                        @Override
                        public void run() {
                            if (bStop) return;
                            try {
                                OAThreadLocalDelegate.setGetDetailHub(OALoader.this.hubFrom, OALoader.this.strPropertyPath);
                                Object objx = recursiveLinkInfos[pos - 1].getValue(obj);
                                _load(objx, pos);
                            }
                            catch (Exception e) {
                                LOG.log(Level.WARNING, "OALoader error while in run", e);
                            }
                            finally {
                                OAThreadLocalDelegate.resetGetDetailHub(null, null);
                                aiThreadsUsed.decrementAndGet();
                                onThreadDone(false);
                            }
                        }
                    });
                    return;
                }
                aiThreadsUsed.decrementAndGet();
            }
            
            if (!bLocked) {
                Object objx = recursiveLinkInfos[pos - 1].getValue(obj);
                _load(objx, pos);
            }
            if (bStop) return;
        }

        if (linkInfos != null && pos < linkInfos.length) {
            boolean bLoaded = linkInfos[pos].isLoaded(obj);
            boolean bLocked = executorService != null && linkInfos[pos].isLocked(obj);
            if (!bLoaded && !bLocked) aiNotLoadedCnt.incrementAndGet();
            
            if (executorService != null && !bLoaded && !bLocked && aiThreadsUsed.get() < threadCount) {
                int x = aiThreadsUsed.incrementAndGet();
                if (x <= threadCount) {
                    executorService.submit(new Runnable() {
                        @Override
                        public void run() {
                            if (bStop) return;
                            try {
                                OAThreadLocalDelegate.setGetDetailHub(OALoader.this.hubFrom, OALoader.this.strPropertyPath);
                                Object objx = linkInfos[pos].getValue(obj);
                                _load(objx, pos+1);
                            }
                            catch (Exception e) {
                                LOG.log(Level.WARNING, "OALoader error while in run", e);
                            }
                            finally {
                                OAThreadLocalDelegate.resetGetDetailHub(null, null);
                                aiThreadsUsed.decrementAndGet();
                                onThreadDone(false);
                            }
                        }
                    });
                    return;
                }
                aiThreadsUsed.decrementAndGet();
            }
            if (!bLocked) {
                Object objx = linkInfos[pos].getValue(obj);
                _load(objx, pos+1);
            }
            if (bStop) return;
        }
    }


    protected void setup(Class c) {
        if (bSetup) return;
        bSetup = true;
        if (propertyPath != null || c == null) return;
        propertyPath = new OAPropertyPath(c, strPropertyPath);
        
        aiThreadsUsed.set(0); 
        aiVisitCnt.set(0);
        aiNotLoadedCnt.set(0);

        linkInfos = propertyPath.getLinkInfos();
        recursiveLinkInfos = propertyPath.getRecursiveLinkInfos();
        methods = propertyPath.getMethods();

        if (linkInfos.length != methods.length) {
            // oafinder is to get from one OAObj/Hub to another, not a property/etc
            throw new RuntimeException("propertyPath " + strPropertyPath + " must end in an OAObject/Hub");
        }

        OAObjectInfo oi = OAObjectInfoDelegate.getObjectInfo(c);
        liRecursiveRoot = oi.getRecursiveLinkInfo(OALinkInfo.MANY);

        if (linkInfos != null && linkInfos.length > 0) {
            cascades = new OACascade[linkInfos.length];
            for (int i=0; i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy