com.viaoa.object.OAFinder Maven / Gradle / Ivy
Show all versions of oa-core Show documentation
/* 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.lang.reflect.*;
import java.util.*;
import com.viaoa.filter.*;
import com.viaoa.hub.*;
import com.viaoa.util.*;
// 20140124
/**
* This is used to find all values from one OAObject/Hub to another OAObject/Hub, using a propertyPath. Support is included for Filters.
*
* @param type of hub or OAObject to use as the root (from)
* @param type of hub for the to class (to).
*
* examples:
// from Router, find all UserLogin for a userId
OAFinder f = new OAFinder(Router.P_UserLogins);
String cpp = UserLoginPP.user().userId().pp;
f.addLikeFilter(cpp, userId);
UserLogin userLogin = f.findFirst(router);
OAFinder f = new OAFinder(ProgramPP.locations().employees().pp) {
@Override
protected boolean isUsed(Employee emp) {
return super.isUsed(emp);
}
@Override
protected void onFound(Employee emp) {
//todo:
}
};
// f.setMaxFound(50);
f.addEqualFilter(EmployeePP.employeeAward().awardType().name(), "some name");
ArrayList al = f.find(program);
*/
public class OAFinder {
private String strPropertyPath;
private OAPropertyPath propertyPath;
private OALinkInfo liRecursiveRoot;
private OALinkInfo[] linkInfos;
private OALinkInfo[] recursiveLinkInfos;
private Method[] methods;
private boolean bAddOrFilter;
private boolean bAddAndFilter;
private OAFilter filter;
private OACascade[] cascades;
private volatile boolean bStop;
private ArrayList alFound;
// stack
private boolean bEnableStack;
private int stackPos;
private StackValue[] stack;
private int maxFound;
private F fromObject;
private Hub fromHub;
private boolean bUseAll;
private boolean bEnableRecursiveRoot;
private boolean bEnableRecursiveRootWasCalled;
private OACascade cascade; // cascade that can be set by calling code
/**
* flag to know if it should only find data that is currently in memory.
*/
private boolean bUseOnlyLoadedData;
public OAFinder() {
}
public OAFinder(String propPath) {
this.strPropertyPath = propPath;
}
public OAFinder(F fromObject, String propPath) {
this.fromObject = fromObject;
this.strPropertyPath = propPath;
}
public OAFinder(Hub fromHub, String propPath) {
this(fromHub, propPath, true);
}
public OAFinder(Hub fromHub, String propPath, boolean bUseAll) {
this.fromHub = fromHub;
this.strPropertyPath = propPath;
this.bUseAll = bUseAll;
}
public void setAllowRecursiveRoot(boolean b) {
this.bEnableRecursiveRoot = b;
this.bEnableRecursiveRootWasCalled = true;
}
/**
* Flag to know if the root object/hub should allow for recursive duing the find. Default is determined by the following. Default is
* false, unless hub is the root and it has a masterObject.
*/
public boolean getAllowRecursiveRoot() {
return this.bEnableRecursiveRoot;
}
/**
* Add the found object to the list that is returned by find. This can be overwritten to get all of the objects as they are found.
*
* @see stop to be able to have the find stop searching.
*/
protected void onFound(T obj) {
alFound.add(obj);
if (maxFound > 0 && alFound.size() >= maxFound) {
stop();
}
}
/**
* Called during a find when data was not found. Use stop() to have the find aborted.
*/
protected void onDataNotFound() {
}
/**
* 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 boolean getStop() {
return bStop;
}
public void setUseOnlyLoadedData(boolean b) {
this.bUseOnlyLoadedData = b;
}
// 20160306
/**
* Flag (default=false) to only use data that is already in memory and not to load from server or datasource.
*/
public boolean getUseOnlyLoadedData() {
return bUseOnlyLoadedData;
}
public void setMaxFound(int x) {
this.maxFound = x;
}
public int getMaxFound() {
return this.maxFound;
}
public ArrayList find() {
if (fromObject != null) {
return find(fromObject);
}
if (fromHub != null) {
if (bUseAll) {
return find(fromHub);
}
F obj = fromHub.getAO();
if (obj != null) {
return find(obj);
}
}
return null;
}
public void setRoot(F obj) {
this.fromObject = obj;
}
public void setRoot(Hub hub) {
this.fromHub = hub;
}
/**
* Given the propertyPath, find all of the objects from a Hub.
*/
public ArrayList find(Hub hubRoot) {
ArrayList al = find(hubRoot, null);
return al;
}
public ArrayList find(ArrayList alRoot) {
return find(alRoot, null);
}
public ArrayList find(ArrayList alRoot, F objectLastUsed) {
if (!bEnableRecursiveRootWasCalled) {
bEnableRecursiveRoot = false;
}
alFound = new ArrayList();
if (bEnableStack) {
stack = new StackValue[5];
}
if (alRoot == null) {
return alFound;
}
int x = alRoot.size();
if (x == 0) {
return alFound;
}
F sample = alRoot.get(0);
bStop = false;
setup(sample.getClass());
int pos;
if (objectLastUsed == null) {
pos = 0;
} else {
pos = alRoot.indexOf(objectLastUsed) + 1;
}
for (; pos < x; pos++) {
F objectRoot = alRoot.get(pos);
if (objectRoot == null) {
continue;
}
stackPos = 0;
performFind(objectRoot);
if (bStop) {
break;
}
}
ArrayList al = alFound;
this.alFound = null;
this.stack = null;
this.stackPos = 0;
this.cascades = null;
return al;
}
// 20171224 update threadloc.getDetail
public ArrayList find(Hub hubRoot, F objectLastUsed) {
if (!bEnableRecursiveRootWasCalled) {
if (hubRoot != null) {
OALinkInfo li = HubDetailDelegate.getLinkInfoFromMasterObjectToDetail(hubRoot);
if (li != null && li.getRecursive()) {
bEnableRecursiveRoot = true;
}
} else {
bEnableRecursiveRoot = true;
}
}
ArrayList al = null;
OASiblingHelper siblingHelper = null;
if (!bUseOnlyLoadedData) {
siblingHelper = new OASiblingHelper(hubRoot);
siblingHelper.add(strPropertyPath);
OAThreadLocalDelegate.addSiblingHelper(siblingHelper);
}
try {
al = _find(hubRoot, objectLastUsed);
} finally {
if (siblingHelper != null) {
OAThreadLocalDelegate.removeSiblingHelper(siblingHelper);
}
}
return al;
}
private int rootHubPos;
public int getRootHubPos() {
return this.rootHubPos;
}
/**
* Given the propertyPath, find all of the objects from a Hub, starting after objectLastFound
*/
protected ArrayList _find(Hub hubRoot, F objectLastUsed) {
alFound = new ArrayList();
if (bEnableStack) {
stack = new StackValue[5];
}
if (hubRoot == null) {
return alFound;
}
rootHubPos = -1;
bStop = false;
setup(hubRoot.getObjectClass());
if (objectLastUsed == null) {
rootHubPos = 0;
} else {
rootHubPos = hubRoot.getPos(objectLastUsed) + 1;
}
for (;; rootHubPos++) {
F objectRoot = hubRoot.getAt(rootHubPos);
if (objectRoot == null) {
break;
}
stackPos = 0;
performFind(objectRoot);
if (bStop) {
break;
}
}
ArrayList al = alFound;
this.alFound = null;
this.stack = null;
this.stackPos = 0;
cascades = null;
return al;
}
public void clearFilters() {
filter = null;
}
public void addFilter(OAFilter filter) {
if (this.filter == null) {
this.filter = filter;
} else {
if (bAddOrFilter) {
this.filter = new OAOrFilter(this.filter, filter);
} else {
this.filter = new OAAndFilter(this.filter, filter);
}
}
bAddAndFilter = bAddOrFilter = false;
}
public OAFilter getFilter() {
return this.filter;
}
public void setFilter(OAFilter f) {
this.filter = f;
}
/**
* Returns true if a matching value is found.
*/
public boolean canFindFirst(F objectRoot) {
int holdMax = getMaxFound();
setMaxFound(1);
ArrayList al = find(objectRoot);
if (getMaxFound() == 1) {
setMaxFound(holdMax);
}
return (al != null && al.size() > 0);
}
public T findFirst() {
if (fromObject != null) {
return findFirst(fromObject);
}
if (fromHub != null) {
if (bUseAll) {
return findFirst(fromHub);
}
F obj = fromHub.getAO();
if (obj != null) {
return findFirst(obj);
}
}
return null;
}
/**
* Finds the first matching value. If searching for a null, then this would return a null, so use the canFindFirst method instead.
*/
public T findFirst(F objectRoot) {
if (objectRoot == null) {
return null;
}
int holdMax = getMaxFound();
setMaxFound(1);
ArrayList al = find(objectRoot);
T obj;
if (al != null && al.size() > 0) {
obj = al.get(0);
} else {
obj = null;
}
if (getMaxFound() == 1) {
setMaxFound(holdMax);
}
return obj;
}
public T findFirst(Hub hub) {
int holdMax = getMaxFound();
setMaxFound(1);
ArrayList al = find(hub);
T obj;
if (al.size() > 0) {
obj = al.get(0);
} else {
obj = null;
}
if (getMaxFound() == 1) {
setMaxFound(holdMax);
}
return obj;
}
public T findNext(Hub hub, F objectLastUsed) {
int holdMax = getMaxFound();
setMaxFound(1);
ArrayList al = find(hub, objectLastUsed);
T obj;
if (al.size() > 0) {
obj = al.get(0);
} else {
obj = null;
}
if (getMaxFound() == 1) {
setMaxFound(holdMax);
}
return obj;
}
public T findLast() {
ArrayList al = find();
if (al == null) return null;
int x = al.size();
if (x == 0) return null;
return al.get(x-1);
}
public T findLast(F objectRoot) {
ArrayList al = find(objectRoot);
if (al == null) return null;
int x = al.size();
if (x == 0) return null;
return al.get(x-1);
}
public T findLast(Hub hub) {
ArrayList al = find(hub);
if (al == null) return null;
int x = al.size();
if (x == 0) return null;
return al.get(x-1);
}
static protected abstract class CompareFilter implements OAFilter {
final String pp;
Object objFound;
Object valueFound;
boolean bCancel;
public CompareFilter(final String pp) {
this.pp = pp;
}
@Override
public boolean isUsed(final Object obj) {
if (bCancel) return true;
if (!(obj instanceof OAObject)) return false;
Object objValue = ((OAObject)obj).getProperty(pp);
if (objFound == null) {
objFound = obj;
valueFound = objValue;
return true;
}
int x = OACompare.compare(objValue, valueFound);
if (isCompareUsed(x)) {
objFound = obj;
valueFound = objValue;
return true;
}
return false;
}
protected void cancel() {
this.bCancel = true;
}
abstract boolean isCompareUsed(int compareValue);
}
public T findLargest(final String pp) {
CompareFilter cf = new CompareFilter(pp) {
@Override
boolean isCompareUsed(int compareValue) {
return compareValue >= 0;
}
};
addFilter(cf);
T t = findLast();
cf.cancel();
return t;
}
public T findLargest(F objectRoot, String pp) {
CompareFilter cf = new CompareFilter(pp) {
@Override
boolean isCompareUsed(int compareValue) {
return compareValue >= 0;
}
};
addFilter(cf);
T t = findLast(objectRoot);
cf.cancel();
return t;
}
public T findLargest(Hub hub, String pp) {
CompareFilter cf = new CompareFilter(pp) {
@Override
boolean isCompareUsed(int compareValue) {
return compareValue >= 0;
}
};
addFilter(cf);
T t = findLast(hub);
cf.cancel();
return t;
}
public T findSmallest(final String pp) {
CompareFilter cf = new CompareFilter(pp) {
@Override
boolean isCompareUsed(int compareValue) {
return compareValue <= 0;
}
};
addFilter(cf);
T t = findLast();
cf.cancel();
return t;
}
public T findSmallest(F objectRoot, String pp) {
CompareFilter cf = new CompareFilter(pp) {
@Override
boolean isCompareUsed(int compareValue) {
return compareValue <= 0;
}
};
addFilter(cf);
T t = findLast(objectRoot);
cf.cancel();
return t;
}
public T findSmallest(Hub hub, String pp) {
CompareFilter cf = new CompareFilter(pp) {
@Override
boolean isCompareUsed(int compareValue) {
return compareValue <= 0;
}
};
addFilter(cf);
T t = findLast(hub);
cf.cancel();
return t;
}
static protected class DuplicateFilter implements OAFilter {
final String pp;
boolean bCancel;
final Map