com.viaoa.object.OAObjectPropertyDelegate Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of oa Show documentation
Show all versions of oa Show documentation
Object Automation library
The newest version!
/* 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.ref.WeakReference;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.viaoa.hub.Hub;
import com.viaoa.remote.multiplexer.OARemoteThreadDelegate;
import com.viaoa.sync.OASync;
import com.viaoa.util.OANotExist;
// 20140225 redone to simplify property locking using CAS
/**
* Manages OAObject.properties, which are used to store references
* (OAObjects, Hubs, OAObjectKey) and misc values.
* Stores as name/value in a flat object array, where even positions are property names and odd positions are the value, which can be null.
* This uses a flat array to make it as efficient as possible for the oaObject with as little overhead as possible.
*/
public class OAObjectPropertyDelegate {
private static Logger LOG = Logger.getLogger(OAObjectPropertyDelegate.class.getName());
/**
* @return true if prop is loaded, and does not need to be loaded from datasource, or from server (if this is client)
*/
public static boolean isPropertyLoaded(OAObject oaObj, String name) {
if (oaObj == null || name == null) return false;
Object[] props = oaObj.properties;
if (props == null) return false;
for (int i=0; i hmLock = new ConcurrentHashMap();
private static class PropertyLock {
boolean done;
boolean hasWait;
Thread thread;
}
public static boolean setPropertyLock(OAObject oaObj, String name) {
return _setPropertyLock(oaObj, name, true, false);
}
public static boolean attemptPropertyLock(OAObject oaObj, String name) {
return _setPropertyLock(oaObj, name, false, true);
}
private static boolean _setPropertyLock(final OAObject oaObj, final String name, final boolean bWaitIfNeeded, final boolean bCheckIfThisThread) {
if (oaObj == null || name == null) return false;
String key = OAObjectDelegate.getGuid(oaObj) + "." + name.toUpperCase();
PropertyLock lock;
synchronized (oaObj) {
lock = hmLock.get(key);
if (lock == null) {
lock = new PropertyLock();
lock.thread = Thread.currentThread();
hmLock.put(key, lock);
return true;
}
}
synchronized (lock) {
if (lock.thread == Thread.currentThread()) return bCheckIfThisThread;
if (!bWaitIfNeeded) return false;
long ms = 0;
for (int i=0; ;i++) {
if (i == 0) {
OARemoteThreadDelegate.startNextThread();
}
else if (i > 5) {
if (ms == 0) ms = System.currentTimeMillis();
else if (System.currentTimeMillis() - ms > 1000) {
if (OAObject.getDebugMode()) {
String s = "wait time exceeded for lock, obj="+oaObj+", prop="+name+", this.Thread="+Thread.currentThread().getName()+", waiting on Thread="+lock.thread.getName()+" (see next stacktrace), will continue";
LOG.log(Level.WARNING, s, new Exception("fyi: wait time exceeded, will continue"));
StackTraceElement[] stes = lock.thread.getStackTrace();
Exception ex = new Exception();
ex.setStackTrace(stes);
LOG.log(Level.WARNING, "... waiting on this Thread="+lock.thread.getName(), ex);
}
return false; // bail out, ouch
}
}
if (lock.done) break;
lock.hasWait = true;
try {
lock.wait(50);
}
catch (Exception e) {
}
}
}
return _setPropertyLock(oaObj, name, bWaitIfNeeded, bCheckIfThisThread); // create a new one
}
public static void releasePropertyLock(OAObject oaObj, String name) {
if (oaObj == null || name == null) return;
String key = OAObjectDelegate.getGuid(oaObj) + "." + name.toUpperCase();
PropertyLock lock;
synchronized (oaObj) {
lock = hmLock.remove(key);
}
if (lock != null) {
synchronized (lock) {
lock.done = true;
if (lock.hasWait) {
lock.notifyAll();
}
}
}
}
public static boolean isPropertyLocked(OAObject oaObj, String name) {
if (oaObj == null || name == null) return false;
String key = OAObjectKeyDelegate.getKey(oaObj).getGuid() + "." + name.toUpperCase();
return (hmLock.get(key) != null);
}
// 20141108 "flip" a hub property to/from a weakRef. Used by HubDelegate.setReferenceable
public static boolean setPropertyWeakRef(OAObject oaObj, String name, boolean bToWeakRef, Object value) {
if (name == null || oaObj == null || oaObj.properties == null) return false;
boolean b = false;
synchronized (oaObj) {
for (int i=0; i 0) {
Object objx = OAObjectPropertyDelegate.getProperty((OAObject) parent, liRev.getName(), true, false);
if (objx instanceof OANotExist) continue;
if (objx instanceof WeakReference) {
objx = ((WeakReference) objx).get();
}
if (!(objx instanceof Hub)) continue;
boolean b = OAObjectPropertyDelegate.setPropertyWeakRef((OAObject) parent, liRev.getName(), !bReferenceable, (Hub) objx);
if (!b) break; // already changed, dont need to continue
}
if (bReferenceable) {
if (cascade == null) cascade = new OACascade();
cascade.add(obj);
setReferenceable((OAObject)parent, bReferenceable, cascade);
}
}
}
public static void clearProperties(OAObject oaObj) {
if (oaObj != null) oaObj.properties = null;
}
}