com.viaoa.object.OAObjectDelegate Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of oa-core Show documentation
Show all versions of oa-core Show documentation
Object Automation library
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.List;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.viaoa.context.OAContext;
import com.viaoa.datasource.OADataSource;
import com.viaoa.hub.Hub;
import com.viaoa.hub.HubDelegate;
import com.viaoa.sync.OASync;
import com.viaoa.sync.OASyncDelegate;
import com.viaoa.util.OAString;
/**
* This is the central Delegate class that performs services for OAObjects. The other Delegate classes are specialized for specific tasks.
* This Delegate is used for multi-specific and misc functionality. The Delegates are designed so that the OAObject class can be light
* weight and have various functionalities built in.
*
* @author vincevia
*/
public class OAObjectDelegate {
private static Logger LOG = Logger.getLogger(OAObjectDelegate.class.getName());
public static final String WORD_New = "NEW";
public static final String WORD_Changed = "CHANGED";
public static final String WORD_Deleted = "DELETED";
public static final String WORD_AutoAdd = "AutoAdd";
public static final Boolean TRUE = Boolean.TRUE;
public static final Boolean FALSE = Boolean.FALSE;
/** Static global lock used when setting global properties (ex: guidCounter) */
/** global counter used for local objects. Value is positive */
static protected AtomicInteger guidCounter = new AtomicInteger(); // unique identifier needed for objects past from client/server
/** global counter used for local objects. Value is negative */
static protected AtomicInteger localGuidCounter = new AtomicInteger();
/** Flag to know if finalized objects should be automatically saved. Default is false. */
protected static boolean bFinalizeSave = false;
/** tracks which OAObjects should not automatically add themself to a detailHub when an oaObj property is set. */
private static final ConcurrentHashMap hmAutoAdd = new ConcurrentHashMap();
/**
* Called by OAObject constructor to assign guid and initialize new OAObject. If OAObjectFlagDelegate.isLoading() == false then
* initialize(...) will be called using the values from getOAObjectInfo()
*/
protected static boolean initialize(OAObject oaObj) {
if (oaObj == null) {
return false;
}
assignGuid(oaObj); // must get a guid before calling setInConstructor, so that it will have a valid hash key
/**
* set OAObject.nulls to know if a primitive property is null or not. All "bits" are flagged/set to 1. Ordering and positions are
* set by the position of uppercase/sorted property in array. See: OAObjectInfoDelegate.initialize()
*/
OAObjectInfo oi = OAObjectInfoDelegate.getOAObjectInfo(oaObj);
String[] ps = oi.getPrimitiveProperties();
int x = (ps == null) ? 0 : ((int) Math.ceil(ps.length / 8.0d));
oaObj.nulls = new byte[x];
if (OAThreadLocalDelegate.isLoading()) {
return false; // dont initialize. Whatever is loading should call initialize below directly
}
boolean bInitializeWithCS = !oi.getLocalOnly() && OASync.isClient(oaObj.getClass());
// 20200910 useDataSource needs to be true ... since other DS (ex: autonumber) might be used
initialize(oaObj, oi, oi.getInitializeNewObjects(), true, oi.getAddToCache(), bInitializeWithCS, true);
//was: initialize(oaObj, oi, oi.getInitializeNewObjects(), oi.getUseDataSource(), oi.getAddToCache(), bInitializeWithCS, true);
return true;
}
public static void initializeAfterLoading(OAObject oaObj) {
initializeAfterLoading(oaObj, false, false, false);
}
public static void initializeAfterLoading(OAObject oaObj, boolean bAssignNewId, boolean bInitializeNulls, boolean bSetChangedToFalse) {
if (oaObj == null) {
return;
}
OAObjectInfo oi = OAObjectInfoDelegate.getOAObjectInfo(oaObj);
boolean bInitializeWithCS = !oi.getLocalOnly() && OASync.isClient(oaObj.getClass());
initialize(oaObj, oi, bInitializeNulls, bAssignNewId, oi.getAddToCache(), bInitializeWithCS, bSetChangedToFalse);
}
/**
* @param oaObj
* @param oi if null, then the correct oi will be retrieved.
* @param bInitializeNulls set all primitive properties to null
* @param bInitializeWithDS will call OAObjectDSDelegateinitialize()
* @param bAddToCache if true then call OAObjectCacheDelegate.add()
* @param bInitializeWithCS if true, then call OAObjectCSDelegate.initialize().
*/
protected static void initialize(OAObject oaObj, OAObjectInfo oi, boolean bInitializeNulls, boolean bInitializeWithDS,
boolean bAddToCache, boolean bInitializeWithCS, boolean bSetChangedToFalse) {
final boolean bWasLoading = OAThreadLocalDelegate.setLoading(true);
try {
if (oi == null) {
oi = OAObjectInfoDelegate.getOAObjectInfo(oaObj);
}
if (bInitializeNulls) {
/* 20180325 20180403 removed,not used
byte[] bsMask = oi.getPrimitiveMask();
for (int i=0; i= guid) {
break;
}
if (guidCounter.compareAndSet(g, guid)) {
break;
}
}
}
/**
* Removes object from HubController and calls super.finalize().
*/
public static void finalizeObject(OAObject oaObj) {
//System.out.println((++qq)+" finalizeObject: "+oaObj);
if (oaObj.guid == 0) {
return; // set to 0 by readResolve or ObjectCacheDelegate.add() to ignore finalization
}
if (oaObj.guid > 0 && !oaObj.deletedFlag) { // set to 0 by readResolve or ObjectCacheDelegate.add() to ignore finalization
if ((oaObj.changedFlag || oaObj.newFlag) && !OAObjectCSDelegate.isWorkstation(oaObj)) {
// 20131128 added autoAttach check
if (OAObjectDelegate.getAutoAdd(oaObj)) {
OAObjectInfo oi = OAObjectInfoDelegate.getOAObjectInfo(oaObj.getClass());
if (oi != null && (oi.getUseDataSource() || OADataSource.getDataSource(oaObj.getClass()) != null)) {
LOG.finer("object was not saved, object=" + oaObj.getClass().getName() + ", key="
+ OAObjectKeyDelegate.getKey(oaObj)
+ ", willSaveNow=" + bFinalizeSave);
if (bFinalizeSave) {
try {
oaObj.save(OAObject.CASCADE_NONE);
} catch (Exception e) {
LOG.log(Level.WARNING, "object had error while saving, object=" + oaObj.getClass().getName() + ", key="
+ OAObjectKeyDelegate.getKey(oaObj), e);
}
}
}
}
}
}
OAObjectCacheDelegate.removeObject(oaObj); // remove from class cache
hmAutoAdd.remove(oaObj.guid);
oaObj.weakhubs = null;
}
/**
* Returns true if this object is new or any changes have been made to this object or any objects in Links that are TYPE=MANY and
* CASCADE=true that match the relationshipType parameter.
*/
public static boolean getChanged(OAObject oaObj, int changedRule) {
if (changedRule == OAObject.CASCADE_NONE) {
return (oaObj.changedFlag || oaObj.newFlag);
}
OACascade cascade = new OACascade();
boolean b = getChanged(oaObj, changedRule, cascade);
return b;
}
public static boolean getChanged(final OAObject oaObj, int iCascadeRule, OACascade cascade) {
if (oaObj.changedFlag || oaObj.newFlag) {
return true;
}
if (iCascadeRule == oaObj.CASCADE_NONE) {
return false;
}
if (cascade.wasCascaded(oaObj, true)) {
return false;
}
if (oaObj.properties == null) {
return false;
}
// check link cascade objects
OAObjectInfo oi = OAObjectInfoDelegate.getOAObjectInfo(oaObj);
List al = oi.getLinkInfos();
for (int i = 0; i < al.size(); i++) {
OALinkInfo li = (OALinkInfo) al.get(i);
String prop = li.getName();
if (prop == null || prop.length() < 1) {
continue;
}
if (li.getCalculated()) {
continue;
}
if (li.getPrivateMethod()) {
continue;
}
if (!li.getUsed()) {
continue;
}
// same as OAObjectSaveDelegate.cascadeSave()
if (OAObjectReflectDelegate.isReferenceNullOrNotLoaded(oaObj, prop)) {
continue;
}
boolean bValidCascade = false;
if (iCascadeRule == OAObject.CASCADE_LINK_RULES && li.cascadeSave) {
bValidCascade = true;
} else if (iCascadeRule == OAObject.CASCADE_OWNED_LINKS && li.getOwner()) {
bValidCascade = true;
} else if (iCascadeRule == OAObject.CASCADE_ALL_LINKS) {
bValidCascade = true;
}
if (OAObjectInfoDelegate.isMany2Many(li)) {
Hub hub = (Hub) OAObjectReflectDelegate.getRawReference(oaObj, prop);
if (HubDelegate.getChanged(hub, OAObject.CASCADE_NONE, cascade)) {
return true;
}
}
if (!bValidCascade) {
continue;
}
Object obj = OAObjectReflectDelegate.getProperty(oaObj, li.name); // if Hub with Keys, then this will load the correct objects to check
if (obj == null) {
continue;
}
if (obj instanceof Hub) {
if (OAObjectHubDelegate.getChanged((Hub) obj, iCascadeRule, cascade)) {
return true; // if there have been adds/removes to hub
}
} else {
if (obj instanceof OAObject) { // 20110420 could be OANullObject
if (getChanged((OAObject) obj, iCascadeRule, cascade)) {
return true;
}
}
}
}
return false;
}
/**
* Used to recursively get all reference objects below this one. All objects will only be visited once.
*/
public static void recurse(OAObject oaObj, OACallback callback) {
OACascade cascade = new OACascade();
recurse(oaObj, callback, cascade);
}
/** see #recurse(OACallback) */
public static void recurse(OAObject oaObj, OACallback callback, OACascade cascade) {
if (cascade.wasCascaded(oaObj, true)) {
return;
}
if (callback != null) {
callback.updateObject(oaObj);
}
OAObjectInfo oi = OAObjectInfoDelegate.getOAObjectInfo(oaObj);
List al = oi.getLinkInfos();
for (int i = 0; i < al.size(); i++) {
OALinkInfo li = (OALinkInfo) al.get(i);
if (li.getCalculated()) {
continue;
}
if (li.getPrivateMethod()) {
continue;
}
if (!li.getUsed()) {
continue;
}
String prop = li.name;
Object obj = OAObjectReflectDelegate.getProperty(oaObj, li.name); // select all
if (obj == null) {
continue;
}
if (obj instanceof Hub) {
Hub h = (Hub) obj;
for (int j = 0;; j++) {
Object o = h.elementAt(j);
if (o == null) {
break;
}
if (o instanceof OAObject) {
recurse((OAObject) o, callback, cascade);
} else {
if (callback != null) {
callback.updateObject(o);
}
}
Object o2 = h.elementAt(j);
if (o != o2) {
j--;
}
}
} else {
if (obj instanceof OAObject) {
recurse((OAObject) obj, callback, cascade);
} else {
if (callback != null) {
callback.updateObject(obj);
}
}
}
}
}
protected static Object[] find(OAObject base, String propertyPath, Object findValue, boolean bFindAll) {
if (propertyPath == null || propertyPath.length() == 0) {
return null;
}
StringTokenizer st = new StringTokenizer(propertyPath, ".");
Object result = base;
for (; st.hasMoreTokens();) {
String s = st.nextToken();
base = (OAObject) result; // previous object
result = base.getProperty(s);
if (!st.hasMoreTokens()) {
// last property, check against findValue
if (result == findValue || (result != null && result.equals(findValue))) {
Object[] objs = new Object[] { base };
return objs;
}
return null;
}
if (result == null) {
return null;
}
if (result instanceof Hub) {
String pp = null;
for (; st.hasMoreTokens();) {
s = st.nextToken();
if (pp == null) {
pp = s;
} else {
pp += "." + s;
}
}
ArrayList al = null;
Hub h = (Hub) result;
for (int ii = 0;; ii++) {
Object obj = h.elementAt(ii);
if (obj == null) {
break;
}
Object[] objs = find((OAObject) obj, pp, findValue, bFindAll);
if (objs != null) {
if (!bFindAll) {
return objs;
}
if (al == null) {
al = new ArrayList(10);
}
for (int i3 = 0; i3 < objs.length; i3++) {
al.add(objs[i3]);
}
}
}
if (al == null) {
return null;
}
Object[] objs = new Object[al.size()];
objs = al.toArray(objs);
return objs;
}
if (!(result instanceof OAObject)) {
return null;
}
}
return null;
}
/**
* Central method that is used when the object property Key is changed (OAObjectKey) and needs to be rehashed in all Hashtables that it
* could exist in.
*
* @param oaObj
* @param oldKey
*/
protected static void rehash(OAObject oaObj, OAObjectKey oldKey) {
// Need to rehash all Hashtables that OAObject is stored in:
// 1: CacheDelegate hashtable
// 2: obj.Hubs - NOTE: not needed, since Hubs dont use hashtables anymore
// 3: HashDelegate hashtables
OAObjectInfo oi = OAObjectInfoDelegate.getOAObjectInfo(oaObj);
if (oi.getAddToCache()) {
OAObjectCacheDelegate.rehash(oaObj, oldKey);
}
OAObjectHashDelegate.rehash(oaObj, oldKey);
}
public static int getGuid(OAObject obj) {
if (obj == null) {
return -1;
}
return obj.guid;
}
/**
* Used to determine if an object should be added to a reference/master hub when one of it's OAObject properties is set. If false, then
* the object will not be added to masterHubs until this is called with "true" or when oaObj is saved.
*
* @param oaObj
* @param bEnabled (default is true)
*/
public static void setAutoAdd(OAObject oaObj, boolean bEnabled) {
if (oaObj == null) {
return;
}
if (!bEnabled && !oaObj.isNew()) {
return;
}
boolean bOld = !hmAutoAdd.containsKey(oaObj.guid);
if (bOld == bEnabled) {
return;
}
if (!bEnabled) {
hmAutoAdd.put(oaObj.guid, oaObj.guid);
} else {
hmAutoAdd.remove(oaObj.guid);
}
OAObjectEventDelegate.firePropertyChange(oaObj, WORD_AutoAdd, bOld ? TRUE : FALSE, bEnabled ? TRUE : FALSE, false, false);
if (!bEnabled || oaObj.deletedFlag) {
return;
}
try {
OAThreadLocalDelegate.setSuppressCSMessages(true);
// need to see if object should be put into linkOne/masterObject hub(s)
OAObjectInfo oi = OAObjectInfoDelegate.getOAObjectInfo(oaObj);
for (OALinkInfo li : oi.getLinkInfos()) {
if (!li.getUsed()) {
continue;
}
if (li.getType() != li.ONE) {
continue;
}
Object objx = OAObjectReflectDelegate.getRawReference(oaObj, li.getName());
if (!(objx instanceof OAObject)) {
continue;
}
OALinkInfo liRev = OAObjectInfoDelegate.getReverseLinkInfo(li);
if (liRev == null) {
continue;
}
if (!liRev.getUsed()) {
continue;
}
if (liRev.getType() != li.MANY) {
continue;
}
if (liRev.getPrivateMethod()) {
continue;
}
Object objz = OAObjectReflectDelegate.getProperty((OAObject) objx, liRev.getName());
if (objz instanceof Hub) {
((Hub) objz).add(oaObj);
}
}
} finally {
OAThreadLocalDelegate.setSuppressCSMessages(false);
}
}
public static boolean getAutoAdd(OAObject oaObj) {
if (oaObj == null) {
return false;
}
return !hmAutoAdd.containsKey(oaObj.guid);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy