
com.viaoa.hub.HubGroupBy 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.hub;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import com.viaoa.object.OAGroupBy;
import com.viaoa.object.OALinkInfo;
import com.viaoa.object.OAObject;
import com.viaoa.object.OAObjectInfo;
import com.viaoa.object.OAObjectInfoDelegate;
import com.viaoa.object.OAThreadLocalDelegate;
import com.viaoa.util.OAPropertyPath;
import com.viaoa.util.OAString;
/**
* Combines a hub into a new single hub to create the equivalent of a database groupBy.
*
* The combined Hub (see getCombinedHub) uses OAObject OAGroupBy<F, G>, where G is the same class as the
* groupBy Hub and F is a hub of the from objects.
*
*
* // group Employees by Dept
* new HubGroupBy<Emp, Dept>(hubEmp, hubAllDept, "depts") new HubGroupBy<Emp, Dept>(hubEmp, "depts")
*
* Split property path - this is when all of the methods in a pp are not public (link that does not
* create method). HubGroupBy is able to group them by splitting the pp using HubGroupBy and HubFrom to get a
* combined group. ex: MRADClient.Application.ApplicationType.ApplicationGroup, hubFrom=hubMRADClients,
* hubGroupBy=hubApplicationGroups note: the method for ApplicationType.getApplicationGroups() is not created
* (is private)
*
* new HubGroupBy(hubMRADClients, hubApplicationGroups, "MRADClient.Application.ApplicationType.ApplicationGroup")
*
* internally will create 2 HubGroupBys ... (hubMRADClients, "MRADClient.Application.ApplicationType")
* (hubApplicationGroups, "ApplicationTypes")
*
* @see HubLeftJoin to create a "flat" list.
* @author vvia
*/
public class HubGroupBy {
// from hub that are to be grouped
private Hub hubFrom;
private final Class classFrom;
private Class classGroupBy;
// optional hub to use as groupBy list. Required if the propertyPath has a "split/gap" (method does not exist)
private Hub hubGroupBy;
// result hub
private Hub> hubCombined;
private String propertyPath;
// internal calc prop created (if needed)
private String listenPropertyName;
private Hub hubMaster;
private Hub hubDetail;
private boolean bIgnoreAOChange;
private boolean bCreateNullList;
// used to name internally created calcProps
private final static AtomicInteger aiCnt = new AtomicInteger();
/**
* Create a hub of objects that are based on hubB.
*
* @param hubB
* @param propertyPath
*/
public HubGroupBy(Hub hubB, String propertyPath, boolean bCreateNullList) {
this.hubGroupBy = null;
this.hubFrom = hubB;
this.classFrom = hubB.getObjectClass();
this.classGroupBy = null;
this.propertyPath = propertyPath;
this.bCreateNullList = bCreateNullList;
setup();
}
public HubGroupBy(Hub hubB, String propertyPath) {
this(hubB, propertyPath, true);
}
/**
* Create a hub on objects that are based on hubB, and are grouped by hubA. This allows a the
* combined hub to have a full list like a left-join.
* @param propertyPath
* pp of the property from the right object to get left object. example: if hubDept,
* hubEmpOrders, then "Employee.Department" HubGroupBy(hubEmpOrders, hubDept,
* "Employee.Department") -or- HubGroupBy(hubEmpOrders, "Employee.Department")
*/
public HubGroupBy(Hub hubB, Hub hubFrom, String propertyPath, boolean bCreateNullList) {
this.hubGroupBy = hubFrom;
this.hubFrom = hubB;
this.classFrom = hubB.getObjectClass();
this.classGroupBy = null;
this.propertyPath = propertyPath;
this.bCreateNullList = bCreateNullList;
setup();
}
public HubGroupBy(Hub hubB, Hub hubFrom, String propertyPath) {
this(hubB, hubFrom, propertyPath, true);
}
/**
* Combine two hgbs.
*/
public HubGroupBy(HubGroupBy hgb1, HubGroupBy hgb2, boolean bCreateNullList) {
if (hgb1 == null || hgb2 == null) throw new IllegalArgumentException("hgb1 & hgb2 can not be null");
this.bCreateNullList = bCreateNullList;
this.classFrom = hgb1.classFrom;
this.classGroupBy = hgb1.classGroupBy;
setupCombined(hgb1, hgb2);
}
public HubGroupBy(HubGroupBy hgb1, HubGroupBy hgb2) {
this(hgb1, hgb2, true);
}
/**
* create a new hgb that creates a combined groupBy with another.
*/
public HubGroupBy(HubGroupBy hgb, String pp, boolean bCreateNullList) {
if (hgb == null) throw new IllegalArgumentException("hgb can not be null");
this.classFrom = hgb.classFrom;
this.classGroupBy = null;
this.bCreateNullList = bCreateNullList;
HubGroupBy hgb2 = new HubGroupBy(hgb.hubFrom, pp, bCreateNullList);
setupCombined(hgb, hgb2);
}
public HubGroupBy(HubGroupBy hgb, String pp) {
this(hgb, pp, true);
}
/**
* @return Hub of combined objects using OAGroupBy
*/
public Hub> getCombinedHub() {
if (hubCombined != null) return hubCombined;
hubCombined = new Hub(OAGroupBy.class);
return hubCombined;
}
/**
* @return Hub of groupBy objects that are in sync (share AO) with combined Hub.
*/
public Hub getMasterHub() {
if (hubMaster == null) {
if (hubGroupBy != null) hubMaster = new Hub(hubGroupBy.getObjectClass());
else hubMaster = new Hub();
new HubMerger(getCombinedHub(), hubMaster, OAGroupBy.P_GroupBy, true);
hubMaster.addHubListener(new HubListenerAdapter() {
@Override
public void afterChangeActiveObject(HubEvent e) {
if (bIgnoreAOChange) return;
try {
bIgnoreAOChange = true;
final Object ao = e.getObject();
hubFrom.setAO(null);
if (hubDetail != null) hubDetail.setAO(null);
if (ao == null) {
getCombinedHub().setAO(null);
}
else {
boolean bFound = false;
for (OAGroupBy bg : getCombinedHub()) {
if (bg.getGroupBy() == ao) {
getCombinedHub().setAO(bg);
bFound = true;
break;
}
}
if (!bFound) {
getCombinedHub().setAO(null);
}
}
}
finally {
bIgnoreAOChange = false;
}
}
@Override
public void afterAdd(HubEvent e) {
if (classGroupBy == null) classGroupBy = (Class) e.getObject().getClass();
}
});
}
return hubMaster;
}
/**
* @return detail hub from compoundHub.hub
*/
public Hub getDetailHub() {
if (hubDetail == null) {
hubDetail = getCombinedHub().getDetailHub(OAGroupBy.P_Hub);
HubDelegate.setObjectClass(hubDetail, classFrom);
hubDetail.addHubListener(new HubListenerAdapter() {
@Override
public void afterChangeActiveObject(HubEvent e) {
if (bIgnoreAOChange) return;
try {
bIgnoreAOChange = true;
hubFrom.setAO(e.getObject());
}
finally {
bIgnoreAOChange = false;
}
}
});
}
return hubDetail;
}
void setup() {
OAPropertyPath opp = new OAPropertyPath(propertyPath);
try {
opp.setup(classFrom, (hubGroupBy != null));
}
catch (Exception e) {
throw new RuntimeException("PropertyPath setup failed", e);
}
OALinkInfo[] lis = opp.getLinkInfos();
Method[] ms = opp.getMethods();
int posEmpty = 0;
for (Method m : ms) {
if (m == null) break;
posEmpty++;
}
if (posEmpty >= ms.length || hubGroupBy == null) {
setupMain();
return; // does not need to be split
}
// need to have a 2way propPath, one from rootHub, and another from topDown hub
String pp1 = OAString.field(propertyPath, ".", 1, posEmpty);
String pp2 = "";
for (int i = ms.length - 1; i >= posEmpty; i--) {
if (pp2.length() > 0) pp2 += ".";
pp2 += lis[i].getReverseName();
}
hgb1 = new HubGroupBy(hubFrom, pp1, bCreateNullList);
hubGB1 = hgb1.getCombinedHub();
hgb2 = new HubGroupBy(hubGroupBy, pp2, bCreateNullList);
hubGB2 = hgb2.getCombinedHub();
setupSplit();
}
// used by propertyPath that require a split
private HubGroupBy hgb1;
private Hub hubGB1;
private HubGroupBy hgb2;
private Hub hubGB2;
/* This is used to define the structure that is created for the split.
*
Original HubGroupBy new HubGroupBy(hubApplicationGroup, hubMRADClient, "MRADClient.Application.ApplicationType.ApplicationGroup")
Split:
GB1: new HubGroupBy(hubMRADClient, "MRADClient.Application.ApplicationType")
GB2: new HubGroupBy(hubApplicationGroup, "ApplicationTypes")
GBNew: hubCombined is updated using setupSlit
OAGroupBy GB1 GB2 GBNew
.A appType appType appGroup
.hubB mrads appGroups mrads
* This is used when a propertyPath has a link where one of the createMethod=false. By having the source hub
* for the leftmost HubB, and must also have the source HubA for the rightmost, two separate hgb can be used to update a 3rd
* hgb. This will set up the listeners for hgb1 & hgb2 to update this.hubCombined.
*/
private void setupSplit() {
// A: hubGroup1 (hgb1) left part of pp, using hubB as the root
// A.1: listen to hgb1 add/removes and update this.hubCombined
hubGB1.addHubListener(new HubListenerAdapter() {
@Override
public void afterInsert(HubEvent e) {
afterAdd(e);
}
@Override
public void afterAdd(HubEvent e) {
OAGroupBy gb1 = (OAGroupBy) e.getObject();
if (gb1.getHub().size() == 0) return;
final Object gb1A = gb1.getGroupBy();
OAGroupBy gb2Found = null;
if (gb1A != null) {
for (OAGroupBy gb2 : hubGB2) {
if (gb2.getGroupBy() == gb1A) {
gb2Found = gb2;
break;
}
}
}
if (gb2Found == null || gb2Found.getHub().getSize() == 0) {
// add to empty list
if (!bCreateNullList) return;
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == null) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) {
gbNewFound = createGroupBy(null);
HubGroupBy.this.getCombinedHub().add(gbNewFound);
}
for (Object gb1B : gb1.getHub()) {
gbNewFound.getHub().add(gb1B);
}
return;
}
for (Object gb2B : gb2Found.getHub()) {
OAObject objGB2b = (OAObject) gb2B;
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == objGB2b) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) {
gbNewFound = createGroupBy((G) objGB2b);
HubGroupBy.this.getCombinedHub().add(gbNewFound);
}
for (Object gb1B : gb1.getHub()) {
gbNewFound.getHub().add(gb1B);
}
}
// remove from gbNew.A=null hubB
if (!bCreateNullList) return;
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == null) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound != null) {
for (Object gb1B : gb1.getHub()) {
gbNewFound.getHub().remove(gb1B);
}
}
}
Object[] removeObjects;
@Override
public void beforeRemoveAll(HubEvent e) {
removeObjects = hubGB1.toArray();
}
@Override
public void afterRemoveAll(HubEvent e) {
for (Object obj : removeObjects) {
remove((OAGroupBy) obj);
}
removeObjects = null;
}
@Override
public void afterRemove(HubEvent e) {
OAGroupBy gb1 = (OAGroupBy) e.getObject();
if (gb1.getHub().size() == 0) return;
remove(gb1);
}
void remove(OAGroupBy gb1) {
final OAObject gb1A = gb1.getGroupBy();
OAGroupBy gb2Found = null;
if (gb1A != null) {
for (OAGroupBy gb2 : hubGB2) {
if (gb2.getGroupBy() == gb1A) {
gb2Found = gb2;
break;
}
}
}
if (gb2Found == null || gb2Found.getHub().getSize() == 0) {
// remove from empty list
if (!bCreateNullList) return;
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == null) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) return;
for (Object gb1B : gb1.getHub()) {
gbNewFound.getHub().remove(gb1B);
}
return;
}
for (Object gb2B : gb2Found.getHub()) {
OAObject objGB2b = (OAObject) gb2B;
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == objGB2b) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) continue;
for (Object gb1B : gb1.getHub()) {
gbNewFound.getHub().remove(gb1B);
}
}
// see if it needs to be added to gbNew.A=null hubB
if (!bCreateNullList) return;
OAGroupBy gbNewFound = null;
for (Object gb1B : gb1.getHub()) {
if (!hubFrom.contains(gb1B)) continue; // no longer in the From list
boolean bFound = false;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == null) {
gbNewFound = gbNew;
continue;
}
if (gbNew.getHub().contains(gb1B)) {
bFound = true;
break;
}
}
if (bFound) continue;
if (gbNewFound == null) {
gbNewFound = createGroupBy(null);
HubGroupBy.this.getCombinedHub().add(gbNewFound);
}
gbNewFound.getHub().add(gb1B);
}
}
});
// A.2: listen to changes to hgb1.hubB changes by using a hubmerger to get add/remove events and update this.hubCombined
Hub hubTemp = new Hub(OAObject.class);
HubMerger hm1 = new HubMerger(hubGB1, hubTemp, OAGroupBy.P_Hub, true) {
@Override
protected void afterInsertRealHub(HubEvent e) {
afterAddRealHub(e);
}
@Override
protected void afterAddRealHub(HubEvent e) {
OAGroupBy gb = (OAGroupBy) ((Hub) e.getSource()).getMasterObject();
final OAObject gb1A = gb.getGroupBy();
Object gb1B = e.getObject(); // object added
OAGroupBy gb2Found = null;
if (gb1A != null) {
for (OAGroupBy gb2 : hubGB2) {
if (gb2.getGroupBy() == gb1A) {
gb2Found = gb2;
break;
}
}
}
if (gb2Found == null || gb2Found.getHub().getSize() == 0) {
// add to empty list
if (!bCreateNullList) return;
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == null) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) {
gbNewFound = createGroupBy(null);
HubGroupBy.this.getCombinedHub().add(gbNewFound);
}
gbNewFound.getHub().add(gb1B);
return;
}
for (Object gb2B : gb2Found.getHub()) {
OAObject objGB2b = (OAObject) gb2B;
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == objGB2b) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) {
gbNewFound = createGroupBy((G) objGB2b);
HubGroupBy.this.getCombinedHub().add(gbNewFound);
}
gbNewFound.getHub().add(gb1B);
}
//remove from null hub
if (!bCreateNullList) return;
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == null) {
gbNew.getHub().remove(gb1B);
break;
}
}
}
private Object[] removeAllObjects;
@Override
protected void beforeRemoveAllRealHub(HubEvent e) {
removeAllObjects = ((Hub) e.getSource()).toArray();
}
@Override
protected void afterRemoveAllRealHub(HubEvent e) {
if (removeAllObjects == null) return;
OAGroupBy gb1 = (OAGroupBy) ((Hub) e.getSource()).getMasterObject();
for (Object obj: removeAllObjects) {
remove(gb1, (OAGroupBy) obj);
}
removeAllObjects = null;
}
@Override
protected void afterRemoveRealHub(HubEvent e) {
OAGroupBy gb1 = (OAGroupBy) ((Hub) e.getSource()).getMasterObject();
Object gb1B = e.getObject();
remove(gb1, gb1B);
}
void remove(final OAGroupBy gb1, final Object gb1B) {
final OAObject gb1A = gb1.getGroupBy();
OAGroupBy gb2Found = null;
if (gb1A != null) {
for (OAGroupBy gb2 : hubGB2) {
if (gb2.getGroupBy() == gb1A) {
gb2Found = gb2;
break;
}
}
}
if (gb2Found == null || gb2Found.getHub().getSize() == 0) {
// remove from empty list
if (!bCreateNullList) return;
if (hgb1.hubFrom.contains(gb1B)) return;
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == null) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) return;
gbNewFound.getHub().remove(gb1B);
return;
}
for (Object gb2B : gb2Found.getHub()) {
OAObject objGB2b = (OAObject) gb2B;
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == objGB2b) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) continue;
gbNewFound.getHub().remove(gb1B);
}
if (!HubGroupBy.this.hubFrom.contains(gb1B)) {
return;
}
// see if it needs to be added to gbNew.A=null hubB
if (!bCreateNullList) return;
OAGroupBy gbNewFound = null;
boolean bFound = false;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == null) {
gbNewFound = gbNew;
continue;
}
if (gbNew.getHub().contains(gb1B)) {
bFound = true;
break;
}
}
if (!bFound) {
if (gbNewFound == null) {
gbNewFound = createGroupBy(null);
HubGroupBy.this.getCombinedHub().add(gbNewFound);
}
gbNewFound.getHub().add(gb1B);
}
}
};
// B: hubGroup2 (hgb2) right reverse part of pp, using hubA as the root
// B.1: listen to hgb2 add/removes and update this.hubCombined
// listen to GB2
hubGB2.addHubListener(new HubListenerAdapter() {
@Override
public void afterInsert(HubEvent e) {
afterAdd(e);
}
@Override
public void afterAdd(HubEvent e) {
OAGroupBy gb2 = (OAGroupBy) e.getObject();
final OAObject gb2A = gb2.getGroupBy();
OAGroupBy gb1Found = null;
if (gb2A != null) {
for (OAGroupBy gb1 : hubGB1) {
if (gb1.getGroupBy() == gb2A) {
gb1Found = gb1;
break;
}
}
}
if (gb1Found == null) {
for (Object gb2B : gb2.getHub()) {
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == gb2B) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) {
gbNewFound = createGroupBy((G) gb2B);
HubGroupBy.this.getCombinedHub().add(gbNewFound);
}
}
return;
}
for (Object gb2B : gb2.getHub()) {
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == gb2B) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) {
gbNewFound = createGroupBy((G) gb2B);
HubGroupBy.this.getCombinedHub().add(gbNewFound);
}
for (Object gb1B : gb1Found.getHub()) {
gbNewFound.getHub().add(gb1B);
}
// might have been in gbNew.A=null gbNew.hubB
if (!bCreateNullList) continue;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == null) {
for (Object gb1B : gb1Found.getHub()) {
gbNew.getHub().remove(gb1B);
}
break;
}
}
}
}
Object[] removeObjects;
@Override
public void beforeRemoveAll(HubEvent e) {
removeObjects = hubGB2.toArray();
}
@Override
public void afterRemoveAll(HubEvent e) {
for (Object obj : removeObjects) {
remove((OAGroupBy) obj);
}
removeObjects = null;
}
@Override
public void afterRemove(HubEvent e) {
OAGroupBy gb2 = (OAGroupBy) e.getObject();
remove(gb2);
}
void remove(OAGroupBy gb2) {
final Object gb2A = gb2.getGroupBy();
OAGroupBy gb1Found = null;
if (gb2A != null) {
for (OAGroupBy gb1 : hubGB1) {
if (gb1.getGroupBy() == gb2A) {
gb1Found = gb1;
break;
}
}
}
if (gb1Found == null || gb1Found.getHub().getSize() == 0) {
for (Object gb2B : gb2.getHub()) {
if (hubGroupBy != null && hubGroupBy.contains(gb2B)) continue;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == gb2B) {
if (gbNew.getHub().size() == 0) HubGroupBy.this.getCombinedHub().remove(gbNew);
break;
}
}
}
return;
}
for (Object gb2B : gb2.getHub()) {
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == gb2B) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) {
if (!bCreateNullList) continue;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == null) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) continue;
}
for (Object gb1B : gb1Found.getHub()) {
// ??? note: dont remove from hubB if it's still used for another path
gbNewFound.getHub().remove(gb1B);
}
if (gbNewFound.getHub().size() == 0) {
if (hubGroupBy == null || !hubGroupBy.contains(gbNewFound.getGroupBy())) {
HubGroupBy.this.getCombinedHub().remove(gbNewFound);
}
}
// add to gbNew.A=null gbNew.hubB
if (!bCreateNullList) continue;
gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == null) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) {
gbNewFound = createGroupBy(null);
HubGroupBy.this.getCombinedHub().add(gbNewFound);
}
for (Object gb1B : gb1Found.getHub()) {
gbNewFound.getHub().add(gb1B);
}
}
}
});
// B.2: listen to changes to hgb2.hubB changes by using a hubmerger to get add/remove events and update this.hubCombined
Hub hubTemp2 = new Hub(OAObject.class);
HubMerger hm2 = new HubMerger(hubGB2, hubTemp2, OAGroupBy.P_Hub, true) {
@Override
protected void afterInsertRealHub(HubEvent e) {
afterAddRealHub(e);
}
@Override
protected void afterAddRealHub(HubEvent e) {
OAGroupBy gb2 = (OAGroupBy) ((Hub) e.getSource()).getMasterObject();
final Object gb2A = gb2.getGroupBy();
Object gb2B = e.getObject(); // object added
OAGroupBy gb1Found = null;
if (gb2A != null) {
for (OAGroupBy gb1 : hubGB1) {
if (gb1.getGroupBy() == gb2A) {
gb1Found = gb1;
break;
}
}
}
if (gb1Found == null) {
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == gb2B) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) {
gbNewFound = createGroupBy((G) gb2B);
HubGroupBy.this.getCombinedHub().add(gbNewFound);
}
return;
}
OAGroupBy gbNewFound = null;
OAGroupBy gbNewNullFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == null) {
gbNewNullFound = gbNew;
if (gbNewFound != null) break;
}
else if (gbNew.getGroupBy() == gb2B) {
gbNewFound = gbNew;
if (gbNewNullFound != null) break;
}
}
if (gbNewFound == null) {
gbNewFound = createGroupBy((G) gb2B);
HubGroupBy.this.getCombinedHub().add(gbNewFound);
}
if (gb1Found == null) return;
for (Object gb1B : gb1Found.getHub()) {
gbNewFound.getHub().add(gb1B);
// remove from null hub
if (gbNewNullFound != null) {
gbNewNullFound.getHub().remove(gb1B);
}
}
}
private Object[] removeAllObjects;
@Override
protected void beforeRemoveAllRealHub(HubEvent e) {
removeAllObjects = ((Hub) e.getSource()).toArray();
}
@Override
protected void afterRemoveAllRealHub(HubEvent e) {
if (removeAllObjects == null) return;
OAGroupBy gb2 = (OAGroupBy) ((Hub) e.getSource()).getMasterObject();
for (Object obj: removeAllObjects) {
remove(gb2, (OAGroupBy) obj);
}
removeAllObjects = null;
}
@Override
protected void afterRemoveRealHub(HubEvent e) {
OAGroupBy gb2 = (OAGroupBy) ((Hub) e.getSource()).getMasterObject();
Object gb2B = e.getObject();
remove(gb2, gb2B);
}
void remove(OAGroupBy gb2, final Object gb2B) {
final Object gb2A = gb2.getGroupBy();
if (gb2A == null) {
boolean bFound = false;
for (OAGroupBy gb : hubGB2) {
if (gb.getGroupBy() == null) continue;
if (gb.getHub().contains(gb2B)) {
bFound = true;
break;
}
}
if (!bFound) {
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == gb2B) {
if (gbNew.getHub().size() == 0) {
HubGroupBy.this.getCombinedHub().remove(gbNew);
}
break;
}
}
}
return;
}
OAGroupBy gb1Found = null;
for (OAGroupBy gb1 : hubGB1) {
if (gb1.getGroupBy() == gb2A) {
gb1Found = gb1;
break;
}
}
if (gb1Found == null || gb1Found.getHub().getSize() == 0) {
if (hubGroupBy.contains(gb2B)) return;
}
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == gb2B) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) return;
if (gb1Found != null) {
for (Object gb1B : gb1Found.getHub()) {
// ??? note: dont remove from hubB if it's still used for another path
gbNewFound.getHub().remove(gb1B);
}
}
if (gbNewFound.getHub().size() == 0) {
if (hubGroupBy == null || !hubGroupBy.contains(gbNewFound.getGroupBy())) {
HubGroupBy.this.getCombinedHub().remove(gbNewFound);
}
}
if (!bCreateNullList) return;
if (gb1Found != null && gb2.getHub().size() == 0) {
// need to add to gbNew.a=null hubB
gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == null) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) {
gbNewFound = createGroupBy(null);
HubGroupBy.this.getCombinedHub().add(gbNewFound);
}
for (Object gb1B : gb1Found.getHub()) {
gbNewFound.getHub().add(gb1B);
}
}
}
};
// C: initial load for this.hubCombined using GB1
for (OAGroupBy gb1 : hubGB1) {
OAObject gb1A = (OAObject) gb1.getGroupBy();
boolean bFound = false;
OAGroupBy gb2Found = null;
for (OAGroupBy gb2 : hubGB2) {
if (gb2.getGroupBy() == gb1A) {
gb2Found = gb2;
}
}
if (gb2Found == null || gb2Found.getHub().getSize() == 0) {
// add to empty list
if (!bCreateNullList) continue;
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == null) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) {
gbNewFound = createGroupBy(null);
HubGroupBy.this.getCombinedHub().add(gbNewFound);
}
for (Object gb1B : gb1.getHub()) {
gbNewFound.getHub().add(gb1B);
}
continue;
}
for (Object gb2B : gb2Found.getHub()) {
OAObject objGB2b = (OAObject) gb2B;
OAGroupBy gbNewFound = null;
for (OAGroupBy gbNew : HubGroupBy.this.getCombinedHub()) {
if (gbNew.getGroupBy() == objGB2b) {
gbNewFound = gbNew;
break;
}
}
if (gbNewFound == null) {
gbNewFound = createGroupBy((G) objGB2b);
HubGroupBy.this.getCombinedHub().add(gbNewFound);
}
for (Object gb1B : gb1.getHub()) {
gbNewFound.getHub().add(gb1B);
}
}
}
}
// main setup, if not needing a split
void setupMain() {
getCombinedHub().addHubListener(new HubListenerAdapter() {
@Override
public void afterChangeActiveObject(HubEvent e) {
if (bIgnoreAOChange) return;
try {
// set the active object in hub A&B when hubCombine.AO is changed
OAGroupBy obj = (OAGroupBy) e.getObject();
if (obj == null) {
if (hubGroupBy != null) hubGroupBy.setAO(null);
if (hubMaster != null) hubMaster.setAO(null);
}
else {
if (hubGroupBy != null) hubGroupBy.setAO(obj.getGroupBy());
if (hubMaster != null) hubMaster.setAO(obj.getGroupBy());
}
hubFrom.setAO(null);
if (hubDetail != null) hubDetail.setAO(null);
}
finally {
bIgnoreAOChange = false;
}
}
});
if (hubGroupBy != null) {
hubGroupBy.addHubListener(new HubListenerAdapter() {
@Override
public void afterInsert(HubEvent e) {
afterAdd(e);
}
@Override
public void afterAdd(HubEvent e) {
G a = (G) e.getObject();
boolean bFound = false;
for (OAGroupBy c : HubGroupBy.this.getCombinedHub()) {
if (c.getGroupBy() == a) {
bFound= true;
break;
}
}
if (!bFound) {
OAGroupBy gbNewFound = createGroupBy(a);
HubGroupBy.this.hubCombined.add(gbNewFound);
}
}
Object[] removeObjects;
@Override
public void beforeRemoveAll(HubEvent e) {
removeObjects = hubGroupBy.toArray();
}
@Override
public void afterRemoveAll(HubEvent e) {
for (Object obj : removeObjects) {
remove((G) obj);
}
removeObjects = null;
}
@Override
public void afterRemove(HubEvent e) {
G a = (G) e.getObject();
remove(a);
}
void remove(G a) {
for (OAGroupBy c : HubGroupBy.this.getCombinedHub()) {
if (c.getGroupBy() == a) {
HubGroupBy.this.hubCombined.remove(c);
break;
}
}
}
@Override
public void onNewList(HubEvent e) {
HubGroupBy.this.hubCombined.clear();
for (G a : hubGroupBy) {
OAGroupBy gbNewFound = createGroupBy(a);
HubGroupBy.this.hubCombined.add(gbNewFound);
}
addAll();
}
});
for (G a : hubGroupBy) {
boolean bFound = false;
for (OAGroupBy c : HubGroupBy.this.getCombinedHub()) {
if (c.getGroupBy() == a) {
bFound= true;
break;
}
}
if (!bFound) {
OAGroupBy gbNewFound = createGroupBy(a);
HubGroupBy.this.hubCombined.add(gbNewFound);
}
}
}
HubListener hl = new HubListenerAdapter() {
@Override
public void afterInsert(HubEvent e) {
afterAdd(e);
}
@Override
public void afterAdd(HubEvent e) {
F b = (F) e.getObject();
add(b);
}
Object[] removeObjects;
@Override
public void beforeRemoveAll(HubEvent e) {
removeObjects = hubFrom.toArray();
}
@Override
public void afterRemoveAll(HubEvent e) {
if (removeObjects == null) return;
for (Object obj : removeObjects) {
remove((F) obj);
}
removeObjects = null;
}
@Override
public void afterRemove(HubEvent e) {
F b = (F) e.getObject();
remove(b);
}
@Override
public void afterPropertyChange(HubEvent e) {
String s = e.getPropertyName();
if (!listenPropertyName.equalsIgnoreCase(s)) return;
update((F) e.getObject());
}
@Override
public void onNewList(HubEvent e) {
try {
bIgnoreAOChange = true;
HubGroupBy.this.getCombinedHub().clear();
}
finally {
bIgnoreAOChange = false;
}
if (hubGroupBy != null) {
for (G a : hubGroupBy) {
OAGroupBy gbNewFound = createGroupBy(a);
HubGroupBy.this.hubCombined.add(gbNewFound);
}
}
addAll();
}
@Override
public void afterChangeActiveObject(HubEvent e) {
if (bIgnoreAOChange) return;
bIgnoreAOChange = true;
try {
F ao = (F) e.getObject();
if (ao == null) {
HubGroupBy.this.hubCombined.setAO(null);
if (hubMaster != null) hubMaster.setAO(null);
if (hubDetail != null) hubDetail.setAO(null);
}
else {
boolean bFound = false;
for (OAGroupBy gb : HubGroupBy.this.getCombinedHub()) {
Hub h = gb.getHub();
if (!h.contains(ao)) continue;
bFound = true;
HubGroupBy.this.hubCombined.setAO(gb);
h.setAO(ao);
if (hubMaster != null) hubMaster.setAO(gb.getGroupBy());
if (hubDetail != null) hubDetail.setAO(ao);
break;
}
if (!bFound) {
HubGroupBy.this.hubCombined.setAO(null);
if (hubMaster != null) hubMaster.setAO(null);
if (hubDetail != null) hubDetail.setAO(null);
}
}
}
finally {
bIgnoreAOChange = false;
}
}
};
boolean b = false;
if (propertyPath == null) {
b = true;
}
else if (propertyPath.indexOf('.') < 0) {
// propertyPath could be a hub
OAObjectInfo oi = OAObjectInfoDelegate.getOAObjectInfo(classFrom);
OALinkInfo li = oi.getLinkInfo(propertyPath);
if (li == null || li.getType() == li.ONE) {
b = true;
}
// else it's a hub
}
if (b) {
listenPropertyName = propertyPath;
hubFrom.addHubListener(hl, propertyPath);
}
else {
listenPropertyName = "hubGroupBy" + aiCnt.getAndIncrement();
hubFrom.addHubListener(hl, listenPropertyName, new String[] { propertyPath });
}
addAll();
}
private void addAll() {
// this will tell the OASyncClient.getDetail which hub objects are being used
Hub holdDetailHub = OAThreadLocalDelegate.getGetDetailHub();
String holdDetailPP = OAThreadLocalDelegate.getGetDetailPropertyPath();
try {
OAThreadLocalDelegate.setGetDetailHub(this.hubFrom, this.propertyPath);
for (F bx : hubFrom) {
try {
OAThreadLocalDelegate.setSuppressCSMessages(true);
add(bx);
}
finally {
OAThreadLocalDelegate.setSuppressCSMessages(false);
}
}
}
finally {
OAThreadLocalDelegate.resetGetDetailHub(holdDetailHub, holdDetailPP);
}
}
private ArrayList add(F b) {
return add(b, false);
}
private ArrayList add(F b, boolean bReturnList) {
if (b == null) return null;
Object valueA = b.getProperty(propertyPath);
ArrayList al = null;
if (valueA instanceof Hub) {
Hub h = (Hub) valueA;
for (int i = 0;; i++) {
valueA = h.getAt(i);
if (valueA == null) break;
boolean bFound = false;
for (OAGroupBy gb : HubGroupBy.this.getCombinedHub()) {
if (gb.getGroupBy() != valueA) continue;
if (bReturnList) {
if (al == null) al = new ArrayList();
al.add(gb);
}
gb.getHub().add(b);
bFound = true;
break;
}
if (!bFound) {
// create new
OAGroupBy gbNewFound = createGroupBy((G) valueA);
HubGroupBy.this.hubCombined.add(gbNewFound);
gbNewFound.getHub().add(b);
if (bReturnList) {
if (al == null) al = new ArrayList();
al.add(gbNewFound);
}
}
}
// add to empty hub
if (h.size() == 0 && bCreateNullList) {
for (OAGroupBy gb : HubGroupBy.this.getCombinedHub()) {
if (gb.getGroupBy() != null) continue;
gb.getHub().add(b);
if (bReturnList) {
if (al == null) al = new ArrayList();
al.add(gb);
}
return al;
}
// create new
OAGroupBy gb = createGroupBy(null);
HubGroupBy.this.hubCombined.add(gb);
gb.getHub().add(b);
if (bReturnList) {
if (al == null) al = new ArrayList();
al.add(gb);
}
}
}
else {
if (!bCreateNullList && valueA == null) return al;
for (OAGroupBy gb : HubGroupBy.this.getCombinedHub()) {
if (gb.getGroupBy() != valueA) continue;
gb.getHub().add(b);
if (bReturnList) {
if (al == null) al = new ArrayList();
al.add(gb);
}
return al;
}
// create new
OAGroupBy c = createGroupBy((G) valueA);
HubGroupBy.this.hubCombined.add(c);
c.getHub().add(b);
if (bReturnList) {
if (al == null) al = new ArrayList();
al.add(c);
}
}
return al;
}
private void remove(G a, F b) {
for (OAGroupBy gb : HubGroupBy.this.getCombinedHub()) {
G ax = (G) gb.getGroupBy();
if (ax != a) continue;
Hub h = gb.getHub();
if (h.contains(b)) {
h.remove(b);
return;
}
}
}
private void remove(F b) {
for (OAGroupBy gb : getCombinedHub()) {
Hub h = gb.getHub();
if (h.contains(b)) {
h.remove(b);
if (h.size() == 0) {
if (hubGroupBy == null || !hubGroupBy.contains(gb.getGroupBy())) {
hubCombined.remove(gb);
}
}
}
}
}
private void update(F b) {
ArrayList al = add(b, true);
for (OAGroupBy gb : getCombinedHub()) {
Hub h = gb.getHub();
if (al != null) {
if (al.contains(gb)) continue;
}
if (h.contains(b)) {
h.remove(b);
}
}
}
//qqqqqqqqqqqqqqqqqqqqq
// HubGroupBy hgb1x, hgb2x;;
void setupCombined(HubGroupBy hgb1, HubGroupBy hgb2) {
final Hub> hub1 = hgb1.getCombinedHub();
final Hub> hub2 = hgb2.getCombinedHub();
//qqqqqqqqqqqqqq
//hgb1x = hgb1;
//hgb2x = hgb2;
getCombinedHub();
HubListener> hl = new HubListenerAdapter>() {
/*
Hub> getOtherHub(HubEvent e) {
if (e.getSource() == hub1) return hub2;
return hub1;
}
*/
@Override
public void afterAdd(HubEvent> e) {
final OAGroupBy gb = e.getObject();
OAGroupBy gbFound = null;
G a = (G) gb.getGroupBy();
for (OAGroupBy c : HubGroupBy.this.getCombinedHub()) {
if (c.getGroupBy() == a) {
gbFound= c;
break;
}
}
if (gbFound == null) {
gbFound = createGroupBy(a);
HubGroupBy.this.getCombinedHub().add(gbFound);
}
for (OAObject obj : gb.getHub()) {
gbFound.getHub().add(obj);
}
}
@Override
public void afterInsert(HubEvent e) {
afterAdd(e);
}
@Override
public void afterRemove(HubEvent> e) {
final OAGroupBy gb = e.getObject();
OAGroupBy gbFound = null;
G a = (G) gb.getGroupBy();
for (OAGroupBy c : HubGroupBy.this.getCombinedHub()) {
if (c.getGroupBy() == a) {
gbFound = c;
break;
}
}
if (gbFound == null) return;
for (OAObject obj : gb.getHub()) {
boolean bStillNeeded = false;
for (OAGroupBy gbx : hub1) {
if (gbx.getGroupBy() == a) {
if (gbx.getHub().contains(obj)) {
bStillNeeded = true;
break;
}
}
}
for (OAGroupBy gbx : hub2) {
if (gbx.getGroupBy() == a) {
if (gbx.getHub().contains(obj)) {
bStillNeeded = true;
break;
}
}
}
if (!bStillNeeded) gbFound.getHub().remove(obj);
}
}
void rebuild() {
HubGroupBy.this.getCombinedHub().clear();
OAGroupBy gbFound = null;
for (OAGroupBy gb : hub1) {
gbFound = createGroupBy(gb.getGroupBy());
HubGroupBy.this.hubCombined.add(gbFound);
for (F obj : gb.getHub()) {
gbFound.getHub().add(obj);
}
}
for (OAGroupBy gb : hub2) {
gbFound = null;
G a = (G) gb.getGroupBy();
for (OAGroupBy c : HubGroupBy.this.getCombinedHub()) {
if (c.getGroupBy() == a) {
gbFound= c;
break;
}
}
if (gbFound == null) {
gbFound = createGroupBy(a);
HubGroupBy.this.hubCombined.add(gbFound);
}
for (F obj : gb.getHub()) {
gbFound.getHub().add(obj);
}
}
}
@Override
public void afterRemoveAll(HubEvent> e) {
rebuild();
}
@Override
public void onNewList(HubEvent e) {
rebuild();
}
};
hub1.addHubListener(hl);
hub2.addHubListener(hl);
// set up hubMergers
//qqqqqq this fails
//Hub hubTemp1 = new Hub();
//qq this works
Hub hubTemp1 = new Hub(OAObject.class);
HubMerger, F> hm1 = new HubMerger, F>(hub1, (Hub)hubTemp1, OAGroupBy.P_Hub, true) {
@Override
protected void afterInsertRealHub(HubEvent e) {
afterAddRealHub(e);
}
@Override
protected void afterAddRealHub(HubEvent e) {
final OAGroupBy gb = (OAGroupBy) e.getHub().getMasterObject();
final F objAdd = (F) e.getObject();
OAGroupBy gbFound = null;
G a = (G) gb.getGroupBy();
if (a == null) {
if (!bCreateNullList) return;
// only add if its in the other hgb null
for (OAGroupBy gbx : hub2) {
if (gbx.getGroupBy() == null) {
if (!gbx.getHub().contains(objAdd)) {
return;
}
}
}
}
for (OAGroupBy c : HubGroupBy.this.getCombinedHub()) {
if (c.getGroupBy() == a) {
gbFound= c;
break;
}
}
if (gbFound == null) {
gbFound = createGroupBy(a);
HubGroupBy.this.getCombinedHub().add(gbFound);
}
gbFound.getHub().add(objAdd);
}
@Override
protected void afterRemoveRealHub(HubEvent e) {
OAGroupBy gb = (OAGroupBy) e.getHub().getMasterObject();
F objRemove = (F) e.getObject();
remove(gb, objRemove);
}
void remove(final OAGroupBy gb, final F objRemove) {
OAGroupBy gbFound = null;
final G a = (G) gb.getGroupBy();
for (OAGroupBy c : HubGroupBy.this.getCombinedHub()) {
if (c.getGroupBy() == a) {
gbFound= c;
break;
}
}
if (gbFound == null) return;
boolean bStillNeeded = false;
if (a != null) {
for (OAGroupBy gbx : hub2) {
if (gbx.getGroupBy() == a) {
if (gbx.getHub().contains(objRemove)) {
bStillNeeded = true;
break;
}
}
}
}
if (!bStillNeeded) gbFound.getHub().remove(objRemove);
}
private Object[] removeAllObjects;
@Override
protected void beforeRemoveAllRealHub(HubEvent e) {
removeAllObjects = ((Hub) e.getSource()).toArray();
}
@Override
protected void afterRemoveAllRealHub(HubEvent e) {
if (removeAllObjects == null) return;
OAGroupBy gb1 = (OAGroupBy) ((Hub) e.getSource()).getMasterObject();
for (Object obj: removeAllObjects) {
remove(gb1, (F) obj);
}
removeAllObjects = null;
}
};
Hub hubTemp2 = new Hub(OAObject.class);
HubMerger, F> hm2 = new HubMerger, F>(hub2, (Hub)hubTemp2, OAGroupBy.P_Hub, true) {
@Override
protected void afterInsertRealHub(HubEvent e) {
afterAddRealHub(e);
}
@Override
protected void afterAddRealHub(HubEvent e) {
final OAGroupBy gb = (OAGroupBy) e.getHub().getMasterObject();
final F objAdd = (F) e.getObject();
OAGroupBy gbFound = null;
G a = (G) gb.getGroupBy();
if (a == null) {
if (!bCreateNullList) return;
// only add if its in the other hgb null
for (OAGroupBy gbx : hub2) {
if (gbx.getGroupBy() == null) {
if (!gbx.getHub().contains(objAdd)) {
return;
}
}
}
}
for (OAGroupBy c : HubGroupBy.this.getCombinedHub()) {
if (c.getGroupBy() == a) {
gbFound= c;
break;
}
}
if (gbFound == null) {
gbFound = createGroupBy(a);
HubGroupBy.this.hubCombined.add(gbFound);
}
gbFound.getHub().add(objAdd);
}
@Override
protected void afterRemoveRealHub(HubEvent e) {
OAGroupBy gb = (OAGroupBy) e.getHub().getMasterObject();
F objRemove = (F) e.getObject();
remove(gb, objRemove);
}
void remove(final OAGroupBy gb, final F objRemove) {
OAGroupBy gbFound = null;
final G a = (G) gb.getGroupBy();
for (OAGroupBy c : HubGroupBy.this.getCombinedHub()) {
if (c.getGroupBy() == a) {
gbFound= c;
break;
}
}
if (gbFound == null) return;
boolean bStillNeeded = false;
if (a != null) {
for (OAGroupBy gbx : hub1) {
if (gbx.getGroupBy() == a) {
if (gbx.getHub().contains(objRemove)) {
bStillNeeded = true;
break;
}
}
}
}
if (!bStillNeeded) gbFound.getHub().remove(objRemove);
}
private Object[] removeAllObjects;
@Override
protected void beforeRemoveAllRealHub(HubEvent e) {
removeAllObjects = ((Hub) e.getSource()).toArray();
}
@Override
protected void afterRemoveAllRealHub(HubEvent e) {
if (removeAllObjects == null) return;
OAGroupBy gb1 = (OAGroupBy) ((Hub) e.getSource()).getMasterObject();
for (Object obj: removeAllObjects) {
remove(gb1, (F) obj);
}
removeAllObjects = null;
}
};
// initial load
for (int i=0; i<2; i++) {
Hub> hub;
if (i == 0) hub = hub1;
else hub = hub2;
for (OAGroupBy gb : hub) {
OAGroupBy gbFound = null;
G a = (G) gb.getGroupBy();
if (!bCreateNullList && a == null) continue;
for (OAGroupBy c : HubGroupBy.this.getCombinedHub()) {
if (c.getGroupBy() == a) {
gbFound= c;
break;
}
}
if (gbFound == null) {
gbFound = createGroupBy(a);
HubGroupBy.this.getCombinedHub().add(gbFound);
}
for (F obj : gb.getHub()) {
gbFound.getHub().add(obj);
}
}
}
}
private OAGroupBy createGroupBy(G grpBy) {
OAGroupBy gb = new OAGroupBy();
if (grpBy != null) gb.setGroupBy(grpBy);
HubDelegate.setObjectClass(gb.getHub(), classFrom);
return gb;
}
public String getGroupByPP() {
String s = "("+classGroupBy.toString() + ")GroupBy";
return s;
}
public String getHubByPP() {
return "("+classFrom.toString() + ")hub";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy