/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright © 2012 ForgeRock AS. All rights reserved.
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* http://forgerock.org/license/CDDLv1.0.html
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at http://forgerock.org/license/CDDLv1.0.html
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
* $Id$
*/
package org.forgerock.openicf.salesforce.resources;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.util.Set;
import java.util.Map.Entry;
import org.forgerock.openicf.salesforce.SalesforceConnection;
import org.forgerock.openicf.salesforce.annotation.ICResource;
import org.forgerock.openicf.salesforce.meta.MetaAttribute;
import org.forgerock.openicf.salesforce.meta.MetaResource;
import org.forgerock.openicf.salesforce.translators.IFieldTranslator;
public abstract class AbstractResource<T extends Serializable> {
public static final String SELF_REFERENCE = "this";
private boolean modified = false;
private MetaResource resource;
private WeakReference<T> entityRef;
private WeakReference<SalesforceConnection> connectionRef;
public AbstractResource(T entity, SalesforceConnection connection) {
this.entityRef = new WeakReference<T>(entity);
this.connectionRef = new WeakReference<SalesforceConnection>(connection);
// Create meta resource
ICResource res = getClass().getAnnotation(ICResource.class);
resource = new MetaResource(res, (Class<? extends AbstractResource<?>>) getClass());
registerTranslators();
}
/**
* This method can be used to initialize lazy loaded fields.
*/
public void initLazyLoadedFields(Set<MetaAttribute> attributes) {
// noop
}
private void registerTranslators() {
SalesforceConnection conn = getConnection();
for (Entry<String, Class<? extends IFieldTranslator<?, ?>>> entry : resource.getFieldTranslators().entrySet()) {
conn.registerTranslator(getClass(), entry.getKey(), entry.getValue());
}
}
public String getIdentifier() {
String result = null;
return result;
}
/**
* Returns the weak referenced entity. If the entity has been
* garbage collected, this method may return null.
*
* @return T the entity.
*/
public T getEntity() {
T result = entityRef.get();
if (result == null) {
throw new IllegalStateException("Entity was null. Probably garbage collected..");
}
return result;
}
/**
* Returns the weak referenced unsaved entity. If the entity has been
* garbage collected, this method may return null.
*
* @return
*/
public T getUnsavedEntity() {
return getEntity();
}
/**
* Returns the weak referenced connection. If the connection has
* been garbage collected, this method may return null.
*
* @return {@link SalesforceConnection} the connection.
*/
protected SalesforceConnection getConnection() {
SalesforceConnection result = connectionRef.get();
if (result == null) {
throw new IllegalStateException("Connection was null. Must have been garbage collected.");
}
return result;
}
public Object getProperty(String property) {
Object value = internalGetProperty(property);
IFieldTranslator translator = internalGetFieldTranslator(property);
return translator == null ? value : translator.fromInternal(value);
}
public void setProperty(String property, Object value) {
Object translatedValue = null;
IFieldTranslator translator = internalGetFieldTranslator(property);
if (translator != null) {
translatedValue = translator.fromExternal(value);
} else {
translatedValue = value;
}
internalSetProperty(property, translatedValue);
}
private Object internalGetProperty(String property) throws RuntimeException {
return null;
}
private void internalSetProperty(String property, Object value) throws RuntimeException {
}
/**
* This method is called during the {@link #setProperty(String, Object)} method
* to verify if the property should actually be changed or not. Subclasses may
* override this method to provide additional behavior.
* <p>
* If this method returns <code>false</code>, then the property will not be
* changed.
* </p>
*
* @param property the property being changed.
* @param oldValue the old value of the property.
* @param newValue the new value of the property.
* @return <code>true</code> if a change occurred, <code>false</code> otherwise.
*/
protected boolean verifyChange(String property, Object oldValue, Object newValue) {
if ((oldValue == null) && (newValue == null)) {
return false;
}
if (((oldValue == null) && (newValue != null)) || ((oldValue != null) && (newValue == null))) {
return true;
}
return !oldValue.equals(newValue);
}
/**
* This method is called before any modification is performed on
* the underlying entity. Clients that requires special processing
* in this case should override this method.
*
* @param property the property being changed.
*/
protected void beforeModification(String property) {
// noop
}
/**
* Call this method after all modifications has been
* committed to the entity. This method will reset the
* internal modification flag. Sub-classes can override
* this method to provide special processing, but should
* make sure to call super in order to update the state.
*/
public void modificationFinished() {
modified = false;
}
private IFieldTranslator<?, ?> internalGetFieldTranslator(String property) {
SalesforceConnection conn = getConnection();
if (conn != null) {
return conn.getTranslator(getClass(), property);
}
return null;
}
}