/*
* 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.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import lotus.domino.NotesException;
import org.openntf.domino.Base;
import org.openntf.domino.utils.DominoUtils;
import org.openntf.domino.utils.Factory;
/**
* @author praml
*
* DominoReference tracks the lifetime of reference object and recycles delegate if reference object is GCed
*
*/
public class DominoReference extends WeakReference<Base<?>> {
/** The Constant log_. */
private static final Logger log_ = Logger.getLogger(DominoReference.class.getName());
/** The delegate_. This is the wrapped Object */
private lotus.domino.Base delegate_;
private transient int hashcode_;
private final long cppId_;
private boolean noRecycle = false;
/**
* Instantiates a new domino reference.
*
* @param reference
* the wrapper to track
* @param q
* the q
* @param delegate
* the delegate
*/
public DominoReference(final Base<?> reference, final ReferenceQueue<Object> q, final lotus.domino.Base delegate, final long cppId) {
super(reference, q);
// Because the reference separately contains a pointer to the delegate object, it's still available even
// though the wrapper is null
this.delegate_ = delegate;
this.cppId_ = cppId;
}
//void clearLotusReference() {
// delegate_ = null;
//}
/**
* Recycle.
*/
boolean recycle() {
boolean result = false;
if (delegate_ != null && !noRecycle) {
try {
if (org.openntf.domino.impl.Base.isDead(delegate_)) {
// the object is dead, so let's see who recycled this
if (org.openntf.domino.impl.Base.isInvalid(delegate_)) {
// if it is also invalid, someone called recycle on the delegate object.
// this is already counted as manual recycle, so do not count twice
} else {
// otherwise, it's parent is recycled.
// TODO this should get counted on a own counter
Factory.countManualRecycle(delegate_.getClass());
}
} else {
// recycle the delegate, because no hard ref points to us.
delegate_.recycle();
result = true;
int total = Factory.countAutoRecycle(delegate_.getClass());
if (log_.isLoggable(Level.FINE)) {
if (total % 5000 == 0) {
log_.log(Level.FINE, "Auto-recycled " + total + " references");
}
}
}
} catch (NotesException e) {
Factory.countRecycleError(delegate_.getClass());
DominoUtils.handleException(e);
}
if (delegate_ instanceof lotus.domino.local.EmbeddedObject) {
// if the wrapper is out of scope and the element was an EmbeddedObject, we call markInvalid
// It does not matter if the object was already recycled/dead. MarkInvalid will internally just
// call "cleanupTempFile" (cannot throw an exception)
((lotus.domino.local.EmbeddedObject) delegate_).markInvalid();
}
}
return result;
}
/**
* Prevents that the delegate object will be really recycled. Autorecycle counting is done. - So you must ensure that you recycle the
* document yourself or wrap it again
*
* @param what
* The object to set to not recycle.
*/
public void setNoRecycle(final boolean what) {
if (noRecycle != what) {
if (what) {
Factory.countManualRecycle(delegate_.getClass()); // decrement counter, someone else will recycle this
} else {
// recycling is enabled again, so count it as active object
Factory.countLotus(delegate_.getClass()); // increment counter
}
}
noRecycle = what;
}
/**
* A WeakValue is equal to another WeakValue iff they both refer to objects that are, in turn, equal according to their own equals
* methods. Key is not checked here, because there might be "dummy" values without a key so that "contains" works
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof DominoReference)) {
return false;
}
Object ref1 = this.get();
Object ref2 = ((DominoReference) obj).get();
if (ref1 == ref2) {
return true;
}
if ((ref1 == null) || (ref2 == null)) {
return false;
}
return ref1.equals(ref2);
}
/**
*
*/
@Override
public int hashCode() {
if (hashcode_ == 0) {
Object ref = this.get();
hashcode_ = (ref == null) ? 0 : ref.hashCode();
}
return hashcode_;
}
lotus.domino.Base getDelegate() {
return delegate_;
}
long getCppId() {
return cppId_;
}
}