/*
* Copyright 2013
*
* 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 org.openntf.domino.impl;
import java.io.IOException;
import java.io.InvalidClassException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import lotus.domino.NotesException;
import org.openntf.domino.Session;
import org.openntf.domino.WrapperFactory;
import org.openntf.domino.big.NoteCoordinate;
import org.openntf.domino.events.EnumEvent;
import org.openntf.domino.events.IDominoEvent;
import org.openntf.domino.events.IDominoListener;
import org.openntf.domino.ext.Formula;
import org.openntf.domino.types.Encapsulated;
import org.openntf.domino.types.FactorySchema;
import org.openntf.domino.types.Resurrectable;
import org.openntf.domino.utils.DominoUtils;
import org.openntf.domino.utils.Factory;
import com.ibm.commons.util.NotImplementedException;
import javolution.util.FastMap;
/**
* A common Base class for almost all org.openntf.domino types.
*
* @param <T>
* the generic type
* @param <D>
* the delegate type
* @param <P>
* the parent type
*
*/
public abstract class Base<T extends org.openntf.domino.Base<D>, D extends lotus.domino.Base, P extends org.openntf.domino.Base<?>>
implements org.openntf.domino.Base<D> {
public static final int SOLO_NOTES_NAMES = 1000;
public static final int NOTES_SESSION = 1;
public static final int NOTES_DATABASE = 2;
public static final int NOTES_VIEW = 3;
public static final int NOTES_NOTE = 4;
public static final int NOTES_ITEM = 5;
public static final int NOTES_RTITEM = 6;
public static final int NOTES_REPORT = 7;
public static final int NOTES_TIME = 8;
public static final int NOTES_MACRO = 9;
public static final int NOTES_SERVER = 10;
public static final int NOTES_DOCCOLL = 11;
public static final int NOTES_AGENTLOG = 12;
public static final int NOTES_ACL = 13;
public static final int NOTES_ACLENTRY = 14;
public static final int NOTES_VIEWCOLUMN = 15;
public static final int NOTES_EMBEDOBJ = 16;
public static final int NOTES_REGISTRATION = 17;
public static final int NOTES_TIMER = 18;
public static final int NOTES_NAME = 19;
public static final int NOTES_FORM = 20;
public static final int NOTES_INTL = 21;
public static final int NOTES_DATERNG = 22;
public static final int NOTES_AGENTCTX = 25;
public static final int NOTES_RTSTYLE = 26;
public static final int NOTES_VIEWENTRY = 27;
public static final int NOTES_VECOLL = 28;
public static final int NOTES_RTPSTYLE = 29;
public static final int NOTES_RTTAB = 30;
public static final int NOTES_REPLICATION = 43;
public static final int NOTES_VIEWNAV = 44;
public static final int NOTES_OUTLINEENTRY = 48;
public static final int NOTES_OUTLINE = 49;
public static final int NOTES_MIMEENTITY = 50;
public static final int NOTES_RTTABLE = 51;
public static final int NOTES_RTNAVIGATOR = 52;
public static final int NOTES_RTRANGE = 53;
public static final int NOTES_NOTECOLLECTION = 54;
public static final int NOTES_DXLEXPORTER = 55;
public static final int NOTES_DXLIMPORTER = 56;
public static final int NOTES_MIMEHDR = 78;
public static final int NOTES_SESSTRM = 79;
public static final int NOTES_ADMINP = 80;
public static final int NOTES_RTDOCLNK = 81;
public static final int NOTES_COLOR = 82;
public static final int NOTES_RTSECTION = 83;
public static final int NOTES_REPLENT = 84;
public static final int NOTES_XMLREFORMATTER = 85;
public static final int NOTES_DOMDOCUMENTFRAGMENTNODE = 86;
public static final int NOTES_DOMNOTATIONNODE = 87;
public static final int NOTES_DOMCHARACTERDATANODE = 88;
public static final int NOTES_PROPERTYBROKER = 89;
public static final int NOTES_NOTESPROPERTY = 90;
public static final int NOTES_DIRECTORY = 91;
public static final int NOTES_DIRNAVIGATOR = 92;
public static final int NOTES_DIRENTRY = 93;
public static final int NOTES_DIRENTRYCOLLECTION = 94;
public static final int NOTES_DOMAIN = 95;
public static final int NOTES_CALENDAR = 96;
public static final int NOTES_CALENDARENTRY = 97;
public static final int NOTES_CALENDARNOTICE = 98;
/** The Constant log_. */
private static final Logger log_ = Logger.getLogger(Base.class.getName());
private static Method getCppObjMethod;
private static Method checkArgMethod;
private static Method checkObjectMethod;
private static Method checkObjectActiveMethod;
private static Method clearCppObjMethod;
private static Method getCppSessionMethod;
private static Method getGCParentMethod;
private static Method getSessionMethod;
// private static Method getStringArrayPropertyMethod;
private static Method getWeakMethod;
private static Method isDeadMethod;
private static Method isInvalidMethod;
private static Method isEqualMethod;
private static Method markInvalidMethod;
// private static Method notImplementedMethod;
private static Method validateObjArgMethod;
// private static Method restoreObjectMethod;
private static final Object[] EMPTY_ARRAY = null;
/** the class id of this object type (implemented as precaution) **/
final int clsid;
/** The wrapperFactory we are from **/
// private final WrapperFactory factory_;
static {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
checkArgMethod = lotus.domino.local.NotesBase.class.getDeclaredMethod("CheckArg", Object.class);
checkArgMethod.setAccessible(true);
checkObjectMethod = lotus.domino.local.NotesBase.class.getDeclaredMethod("CheckObject", (Class<?>[]) null);
checkObjectMethod.setAccessible(true);
checkObjectActiveMethod = lotus.domino.local.NotesBase.class.getDeclaredMethod("CheckObjectActive", (Class<?>[]) null);
checkObjectActiveMethod.setAccessible(true);
clearCppObjMethod = lotus.domino.local.NotesBase.class.getDeclaredMethod("ClearCppObj", (Class<?>[]) null);
clearCppObjMethod.setAccessible(true);
getCppObjMethod = lotus.domino.local.NotesBase.class.getDeclaredMethod("GetCppObj", (Class<?>[]) null);
getCppObjMethod.setAccessible(true);
getCppSessionMethod = lotus.domino.local.NotesBase.class.getDeclaredMethod("GetCppSession", (Class<?>[]) null);
getCppSessionMethod.setAccessible(true);
getGCParentMethod = lotus.domino.local.NotesBase.class.getDeclaredMethod("getGCParent", (Class<?>[]) null);
getGCParentMethod.setAccessible(true);
getSessionMethod = lotus.domino.local.NotesBase.class.getDeclaredMethod("getSession", (Class<?>[]) null);
getSessionMethod.setAccessible(true);
getWeakMethod = lotus.domino.local.NotesBase.class.getDeclaredMethod("getWeak", (Class<?>[]) null);
getWeakMethod.setAccessible(true);
isDeadMethod = lotus.domino.local.NotesBase.class.getDeclaredMethod("isDead", (Class<?>[]) null);
isDeadMethod.setAccessible(true);
isInvalidMethod = lotus.domino.local.NotesBase.class.getDeclaredMethod("isInvalid", (Class<?>[]) null);
isInvalidMethod.setAccessible(true);
isEqualMethod = lotus.domino.local.NotesBase.class.getDeclaredMethod("isEqual", Long.TYPE);
isEqualMethod.setAccessible(true);
markInvalidMethod = lotus.domino.local.NotesBase.class.getDeclaredMethod("markInvalid", (Class<?>[]) null);
markInvalidMethod.setAccessible(true);
validateObjArgMethod = lotus.domino.local.NotesBase.class.getDeclaredMethod("validateObjArg", Object.class,
Boolean.TYPE);
validateObjArgMethod.setAccessible(true);
return null;
}
});
} catch (Exception e) {
e.printStackTrace();
DominoUtils.handleException(e);
}
}
/**
* returns the cpp_id. DO NOT REMOVE. Otherwise native funtions won't work
*
* @return the cpp_id
*/
public final long GetCppObj() {
try {
return ((Long) getCppObjMethod.invoke(getDelegate(), EMPTY_ARRAY)).longValue();
} catch (Exception e) {
DominoUtils.handleException(e);
return 0L;
}
}
protected static final long GetCppObj(final lotus.domino.Base obj) {
try {
if (obj instanceof Base) {
return ((Long) getCppObjMethod.invoke(toLotus(obj), EMPTY_ARRAY)).longValue();
} else {
return ((Long) getCppObjMethod.invoke(obj, EMPTY_ARRAY)).longValue();
}
} catch (Exception e) {
DominoUtils.handleException(e);
return 0L;
}
}
/**
* returns the cpp-session id. Needed for some BackendBridge functions
*
* @return the cpp_id of the session
*/
public final long GetCppSession() {
try {
return ((Long) getCppSessionMethod.invoke(getDelegate(), EMPTY_ARRAY)).longValue();
} catch (Exception e) {
DominoUtils.handleException(e);
return 0L;
}
}
/** The parent/ancestor. */
protected P parent;
public long parentCppId;
/**
* Find the parent if no one was specified
*
* @param delegate
* @return
*/
protected P findParent(final WrapperFactory wf, final D delegate, final int i) throws NotesException {
throw new UnsupportedOperationException("You must specify a valid parent when creating a " + getClass().getName());
}
/**
* Returns the class-id. Currently not used
*
* @return
*/
int GetClassID() {
return clsid;
}
// public static class WrapCounter extends ThreadLocal<Long> {
//
// @Override
// protected Long initialValue() {
// return new Long(0);
// }
//
// public void increment() {
// long cur = super.get();
// super.set(cur++);
// }
// }
// public static WrapCounter traceWrapCount = new WrapCounter();
//
// public static ThreadLocal<Long> traceMinDelta = new ThreadLocal<Long>() {
// @Override
// protected Long initialValue() {
// return Long.MAX_VALUE;
// }
//
// @Override
// public void set(final Long value) {
// if (value < super.get()) {
// super.set(value);
// // System.out.println("New min delta discovered: " + value);
// }
// }
// };
//
// public static ThreadLocal<Long> traceMaxDelta = new ThreadLocal<Long>() {
// @Override
// protected Long initialValue() {
// return Long.MIN_VALUE;
// }
//
// @Override
// public void set(final Long value) {
// long curValue = super.get();
// if (value > curValue) {
// if ((curValue - value) > 100000) {
// System.out.println("Jump greater than 100000 when we wrapped object count " + traceWrapCount.get());
// }
// super.set(value);
// // System.out.println("New max delta discovered: " + value);
// }
// }
// };
// /**
// * Gets the parent.
// *
// * @return the parent
// */
// protected final P getAncestor(final int deprecated) {
// return ancestor;
// }
//
// public final P getParent() {
// return ancestor;
// }
/**
* Instantiates a new base.
*
* @param delegate
* the delegate
* @param parent
* the parent (may be null)
* @param wf
* the wrapperFactory
* @param cppId
* the cpp-id
* @param classId
* the class id
*/
protected Base(final D delegate, final P parent, final int classId) {
if (parent == null) {
throw new NullPointerException("parent must not be null");
}
this.parent = parent;
clsid = classId;
if (delegate instanceof lotus.domino.local.NotesBase) {
setDelegate(delegate, false);
} else if (delegate != null) {
// normally you won't get here if you come from fromLotus
throw new IllegalArgumentException("Why are you wrapping a non-Lotus object? " + delegate.getClass().getName());
}
}
/**
* constructor for no arg child objects (deserialzation)
*/
protected Base(final int classId) {
clsid = classId;
}
/**
* Sets the delegate on init or if resurrect occurred
*
* @param delegate
* the delegate
* @param cppId
* the cpp-id
*/
protected abstract void setDelegate(final D delegate, boolean fromResurrect);
// /**
// * Gets the lotus id.
// *
// * @param base
// * the base
// * @return the lotus id
// */
// protected static long getLotusId(final lotus.domino.Base base) {
//
// // try {
// // if (base instanceof lotus.domino.local.NotesBase) {
// // return ((Long) getCppObjMethod.invoke(base, EMPTY_ARRAY)).longValue();
// // } else if (base instanceof org.openntf.domino.impl.Base) {
// // return ((org.openntf.domino.impl.Base<?, ?, ?>) base).GetCppObj();
// // }
// // } catch (Exception e) {
// // }
// return 0L;
// }
/**
* Checks if the lotus object is invalid. A object is invalid if it is recycled by the java side.
*
* i.E.: Some Java code has called base.recycle();
*
* @param base
* the base
* @return true, if is recycled
*/
protected static boolean isInvalid(final lotus.domino.Base base) {
if (base == null) {
return true;
}
try {
return ((Boolean) isInvalidMethod.invoke(base, EMPTY_ARRAY)).booleanValue();
} catch (Exception e) {
DominoUtils.handleException(e);
return true;
}
}
/**
* Checks if is dead. A object is dead if it is invalid (=recycled by java) or if it's cpp-object = 0.
*
* This happens if the parent was recycled.
*
* @param base
* the base
* @return true, if is recycled
*/
public static boolean isDead(final lotus.domino.Base base) {
if (base == null) {
return true;
}
try {
return ((Boolean) isDeadMethod.invoke(base, EMPTY_ARRAY)).booleanValue();
} catch (Exception e) {
DominoUtils.handleException(e);
return true;
}
}
/**
* Returns the session for a certain base object
*
* @param base
* @return
*/
protected static lotus.domino.Session getSession(final lotus.domino.Base base) {
if (base == null) {
return null;
}
try {
return ((lotus.domino.Session) getSessionMethod.invoke(base, EMPTY_ARRAY));
} catch (Exception e) {
DominoUtils.handleException(e);
return null;
}
}
// /**
// * Gets the delegate.
// *
// * @param wrapper
// * the wrapper
// * @return the delegate
// */
// @SuppressWarnings("rawtypes")
// public static lotus.domino.Base getDelegate(final lotus.domino.Base wrapper) {
// if (wrapper instanceof org.openntf.domino.impl.Base) {
// return ((org.openntf.domino.impl.Base) wrapper).getDelegate();
// }
// return wrapper;
// }
/**
* Gets the delegate.
*
* @return the delegate
*/
protected D getDelegate() {
D ret = getDelegate_unchecked();
if (this instanceof Resurrectable && isDead(ret)) {
if (log_.isLoggable(Level.FINE)) {
log_.fine("[" + Thread.currentThread().getId() + "] Resurrecting " + getClass().getName() + " '" + super.hashCode() + "'");
}
resurrect();
if (log_.isLoggable(Level.FINE)) {
log_.fine(
"[" + Thread.currentThread().getId() + "] Resurrect " + getClass().getName() + " '" + super.hashCode() + "' done");
}
ret = getDelegate_unchecked();
}
return ret;
}
protected abstract D getDelegate_unchecked();
protected void resurrect() {
throw new AbstractMethodError();
}
// wrap objects. Delegate this to the wrapperFactory
/**
* Wraps objects. Delegate to WrapperFactory
*
* @see org.openntf.domino.WrapperFactory#fromLotus(lotus.domino.Base, FactorySchema, org.openntf.domino.Base)
*/
@SuppressWarnings({ "rawtypes" })
protected <T1 extends org.openntf.domino.Base, D1 extends lotus.domino.Base, P1 extends org.openntf.domino.Base> T1 fromLotus(
final D1 lotus, final FactorySchema<T1, D1, P1> schema, final P1 parent) {
return getFactory().fromLotus(lotus, schema, parent);
}
/**
* Wraps a collection. Delegate to WrapperFactory
*
* @see org.openntf.domino.WrapperFactory#fromLotus(Collection, FactorySchema, org.openntf.domino.Base)
*/
@SuppressWarnings({ "rawtypes" })
<T1 extends org.openntf.domino.Base, D1 extends lotus.domino.Base, P1 extends org.openntf.domino.Base> Collection<T1> fromLotus(
final Collection<?> lotusColl, final FactorySchema<T1, D1, P1> schema, final P1 parent) {
return getFactory().fromLotus(lotusColl, schema, parent);
}
/**
* Wraps a collection and returns it as vector. Delegate to WrapperFactory
*
* @see org.openntf.domino.WrapperFactory#fromLotusAsVector(Collection, FactorySchema, org.openntf.domino.Base)
*/
@SuppressWarnings({ "rawtypes" })
protected <T1 extends org.openntf.domino.Base, D1 extends lotus.domino.Base, P1 extends org.openntf.domino.Base> Vector<T1> fromLotusAsVector(
final Collection<?> lotusColl, final FactorySchema<T1, D1, P1> schema, final P1 parent) {
return getFactory().fromLotusAsVector(lotusColl, schema, parent);
}
/**
* Wraps column values
*
* @see org.openntf.domino.WrapperFactory#wrapColumnValues(Collection, org.openntf.domino.Session)
*/
protected Vector<Object> wrapColumnValues(final Collection<?> values, final org.openntf.domino.Session session) {
return getFactory().wrapColumnValues(values, session);
}
/**
* returns the WrapperFactory
*
* @return
*/
protected abstract WrapperFactory getFactory();
/*
* (non-Javadoc)
* This method recycles the delegate (and counts it as manual recycle)
*
* @see lotus.domino.Base#recycle()
* (it is NOT deprecated in the .impl. package as it is called in several places!)
*/
@Override
public void recycle() {
D delegate = getDelegate_unchecked();
if (isDead(delegate)) {
return;
}
s_recycle(delegate); // RPr: we must recycle the delegate, not "this". Do not call getDelegate as it may reinstantiate it
Factory.countManualRecycle(delegate.getClass());
}
// unwrap objects
/**
* gets the delegate
*
* @param wrapper
* the wrapper
* @param recycleThis
* adds the delegate to the list, if it has to be recycled.
* @return the delegate
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
protected static <T extends lotus.domino.Base> T toLotus(final T wrapper, final Collection recycleThis) {
if (wrapper instanceof org.openntf.domino.impl.Base) {
lotus.domino.Base ret = ((org.openntf.domino.impl.Base) wrapper).getDelegate();
if (wrapper instanceof Encapsulated && recycleThis != null) {
recycleThis.add(ret);
}
return (T) ret;
}
return wrapper;
}
/**
* Gets the delegate.
*
* @param wrapper
* the wrapper
* @return the delegate
*/
//
@SuppressWarnings({ "unchecked", "rawtypes" })
protected static <T extends lotus.domino.Base> T toLotus(final T wrapper) {
if (wrapper instanceof org.openntf.domino.impl.Base) {
return (T) ((org.openntf.domino.impl.Base) wrapper).getDelegate();
}
return wrapper;
}
/**
* To lotus.
*
* @param baseObj
* the base obj
* @return the lotus.domino. base version or the object itself, as appropriate
*/
@SuppressWarnings("rawtypes")
protected static Object toLotus(final Object baseObj) {
if (baseObj instanceof org.openntf.domino.impl.Base) {
return ((org.openntf.domino.impl.Base) baseObj).getDelegate();
}
return baseObj;
}
// /**
// * Unwraps anything to a dominofriendly object
// *
// * @deprecated use {@link #toDominoFriendly(Object, org.openntf.domino.Base, Collection)} instead
// * @param value
// * @param context
// * @return
// * @throws IllegalArgumentException
// */
// @Deprecated
// protected static Object toDominoFriendly(final Object value, final Session session) throws IllegalArgumentException {
// return toDominoFriendly(value, session, null);
// }
/**
* toItemFriendly: special case for "toDominoFriendly" that handles "DateTime" / "DateRange" correctly
*
* @param value
* The Object value to coerce into an Item-friendly type.
* @param context
* The context object.
* @param recycleThis
* A rolling collection of to-recycle objects
* @return An object value that can be stored in an Item.
* @throws IllegalArgumentException
* When the provided value cannot be successfully converted into an Item-safe value.
*/
protected static Object toItemFriendly(final Object value, final Session session, final Collection<lotus.domino.Base> recycleThis)
throws IllegalArgumentException {
if (value == null) {
log_.log(Level.INFO, "Trying to convert a null argument to Domino friendly. Returning null...");
return null;
}
if (value instanceof lotus.domino.Base) {
if (value instanceof lotus.domino.Name) {
// Names are written as canonical
try {
return ((lotus.domino.Name) value).getCanonical();
} catch (NotesException e) {
DominoUtils.handleException(e);
}
} else if (value instanceof org.openntf.formula.DateTime) {
return javaToDominoFriendly(value, session, recycleThis);
} else if (value instanceof org.openntf.domino.DateTime || value instanceof org.openntf.domino.DateRange) {
// according to documentation, these datatypes should be compatible to write to a field ... but DateRanges make problems
return toLotus((org.openntf.domino.Base<?>) value, recycleThis);
} else if (value instanceof lotus.domino.DateTime || value instanceof lotus.domino.DateRange) {
return value;
}
throw new IllegalArgumentException("Cannot convert to Domino friendly from type " + value.getClass().getName());
} else if (value instanceof Collection) {
if (isFriendlyVector(value)) {
return value;
} else {
Collection<?> coll = (Collection<?>) value;
Vector<Object> dominoFriendlyVec = new Vector<Object>(coll.size());
for (Object valNode : coll) {
if (valNode != null) { // CHECKME: Should NULL values discarded?
dominoFriendlyVec.add(toItemFriendly(valNode, session, recycleThis));
}
}
return dominoFriendlyVec;
}
} else {
return javaToDominoFriendly(value, session, recycleThis);
}
}
protected static boolean isFriendlyVector(final Object value) {
if (!(value instanceof Vector)) {
return false;
}
for (Object v : (Vector<?>) value) {
if (v instanceof String || v instanceof Integer || v instanceof Double) {
// ok
} else {
return false;
}
}
return true;
}
/**
*
* <p>
* Attempts to convert a provided scalar value to a "Domino-friendly" data type like DateTime, String, etc. Currently, the data types
* supported are the already-Domino-friendly ones, Number, Date, Calendar, and CharSequence.
* </p>
*
* @param value
* The incoming non-collection value
* @param context
* The context Base object, for finding the correct session
* @return The Domino-friendly conversion of the object, or the object itself if it is already usable.
* @throws IllegalArgumentException
* When the object is not convertible.
*/
@SuppressWarnings("rawtypes")
protected static Object toDominoFriendly(final Object value, final Session session, final Collection<lotus.domino.Base> recycleThis)
throws IllegalArgumentException {
if (value == null) {
log_.log(Level.INFO, "Trying to convert a null argument to Domino friendly. Returning null...");
return null;
}
//Extended in order to deal with Arrays
if (value.getClass().isArray()) {
int i = Array.getLength(value);
java.util.Vector<Object> result = new java.util.Vector<Object>(i);
for (int k = 0; k < i; ++k) {
Object o = Array.get(value, k);
result.add(toDominoFriendly(o, session, recycleThis));
}
return result;
}
if (value instanceof Collection) {
java.util.Vector<Object> result = new java.util.Vector<Object>();
Collection<?> coll = (Collection) value;
for (Object o : coll) {
result.add(toDominoFriendly(o, session, recycleThis));
}
return result;
}
if (value instanceof org.openntf.domino.Base) {
// this is a wrapper
return toLotus((org.openntf.domino.Base) value, recycleThis);
} else if (value instanceof lotus.domino.Base) {
// this is already domino friendly
return value;
} else {
return javaToDominoFriendly(value, session, recycleThis);
}
}
/**
* converts a lot of java types to domino-friendly types
*
* @param value
* @param context
* @param recycleThis
* @return
*/
private static Object javaToDominoFriendly(final Object value, final Session session, final Collection<lotus.domino.Base> recycleThis) {
//FIXME NTF This stuff should really defer to TypeUtils. We should do ALL type coercion in that utility class
if (value instanceof Integer || value instanceof Double) {
return value;
} else if (value instanceof String) {
return value;
} else if (value.getClass().isPrimitive()) {
//FIXME: NTF IS A COMPLETE HACK!!!! (but we just want to know if it'll fix PWithers' problem)
Class<?> cl = value.getClass();
if (cl == Boolean.TYPE) {
if ((Boolean) value) {
return "1";
} else {
return "0";
}
}
} else if (value instanceof Boolean) {
if ((Boolean) value) {
return "1";
} else {
return "0";
}
} else if (value instanceof Character) {
return value.toString();
}
// Now for the illegal-but-convertible types
if (value instanceof Number) {
// TODO Check if this is greater than what Domino can handle and serialize if so
// CHECKME: Is "doubleValue" really needed. (according to help.nsf only Integer and Double is supported, so keep it)
return ((Number) value).doubleValue();
} else if (value instanceof java.util.Date || value instanceof java.util.Calendar
|| value instanceof org.openntf.formula.DateTime) {
lotus.domino.Session lsess = toLotus(session);
try {
lotus.domino.DateTime dt = null;
if (value instanceof java.util.Date) {
dt = lsess.createDateTime((java.util.Date) value);
} else if (value instanceof org.openntf.formula.DateTime) {
org.openntf.formula.DateTime fdt = (org.openntf.formula.DateTime) value;
dt = lsess.createDateTime(fdt.toJavaDate());
if (fdt.isAnyDate()) {
dt.setAnyDate();
}
if (fdt.isAnyTime()) {
dt.setAnyTime();
}
} else {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
java.util.Calendar intermediate = (java.util.Calendar) value;
dt = lsess.createDateTime(sdf.format(intermediate.getTime()) + " " + intermediate.getTimeZone().getID());
}
if (recycleThis != null) {
recycleThis.add(dt);
}
return dt;
} catch (Throwable t) {
DominoUtils.handleException(t);
return null;
}
// return toLotus(Factory.getSession(context).createDateTime((java.util.Date) value));
} else if (value instanceof CharSequence) {
return value.toString();
// } else if (value instanceof CaseInsensitiveString) { // CaseInsensitiveString is a CharSequence
// return value.toString();
} else if (value instanceof Pattern) {
return ((Pattern) value).pattern();
} else if (value instanceof Class<?>) {
return ((Class<?>) value).getName();
} else if (value instanceof Enum<?>) {
return ((Enum<?>) value).getDeclaringClass().getName() + " " + ((Enum<?>) value).name();
} else if (value instanceof Formula) {
return ((Formula) value).getExpression();
} else if (value instanceof NoteCoordinate) {
return ((NoteCoordinate) value).toString();
}
throw new IllegalArgumentException("Cannot convert to Domino friendly from type " + value.getClass().getName());
}
// /**
// * To domino friendly.
// *
// * @deprecated use {@link #toDominoFriendly(Collection, org.openntf.domino.Base, Collection)}
// * @param values
// * the values
// * @param context
// * the context
// * @return the vector
// * @throws IllegalArgumentException
// * the illegal argument exception
// */
// @Deprecated
// protected static java.util.Vector<Object> toDominoFriendly(final Collection<?> values, final Session session)
// throws IllegalArgumentException {
// java.util.Vector<Object> result = new java.util.Vector<Object>();
// for (Object value : values) {
// result.add(toDominoFriendly(value, session));
// }
// return result;
// }
/**
*
* @param values
* the values
* @param context
*
* @param recycleThis
* @return
* @throws IllegalArgumentException
*/
protected static java.util.Vector<Object> toDominoFriendly(final Collection<?> values, final Session session,
final Collection<lotus.domino.Base> recycleThis) throws IllegalArgumentException {
java.util.Vector<Object> result = new java.util.Vector<Object>();
for (Object value : values) {
result.add(toDominoFriendly(value, session, recycleThis));
}
return result;
}
/**
* To lotus.
*
* @param values
* the values
* @return the java.util. vector
*/
protected static java.util.Vector<Object> toLotus(final Collection<?> values) {
if (values == null) {
return null;
} else {
java.util.Vector<Object> result = new java.util.Vector<Object>(values.size());
for (Object value : values) {
if (value instanceof lotus.domino.Base) {
result.add(toLotus((lotus.domino.Base) value));
} else {
result.add(value);
}
}
return result;
}
}
/**
* Recycle.
*
* @param base
* the base
* @return true, if successful
*/
protected static boolean s_recycle(final lotus.domino.Base base) {
if (base == null || base instanceof org.openntf.domino.Base) {
return false; // wrappers and null objects are not recycled!
}
boolean result = false;
lotus.domino.DateTime sdtAux = null;
lotus.domino.DateTime edtAux = null;
//if (!isLocked(base)) {
try {
if (base instanceof lotus.domino.local.DateRange) { //NTF - check to see if we have valid start/end dates to prevent crashes in 9.0.1
lotus.domino.local.DateRange dr = (lotus.domino.local.DateRange) base;
if (dr.getStartDateTime() == null || dr.getEndDateTime() == null) {
lotus.domino.Session rawsession = toLotus(Base.getSession(base));
sdtAux = rawsession.createDateTime("2001/01/01");
edtAux = rawsession.createDateTime("2001/02/02");
dr.setStartDateTime(sdtAux);
dr.setEndDateTime(edtAux);
}
}
base.recycle();
result = true;
} catch (Throwable t) {
Factory.countRecycleError(base.getClass());
DominoUtils.handleException(t);
// shikata ga nai
} finally {
try {
if (sdtAux != null) {
sdtAux.recycle();
}
if (edtAux != null) {
edtAux.recycle();
}
} catch (NotesException ne) { // Now it's enough
}
}
//} else {
// System.out.println("Not recycling a " + base.getClass().getName() + " because it's locked.");
//}
return result;
}
/**
* recycle ALL native objects
*
* @param o
* the object(s) to recycle
*/
protected static void s_recycle(final Object o) {
// NTF this is for recycling of encapsulated objects like DateTime and Name
// RPr ' do we need an extra method here?
if (o instanceof Collection) {
Collection<?> c = (Collection<?>) o;
if (!c.isEmpty()) {
for (Object io : c) {
s_recycle((lotus.domino.Base) io);
}
}
} else if (o instanceof lotus.domino.Base) {
s_recycle((lotus.domino.Base) o);
}
}
// /**
// * recycle encapsulated objects
// *
// * @param o
// * the objects to recycle (only encapsulated are recycled)
// */
// public static void enc_recycle(final Object o) {
// // NTF this is for recycling of encapsulated objects like DateTime and Name
// // RPr ' do we need an extra method here?
// if (o instanceof Collection) {
// Collection<?> c = (Collection<?>) o;
// if (!c.isEmpty()) {
// for (Object io : c) {
// if (io instanceof lotus.domino.DateTime || io instanceof lotus.domino.DateRange || io instanceof lotus.domino.Name) {
// s_recycle((lotus.domino.Base) io);
// }
// }
// }
// } else if (o instanceof lotus.domino.DateTime || o instanceof lotus.domino.DateRange || o instanceof lotus.domino.Name) {
// s_recycle((lotus.domino.Base) o);
// }
//
// }
// /**
// * Checks if is recycled.
// *
// * @return true, if is recycled
// */
// public boolean isRecycled() {
// return recycled_;
// }
/*
* (non-Javadoc)
*
* @see lotus.domino.Base#recycle(java.util.Vector)
*/
@Override
@Deprecated
@SuppressWarnings("rawtypes")
public void recycle(final Vector arg0) {
for (Object o : arg0) {
if (o instanceof org.openntf.domino.impl.Base) {
((org.openntf.domino.impl.Base) o).recycle();
} else if (o instanceof lotus.domino.local.NotesBase) {
s_recycle((lotus.domino.local.NotesBase) o);
}
}
}
private List<IDominoListener> listeners_;
private transient Map<EnumEvent, List<IDominoListener>> listenerCache_;
// these are important to link deferred against, so that they aren't recycled.
// defered objects that have the same delegate build a circle, so that they aren't gc-ed as
// long as someone is holding a reference to at least one object of this circle.
protected Base<?, ?, ?> siblingWrapper_;
// The origin of the deferreds
// RPR: Currently, if you use multiple deferreds pointing to the same document, you MAY
// get unexpected results, because each Document caches different things.
// Normally, each document should route every method call to its origin!
protected T originOfDeferred_;
@Override
public final boolean hasListeners() {
if (originOfDeferred_ != null) {
return originOfDeferred_.hasListeners();
}
return listeners_ != null && !listeners_.isEmpty();
}
@Override
public final List<IDominoListener> getListeners() {
if (originOfDeferred_ != null) {
return originOfDeferred_.getListeners();
}
if (listeners_ == null) {
listeners_ = new ArrayList<IDominoListener>();
}
return listeners_;
}
@Override
public final void addListener(final IDominoListener listener) {
if (originOfDeferred_ != null) {
originOfDeferred_.addListener(listener);
} else {
listenerCache_ = null;
getListeners().add(listener);
}
}
@Override
public final void removeListener(final IDominoListener listener) {
if (originOfDeferred_ != null) {
originOfDeferred_.removeListener(listener);
} else {
listenerCache_ = null;
getListeners().remove(listener);
}
}
@Override
@SuppressWarnings("unchecked")
public final List<IDominoListener> getListeners(final EnumEvent event) {
if (originOfDeferred_ != null) {
return originOfDeferred_.getListeners(event);
}
if (!hasListeners()) {
return Collections.EMPTY_LIST;
}
if (listenerCache_ == null) {
listenerCache_ = new FastMap<EnumEvent, List<IDominoListener>>();
}
List<IDominoListener> result = listenerCache_.get(event);
if (result == null) {
result = new ArrayList<IDominoListener>();
for (IDominoListener listener : getListeners()) {
for (EnumEvent curEvent : listener.getEventTypes()) {
if (curEvent.equals(event)) {
result.add(listener);
break;
}
}
}
listenerCache_.put(event, result);
}
return result;
}
@Override
public final boolean fireListener(final IDominoEvent event) {
if (originOfDeferred_ != null) {
return originOfDeferred_.fireListener(event);
}
boolean result = true;
if (!hasListeners()) {
return true;
}
List<IDominoListener> listeners = getListeners(event.getEvent());
if (listeners == null || listeners.isEmpty()) {
return true;
}
for (IDominoListener listener : listeners) {
try {
if (!listener.eventHappened(event)) {
result = false;
break;
}
} catch (Throwable t) {
DominoUtils.handleException(t);
}
}
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return getDelegate().toString();
}
// ------------ native functions - to be as much compatible to the lotus.domino.local...
// Methods that have no meaningful implementation throw a exception
@Deprecated
public boolean needsGui() {
log_.fine("needsGui called");
return false;
}
@Deprecated
public void dontUseGui() {
log_.fine("dontUseGui called");
}
@Deprecated
public void okToUseGui() {
log_.fine("okToUseGui called");
}
@Deprecated
public boolean avoidingGui() {
log_.fine("avoidingGui called");
return true;
}
// ---- package private
@Deprecated
void markInvalid() {
throw new NotImplementedException();
}
@Deprecated
void ClearCppObj() {
throw new NotImplementedException();
}
@Deprecated
Object getWeak() {
throw new NotImplementedException();
}
@Deprecated
lotus.domino.Session getSession() {
throw new NotImplementedException();
}
@Deprecated
Object getGCParent() {
throw new NotImplementedException();
}
@Deprecated
boolean isInvalid() {
throw new NotImplementedException();
}
void restoreObject(final lotus.domino.Session paramSession, final long paramLong) {
throw new NotImplementedException();
}
@Deprecated
void CheckObject() {
throw new NotImplementedException();
}
@Deprecated
void CheckObjectActive() {
throw new NotImplementedException();
}
@Override
public boolean isDead() {
return isDead(getDelegate_unchecked());
}
@Deprecated
void CheckArg(final Object paramObject) {
throw new NotImplementedException();
}
@Deprecated
boolean isEqual(final long paramLong) {
throw new NotImplementedException();
}
@SuppressWarnings("rawtypes")
@Deprecated
Vector PropGetVector(final int paramInt) {
throw new NotImplementedException();
}
@Deprecated
void validateObjArg(final Object paramObject, final boolean paramBoolean) {
throw new NotImplementedException();
}
@SuppressWarnings("rawtypes")
@Deprecated
Vector getStringArrayProperty(final int paramInt) {
throw new NotImplementedException();
}
private static final int EXTERNALVERSIONUID = 20141205; // The current date (when it was implemented)
protected void writeExternal(final ObjectOutput out) throws IOException {
out.writeInt(EXTERNALVERSIONUID);
out.writeObject(parent);
// factory is final and unchangeable
// I also do not know if serializing listeners will make sense, so I don't do it
}
@SuppressWarnings("unchecked")
protected void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
int version = in.readInt();
if (version != EXTERNALVERSIONUID) {
throw new InvalidClassException("Cannot read dataversion " + version);
}
parent = (P) in.readObject();
}
protected void readResolveCheck(final Object expected, final Object given) {
if (expected == null ? given != null : !expected.equals(given)) {
log_.warning("Deserializing different " + getClass().getSimpleName() + ". Given: " + given + ", expected: " + expected);
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + clsid;
result = prime * result + ((parent == null) ? 0 : parent.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Base)) {
return false;
}
Base<?, ?, ?> other = (Base<?, ?, ?>) obj;
if (clsid != other.clsid) {
return false;
}
if (parent == null) {
if (other.parent != null) {
return false;
}
} else if (!parent.equals(other.parent)) {
return false;
}
return true;
}
protected void setNewSibling(final org.openntf.domino.impl.Base<?, ?, ?> oldWrapper) {
listeners_ = oldWrapper.listeners_;
}
@SuppressWarnings("unchecked")
protected void linkToExisting(final Base<?, ?, ?> oldWrapper) {
// link the implWrapper into the circle
if (oldWrapper.siblingWrapper_ == null) {
oldWrapper.siblingWrapper_ = oldWrapper;
}
siblingWrapper_ = oldWrapper.siblingWrapper_;
oldWrapper.siblingWrapper_ = this;
// link to origin
originOfDeferred_ = (T) oldWrapper.originOfDeferred_;
// if the oldWrapper has no origin, it IS the origin
if (originOfDeferred_ == null) {
originOfDeferred_ = (T) oldWrapper;
}
}
}