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

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

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.object;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Logger;

import com.viaoa.datasource.OADataSource;
import com.viaoa.datasource.OASelect;
import com.viaoa.datasource.jdbc.OADataSourceJDBC;
import com.viaoa.datasource.jdbc.db.ManyToMany;
import com.viaoa.hub.Hub;
import com.viaoa.util.OAPropertyPath;
import com.viaoa.util.OAString;

/* This is used to preload objects.
 *
 * Compared to OALoader, which loads objects by following a root object or Hub, and then goes through calling all of the methods in the property path.
 * ex:  Customers.Orders.Items.products
 * This can lead to a lot of calls to DS.
 *
 * OAPreLoader is used when loading all objects, so that it can first preload the objects in the property path, and then use the cached objects to set
 * the property values.
 *
 * This will load and set recursive properties, M2M properties.
 *
 * Ex: from class: ItemCategory, pp: items.products
 *  where itemCategory is recursive and itemCategory.items is M2M
 *
 * */
public class OAPreLoader {
	private static Logger LOG = Logger.getLogger(OAPreLoader.class.getName());

	private Class classFrom;
	private String strPropertyPath;

	/**
	 * Create a new pre loader. Call load method to run.
	 *
	 * @param classFrom base/root class for property path
	 * @param propPath  property path to load. Note: all links need to be of type Many
	 */
	public OAPreLoader(Class classFrom, String propPath) {
		this.classFrom = classFrom;
		this.strPropertyPath = propPath;
	}

	/**
	 * load the property path.
	 *
	 * @return objects load from classFrom, so that gc does not remove objects from OAObjectCache
	 */
	public ArrayList load() {
		if (classFrom == null) {
			return null;
		}

		OAPropertyPath propertyPath = null;
		OALinkInfo[] linkInfos = null;

		if (OAString.isNotEmpty(strPropertyPath)) {
			propertyPath = new OAPropertyPath(classFrom, strPropertyPath);
			linkInfos = propertyPath.getLinkInfos();
		}
		ArrayList al = null;
		try {
			OAThreadLocalDelegate.setLoading(true);
			al = _load(linkInfos);
		} finally {
			OAThreadLocalDelegate.setLoading(false);
		}
		return al;
	}

	protected ArrayList _load(OALinkInfo[] linkInfos) {
		final HashMap hm = new HashMap<>();

		final ArrayList al = load(classFrom, null);
		hm.put(classFrom, al);

		if (linkInfos != null) {
			for (OALinkInfo linkInfo : linkInfos) {
				Class c = linkInfo.getToClass();

				if (linkInfo.getType() != OALinkInfo.MANY) {
					break;
				}

				ArrayList alx = hm.get(c);
				if (alx == null) {
					alx = load(c, linkInfo);
					hm.put(c, alx);
				}

				if (linkInfo.isMany2Many()) {
					loadMtoM(linkInfo);
				} else {
					loadOtoM(linkInfo, alx);
				}
			}
		}
		return al;
	}

	protected void loadOtoM(OALinkInfo linkInfo, ArrayList alMany) {
		if (linkInfo == null || linkInfo.getType() != OALinkInfo.MANY) {
			return;
		}
		if (linkInfo.getPrivateMethod()) {
			return;
		}

		OALinkInfo liMany = linkInfo;
		OALinkInfo liOne = linkInfo.getReverseLinkInfo();
		if (liOne == null || liOne.getType() != OALinkInfo.ONE) {
			return;
		}

		for (Object objFromMany : alMany) {
			Object objOne = ((OAObject) objFromMany).getProperty(liOne.getName());
			if (!(objOne instanceof OAObject)) {
				continue;
			}

			Hub hub;
			Object objOneHub = OAObjectPropertyDelegate.getProperty((OAObject) objOne, liMany.getName(), false, true);
			if (objOneHub instanceof Hub) {
				hub = (Hub) objOneHub;
			} else {
				hub = new Hub(liMany.getToClass());
				OAObjectPropertyDelegate.setProperty((OAObject) objOne, liMany.getName(), hub);
			}
			hub.add(objFromMany);
		}
	}

	protected void loadMtoM(OALinkInfo linkInfo) {
		if (linkInfo == null || !linkInfo.isMany2Many()) {
			return;
		}
		OADataSource ds = OADataSource.getDataSource(linkInfo.getToClass());
		if (!(ds instanceof OADataSourceJDBC)) {
			return;
		}

		OALinkInfo liA = linkInfo;
		OALinkInfo liB = linkInfo.getReverseLinkInfo();
		if (liB == null) {
			return;
		}

		Class classA = liB.getToClass();
		Class classB = liA.getToClass();

		ArrayList alManyToMany = ((OADataSourceJDBC) ds).getManyToMany(linkInfo);
		if (alManyToMany == null) {
			return;
		}

		for (ManyToMany mm : alManyToMany) {
			Object objA = OAObjectCacheDelegate.get(classA, mm.ok1);
			Object objB = OAObjectCacheDelegate.get(classB, mm.ok2);
			if (objA == null || objB == null) {
				continue;
			}

			if (!liA.getPrivateMethod()) {
				Hub hub;
				Object objx = OAObjectPropertyDelegate.getProperty((OAObject) objA, liA.getName(), false, true);
				if (objx instanceof Hub) {
					hub = (Hub) objx;
				} else {
					hub = new Hub(classB);
					OAObjectPropertyDelegate.setProperty((OAObject) objA, liA.getName(), hub);
				}
				hub.add(objB);
			}

			if (!liB.getPrivateMethod()) {
				Hub hub;
				Object objx = OAObjectPropertyDelegate.getProperty((OAObject) objB, liB.getName(), false, true);
				if (objx instanceof Hub) {
					hub = (Hub) objx;
				} else {
					hub = new Hub(classA);
					OAObjectPropertyDelegate.setProperty((OAObject) objB, liB.getName(), hub);
				}
				hub.add(objA);
			}
		}
	}

	// 1toM recursive - load all then populate f.hubChildren
	protected ArrayList load(Class clazz, final OALinkInfo linkInfo) {
		OASelect sel = new OASelect<>(clazz);
		OAObjectInfo oi = OAObjectInfoDelegate.getObjectInfo(clazz);
		OALinkInfo liRecursive = OAObjectInfoDelegate.getRecursiveLinkInfo(oi, OALinkInfo.MANY);

		String sortOrder = null;
		if (liRecursive != null) {
			OALinkInfo liRev = liRecursive.getReverseLinkInfo();
			if (liRev != null) {
				sortOrder = liRecursive.getSortProperty();
			}
		}
		if (sortOrder == null && linkInfo != null) {
			sortOrder = linkInfo.getSortProperty();
		}
		if (OAString.isNotEmpty(sortOrder)) {
			sel.setOrder(sortOrder);
		}

		ArrayList al = new ArrayList<>();
		for (;;) {
			Object obj = sel.next();
			if (obj == null) {
				break;
			}
			al.add(obj);
		}

		if (liRecursive != null) {
			loadRecursive(clazz, al, liRecursive);

			// might need to reselect if both had different sortOrder
			String s = liRecursive.getSortProperty();
			if (linkInfo != null && OAString.isNotEmpty(s)) {
				String s2 = linkInfo.getSortProperty();
				if (OAString.isNotEmpty(s2)) {
					if (!OAString.isEqual(s, s2, true)) {
						sel = new OASelect<>(clazz);
						sel.setOrder(s);
						al = new ArrayList<>();
						for (;;) {
							Object obj = sel.next();
							if (obj == null) {
								break;
							}
							al.add(obj);
						}
					}
				}
			}
		}
		return al;
	}

	protected void loadRecursive(Class clazz, ArrayList al, OALinkInfo liMany) {
		if (liMany == null) {
			return;
		}
		OALinkInfo liOne = liMany.getReverseLinkInfo();
		if (liOne == null) {
			return;
		}

		for (Object f : al) {
			Object fParent = liOne.getValue(f);
			if (!(fParent instanceof OAObject)) {
				continue;
			}

			Hub hub;
			Object objx = OAObjectPropertyDelegate.getProperty((OAObject) fParent, liMany.getName(), false, true);
			if (objx instanceof Hub) {
				hub = (Hub) objx;
			} else {
				hub = new Hub(clazz);
				OAObjectPropertyDelegate.setProperty((OAObject) fParent, liMany.getName(), hub);
			}
			hub.add(f);
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy