/*
* Copyright © 2013. Palomino Labs (http://palominolabs.com)
*
* 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.palominolabs.crm.sf.core;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import java.util.HashMap;
import java.util.Map;
import static java.util.Collections.unmodifiableMap;
/**
* @param <T> the type of relationship query result
* @param <U> the type to expose for sub objects
*/
@ThreadSafe
public abstract class AbstractSObject<T, U extends SObject> implements SObject {
/**
* id of the object. May be null.
*/
private final Id id;
/**
* name => value map.
*/
@GuardedBy("this")
private final Map<String, String> fields = new HashMap<String, String>();
/**
* The SF type of the object
*/
private final String type;
/**
* Map of relationship query names (e.g. "Contacts") to their query results
*/
@GuardedBy("this")
private final Map<String, T> relationshipQueryResults = new HashMap<String, T>();
@GuardedBy("this")
private final Map<String, U> relationshipSubObjects = new HashMap<String, U>();
protected AbstractSObject(@Nonnull String type, @Nullable Id id) {
this.type = type;
this.id = id;
}
@Override
@Nullable
public Id getId() {
return this.id;
}
@Override
@Nonnull
public String getType() {
return this.type;
}
@Override
public synchronized void setField(@Nonnull String name, @Nullable String value) {
this.fields.put(name, value);
}
@Override
@Nullable
public synchronized String getField(@Nonnull String name) {
return this.fields.get(name);
}
@Override
public synchronized boolean isFieldSet(@Nonnull String fieldName) {
return this.fields.containsKey(fieldName);
}
@Override
@Nonnull
public synchronized Map<String, String> getAllFields() {
return new HashMap<String, String>(this.fields);
}
@Override
public synchronized void setAllFields(@Nonnull Map<String, String> newFields) {
for (Map.Entry<String, String> entry : newFields.entrySet()) {
this.setField(entry.getKey(), entry.getValue());
}
}
@Override
@Nonnull
public synchronized String removeField(@Nonnull String key) {
return this.fields.remove(key);
}
/**
* Represents sub-query results like the Contacts in this parent-to-child query:
* <code>"SELECT Id, Name, AnnualRevenue, (SELECT Id, FirstName, Email FROM Contacts) FROM Account</code>
*
* @return map of relationship names to query results (which may need queryMore(), etc)
*/
@Nonnull
public synchronized Map<String, T> getRelationshipQueryResults() {
return unmodifiableMap(relationshipQueryResults);
}
/**
* Only used during SObject extraction from a stub result.
*
* @param relationshipName the relationship name
* @param queryResult the query result for that relationship subquery
*/
protected synchronized void setRelationshipQueryResultInner(@Nonnull String relationshipName,
@Nonnull T queryResult) {
this.relationshipQueryResults.put(relationshipName, queryResult);
}
/**
* Represents sub-objects like the Owner object (of type User) in this child-to-parent query:
*
* <code>SELECT Owner.Name FROM Account</code>
*
* @return map of relationship names to sub objects.
*/
@Nonnull
public synchronized Map<String, U> getRelationshipSubObjects() {
return unmodifiableMap(relationshipSubObjects);
}
/**
* @param relationshipName relationship name
* @param subObject the sub-object to add
*/
protected synchronized void setRelationshipSubObjectInner(@Nonnull String relationshipName,
@Nonnull U subObject) {
relationshipSubObjects.put(relationshipName, subObject);
}
}