package org.cloudgraph.web.sdo.adapter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudgraph.web.model.cache.ReferenceDataCache;
import org.cloudgraph.web.model.taxonomy.TaxonomyConstants;
import org.cloudgraph.web.sdo.categorization.Category;
import org.cloudgraph.web.sdo.core.PropertyCategorization;
import org.cloudgraph.web.sdo.meta.Classifier;
import org.cloudgraph.web.sdo.meta.Clazz;
import org.cloudgraph.web.sdo.meta.InstanceSpecification;
import org.cloudgraph.web.sdo.meta.InstanceValue;
import org.cloudgraph.web.sdo.meta.LiteralBoolean;
import org.cloudgraph.web.sdo.meta.LiteralClob;
import org.cloudgraph.web.sdo.meta.LiteralDate;
import org.cloudgraph.web.sdo.meta.LiteralDouble;
import org.cloudgraph.web.sdo.meta.LiteralFloat;
import org.cloudgraph.web.sdo.meta.LiteralInteger;
import org.cloudgraph.web.sdo.meta.LiteralLong;
import org.cloudgraph.web.sdo.meta.LiteralShort;
import org.cloudgraph.web.sdo.meta.LiteralString;
import org.cloudgraph.web.sdo.meta.Property;
import org.cloudgraph.web.sdo.meta.Slot;
import org.cloudgraph.web.sdo.meta.ValueSpecification;
import org.cloudgraph.web.util.BeanFinder;
/**
*/
public class InstanceSpecificationAdapter extends QueueAdapter
implements Serializable, Comparable<InstanceSpecificationAdapter> {
private static Log log = LogFactory.getLog(InstanceSpecificationAdapter.class);
private static final List<Object> EMPTY_LIST = new ArrayList<Object>();
private static final long serialVersionUID = 1L;
private InstanceSpecificationAdapter source;
protected int level;
protected int maxLevel;
protected InstanceSpecification ins;
protected Map<String, PropertyAdapter> properyMap;
protected List<PropertyAdapter> propertyList;
protected ReferenceDataCache cache;
protected ValueMap values = new ValueMap();
@SuppressWarnings("unused")
private InstanceSpecificationAdapter() {
this.cache = (new BeanFinder()).findReferenceDataCache();
cache.getInventoryPerspectiveModel(); // cache/load this taxonomy
cache.getOrderingModel(); // cache/load this taxonomy
}
public InstanceSpecificationAdapter(
InstanceSpecificationAdapter source,
InstanceSpecification ins,
List<PropertyAdapter> props,
int level, int maxLevel) {
this();
this.level = level;
this.maxLevel = maxLevel;
this.source = source;
this.ins = ins;
this.propertyList = props;
this.properyMap = new HashMap<String, PropertyAdapter>();
for (PropertyAdapter property : props) {
String name = property.getProperty().getName();
this.properyMap.put(name, property);
Object value = getValue(this.ins, property.getProperty());
// what the?
value = getValue(this.ins, property.getProperty());
if (value != null) {
this.values.put(name, value);
}
}
}
public InstanceSpecificationAdapter(
InstanceSpecification ins,
List<PropertyAdapter> props,
int level, int maxLevel) {
this(null, ins, props, level, maxLevel);
}
@Override
public int compareTo(InstanceSpecificationAdapter other) {
Object thisOrderingValue = getPrimaryOrderingValue(this.ins);
Object otherOrderingValue = getPrimaryOrderingValue(other.ins);
if (thisOrderingValue != null && otherOrderingValue != null) {
if (Comparable.class.isAssignableFrom(thisOrderingValue.getClass()))
{
Comparable thisValueComparable = (Comparable)thisOrderingValue;
return thisValueComparable.compareTo(otherOrderingValue);
}
}
// TODO Auto-generated method stub
return 0;
}
public InstanceSpecificationAdapter getSource() {
return source;
}
public InstanceSpecification getInstanceSpecification() {
return this.ins;
}
public Long getId() {
return ins.getSeqId();
}
public Map<String, Object> getValues() {
return this.values;
}
public String getClassName() {
if (ins.getClazz() != null) {
Clazz clzz = ins.getClazz();
if (clzz.getClassifier()!= null)
{
Classifier clss = clzz.getClassifier();
return clss.getName();
}
}
return "";
}
public String getCaption() {
return this.createCaption(this.ins,
this.properyMap.values());
}
public String toString() {
return getCaption();
}
protected String createCaption(InstanceSpecification inst,
Collection<PropertyAdapter> properties) {
StringBuilder buf = new StringBuilder();
for (PropertyAdapter adapter : properties) {
Property prop = adapter.getProperty();
Object value = getIdentifierValue(inst, prop);
if (value != null) {
buf.append(value);
buf.append(" ");
buf.append("\t");
}
}
String result = null;
if (buf.toString().trim().length() > 0)
result = buf.toString().trim();
else
result = String.valueOf(inst.getSeqId());
return result;
}
protected String createCaption2(InstanceSpecification instSpec,
List<Property> properties) {
StringBuilder buf = new StringBuilder();
for (Property prop : properties) {
Object value = getIdentifierValue(instSpec, prop);
if (value != null) {
buf.append(value);
buf.append(" ");
buf.append("\t");
}
}
String result = null;
if (buf.toString().trim().length() > 0)
result = buf.toString().trim();
else
result = String.valueOf(instSpec.getSeqId());
return result;
}
private Object getValue(InstanceSpecification instSpec, Property prop) {
Slot slot = getSlot(instSpec, prop.getSeqId());
if (slot != null) {
return getValue(instSpec, slot);
}
else {
if (prop.getLowerValue() == 1)
log.warn("no slot found for required property, "
+ instSpec.getClazz().getClassifier().getName() + "."
+ prop.getName());
}
return null;
}
private Object getIdentifierValue(InstanceSpecification instSpec, Property prop) {
if (prop.getPropertyCategorizationCount() > 0)
for (PropertyCategorization pc : prop.getPropertyCategorization()) {
Category cat = pc.getCategorization().getCategory();
Category cached = this.cache.getCategory(cat.getSeqId());
if (isIdentifierCat(cached)) {
Slot slot = getSlot(instSpec, prop.getSeqId());
if (slot != null) {
return getValue(instSpec, slot);
}
}
}
return null;
}
private Object getPrimaryOrderingValue(InstanceSpecification instSpec) {
for (PropertyAdapter adpater : this.properyMap.values()) {
Object value = getPrimaryOrderingValue(instSpec, adpater.getProperty());
if (value != null) {
return value;
}
}
return null;
}
private Object getPrimaryOrderingValue(InstanceSpecification instSpec, Property prop) {
if (prop.getPropertyCategorizationCount() > 0)
for (PropertyCategorization pc : prop.getPropertyCategorization()) {
Category cat = pc.getCategorization().getCategory();
Category cached = this.cache.getCategory(cat.getSeqId());
if (isPrimaryOrderingCat(cached)) {
Slot slot = getSlot(instSpec, prop.getSeqId());
if (slot != null) {
return getValue(instSpec, slot);
}
}
}
return null;
}
private boolean isIdentifierCat(Category current)
{
if (current != null) {
if (TaxonomyConstants.SYS_TAXONOMY_CAT_IDENT != current.getId())
return false; // FIXME; somehow
while (current != null) {
if (ReferenceDataCache.TAXONOMY_NAME_INVPM.equals(current.getName()))
return true;
current = current.getParent();
}
}
return false;
}
private boolean isPrimaryOrderingCat(Category current)
{
if (current != null) {
if (TaxonomyConstants.SYS_TAXONOMY_ORDERING_CAT_PRIMARY != current.getId())
return false; // FIXME; somehow
while (current != null) {
if (ReferenceDataCache.TAXONOMY_NAME_ORDERING.equals(current.getName()))
return true;
current = current.getParent();
}
}
return false;
}
protected Slot getSlot(InstanceSpecification instSpec,
Long propertySeqId) {
if (instSpec.getSlot() != null)
for (Slot slot : instSpec.getSlot()) {
long featureId = slot.getDefiningFeature().getSeqId();
if (featureId == propertySeqId.longValue()) {
return slot;
}
}
return null;
}
protected Object getValue(InstanceSpecification owner, Slot slot) {
try {
Property slotProp = slot.getDefiningFeature();
if (slotProp == null) {
log.warn("cannot determine multiplicity for slot/property - exiting");
return null;
}
// only assume property has a name at any particular instance level, and get its
// cached adapter for full info
PropertyAdapter propAdapter = this.properyMap.get(slotProp.getName());
if (propAdapter == null) {
throw new IllegalStateException("cannot determine multiplicity for slot/property");
}
if (propAdapter.getIsMany()) {
return getMultiValue(owner, slot);
}
else {
return getSingularValue(owner, slot);
}
}
catch (Throwable t) {
log.error(t.getMessage(), t);
return "";
}
}
protected Object getMultiValue(InstanceSpecification owner, Slot slot) {
List<Object> result = new ArrayList<Object>();
if (slot.getValueCount() > 0) {
if (slot.getValueCount() > 1)
log.warn("found multiple value specs for multi property '"
+ slot.getDefiningFeature().getName() + "' - ignoring");
ValueSpecification vs = slot.getValue(0);
return getMultiSpecificationValue(owner, slot, vs);
}
return result;
}
protected Object getSingularValue(InstanceSpecification owner, Slot slot) {
if (slot.getValueCount() > 0) {
if (slot.getValueCount() > 1)
log.warn("found multiple value specs for singular property '"
+ slot.getDefiningFeature().getName() + "' - ignoring");
ValueSpecification vs = slot.getValue(0);
return getSingularSpecificationValue(owner, slot, vs);
}
return ""; //FIXME: why does JSF demand this??
}
//FIXME: use its datatype
protected Object getSingularSpecificationValue(InstanceSpecification owner,
Slot slot, ValueSpecification valueSpec) {
if (valueSpec.getInstanceValueCount() > 0) {
if (this.level == this.maxLevel)
return null; // no more levels
List<PropertyAdapter> props = null;
InstanceValue iv = valueSpec.getInstanceValue(0);
if (iv.getFumlRepositoryInstance() != null) {
InstanceSpecification is = iv.getFumlRepositoryInstance();
InstanceSpecificationAdapter source = this.getSource();
if (source != null) {
if (source.getInstanceSpecification().equals(is))
return null; // skip its parent
}
if (props == null) { //FIXME: use its datatype
props = new ArrayList<PropertyAdapter>();
// FIXME no class in query here
List<Property> list = this.cache.getProperties(is.getClazz().getSeqId());
if (list != null)
for (Property p : list)
props.add(new PropertyAdapter(p));
}
if (is.getSeqId() == owner.getSeqId()) {
log.warn("instance linked to same instance ("
+ is.getSeqId() + ")");
return null; // recursion
}
return new InstanceSpecificationAdapter(
this, is, props, this.level + 1, this.maxLevel);
//log.info(is.dump());
}
}
else if (valueSpec.getLiteralStringCount() > 0)
return valueSpec.getLiteralString(0).getValue();
else if (valueSpec.getLiteralClobCount() > 0)
return valueSpec.getLiteralClob(0).getValue();
else if (valueSpec.getLiteralShortCount() > 0)
return valueSpec.getLiteralShort(0).getValue();
else if (valueSpec.getLiteralIntegerCount() > 0)
return valueSpec.getLiteralInteger(0).getValue();
else if (valueSpec.getLiteralLongCount() > 0)
return valueSpec.getLiteralLong(0).getValue();
else if (valueSpec.getLiteralFloatCount() > 0)
return valueSpec.getLiteralFloat(0).getValue();
else if (valueSpec.getLiteralDoubleCount() > 0)
return valueSpec.getLiteralDouble(0).getValue();
else if (valueSpec.getLiteralBooleanCount() > 0)
return valueSpec.getLiteralBoolean(0).getValue();
else if (valueSpec.getLiteralDateCount() > 0)
return valueSpec.getLiteralDate(0).getValue();
return null;
}
protected List<Comparable> getMultiSpecificationValue(InstanceSpecification owner,
Slot slot, ValueSpecification valueSpec) {
List<PropertyAdapter> props = null;
List<Comparable> list = new ArrayList<Comparable>();
if (valueSpec.getInstanceValueCount() > 0) {
if (this.level == this.maxLevel)
return list; // no more levels
for (InstanceValue iv : valueSpec.getInstanceValue()) {
if (iv.getFumlRepositoryInstance() == null)
continue;
InstanceSpecification is = iv.getFumlRepositoryInstance();
if (this.getSource() != null && this.getSource().getInstanceSpecification().equals(is))
continue; // skip its parent
if (props == null) { //FIXME: use its datatype
props = new ArrayList<PropertyAdapter>();
List<Property> plist = this.cache.getProperties(is.getClazz().getSeqId());
if (plist != null)
for (Property p : plist)
props.add(new PropertyAdapter(p));
}
if (is.getSeqId() == owner.getSeqId()) {
log.warn("instance linked to same instance ("
+ is.getSeqId() + ")");
continue; // recursion
}
list.add(new InstanceSpecificationAdapter(
this, is, props, this.level + 1, this.maxLevel));
//log.info(is.dump());
} // for
} // if
else if (valueSpec.getLiteralStringCount() > 0) {
for (LiteralString lit : valueSpec.getLiteralString())
list.add(lit.getValue());
}
else if (valueSpec.getLiteralClobCount() > 0) {
for (LiteralClob lit : valueSpec.getLiteralClob())
list.add(lit.getValue());
}
else if (valueSpec.getLiteralShortCount() > 0) {
for (LiteralShort lit : valueSpec.getLiteralShort())
list.add(lit.getValue());
}
else if (valueSpec.getLiteralIntegerCount() > 0) {
for (LiteralInteger lit : valueSpec.getLiteralInteger())
list.add(lit.getValue());
}
else if (valueSpec.getLiteralLongCount() > 0) {
for (LiteralLong lit : valueSpec.getLiteralLong())
list.add(lit.getValue());
}
else if (valueSpec.getLiteralFloatCount() > 0) {
for (LiteralFloat lit : valueSpec.getLiteralFloat())
list.add(lit.getValue());
}
else if (valueSpec.getLiteralDoubleCount() > 0) {
for (LiteralDouble lit : valueSpec.getLiteralDouble())
list.add(lit.getValue());
}
else if (valueSpec.getLiteralBooleanCount() > 0) {
for (LiteralBoolean lit : valueSpec.getLiteralBoolean())
list.add(lit.getValue());
}
else if (valueSpec.getLiteralDateCount() > 0) {
for (LiteralDate lit : valueSpec.getLiteralDate())
list.add(lit.getValue());
}
Collections.sort(list);
return list;
}
class ValueMap implements Map<String, Object> {
private Map<String, Object> theMap = new HashMap<String, Object>();
@Override
public int size() {
return this.theMap.size();
}
@Override
public boolean isEmpty() {
return this.theMap.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return this.theMap.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return this.theMap.containsValue(value);
}
@Override
public Object get(Object key) {
Object result = null;
PropertyAdapter property = properyMap.get(key);
if (property == null) {
log.warn("property '"
+ key + "' is not defined for entity, "
+ getClassName());
result = EMPTY_LIST;
}
else {
result = this.theMap.get(key);
if (result != null) {
if (property.getIsMany())
if (!(result instanceof Collection || result instanceof Map || result instanceof Object[]))
{
Object value = result;
List<Object> list = new ArrayList<Object>();
list.add(value);
result = list;
}
}
else
result = EMPTY_LIST; // keeps JSTL forEach happy
}
return result;
}
@Override
public Object put(String key, Object value) {
return this.theMap.put(key, value);
}
@Override
public Object remove(Object key) {
return this.theMap.remove(key);
}
@Override
public void clear() {
this.theMap.clear();
}
@Override
public Set<String> keySet() {
return this.theMap.keySet();
}
@Override
public Collection<Object> values() {
return this.theMap.values();
}
@Override
public Set<java.util.Map.Entry<String, Object>> entrySet() {
return this.theMap.entrySet();
}
@Override
public void putAll(Map<? extends String, ? extends Object> m) {
this.theMap.putAll(m);
}
}
}