//
// ERXFakeRelationship.java: Class file for WO Component 'ERXFakeRelationship'
// Project simple
//
// Created by ak on Tue Mar 26 2002
//
package er.extensions.components;
import java.util.Enumeration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.eoaccess.EOAttribute;
import com.webobjects.eoaccess.EODatabaseDataSource;
import com.webobjects.eoaccess.EOEntityClassDescription;
import com.webobjects.eoaccess.EOUtilities;
import com.webobjects.eocontrol.EOClassDescription;
import com.webobjects.eocontrol.EOEnterpriseObject;
import com.webobjects.eocontrol.EOSortOrdering;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSKeyValueCoding;
import com.webobjects.foundation.NSMutableArray;
import er.extensions.eof.ERXEOControlUtilities;
/**
* UI and support methods to edit "relations" to objects flattened into a text field (e.g. languages = "-de-en-"). Useful when you don't need referential integrity but only a quick place to store flags and the like.
*
* @binding dataSource
* @binding destinationDisplayKey
* @binding isMandatory
* @binding relationshipKey
* @binding sourceEntityName
* @binding sourceObject
* @binding uiStyle
* @binding isToMany
* @binding destinationEntityName
* @binding size
* @binding maxColumns
*/
public class ERXFakeRelationship extends WOComponent {
/**
* Do I need to update serialVersionUID?
* See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the
* <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a>
*/
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(ERXFakeRelationship.class);
// temps for our children
NSArray theList;
EOEnterpriseObject theCurrentItem;
String theCurrentValue;
boolean isMandatoryRead;
NSArray selections;
// bindings from the parent component
EOEnterpriseObject sourceObject;
String destinationEntityName;
String sourceEntityName;
EODatabaseDataSource dataSource;
boolean isMandatory;
String delimiter;
String relationshipKey;
String destinationDisplayKey;
String uiStyle;
public ERXFakeRelationship(WOContext context) {
super(context);
}
@Override
public boolean synchronizesVariablesWithBindings() {
return false;
}
public String delimiter() {
if(delimiter == null) {
if(hasBinding("delimiter"))
delimiter = (String)valueForBinding("delimiter");
else
delimiter = "\n";
}
return delimiter;
}
public NSArray theList() {
if(theList == null) {
NSMutableArray list = dataSource().fetchObjects().mutableClone();
NSArray orderings = new NSArray(EOSortOrdering.sortOrderingWithKey(destinationDisplayKey(), EOSortOrdering.CompareAscending));
EOSortOrdering.sortArrayUsingKeyOrderArray(list, orderings);
theList = list;
}
return theList;
}
public void setTheList(NSArray aValue) {
theList = aValue;
}
public String theCurrentValue() {
return (String)((NSKeyValueCoding)theCurrentItem()).valueForKey(destinationDisplayKey());
}
public void setTheCurrentValue(String aValue) {
theCurrentValue = aValue;
}
public EOEnterpriseObject theCurrentItem() {
return theCurrentItem;
}
public void setTheCurrentItem(EOEnterpriseObject aValue) {
theCurrentItem = aValue;
}
public static void setFakeRelationshipForKey(EOEnterpriseObject sourceObject, NSArray objects, String relationshipKey, String destinationEntityName, String delimiter) {
if(objects.count() > 0) {
StringBuilder newValue = new StringBuilder();
Enumeration e = objects.objectEnumerator();
while(e.hasMoreElements()) {
EOEnterpriseObject rel = (EOEnterpriseObject)e.nextElement();
newValue.append(ERXEOControlUtilities.primaryKeyStringForObject(rel));
newValue.append(delimiter);
}
sourceObject.takeValueForKey(delimiter + newValue.toString(), relationshipKey);
} else {
sourceObject.takeValueForKey(null, relationshipKey);
}
}
public static NSArray fakeRelationshipForKey(EOEnterpriseObject sourceObject, String relationshipKey, String destinationEntityName, String delimiter) {
String selectionString = (String)sourceObject.valueForKey(relationshipKey);
NSArray selectionsKeys = NSArray.componentsSeparatedByString(selectionString, delimiter);
NSMutableArray selections = new NSMutableArray(selectionsKeys.count());
Enumeration e = selectionsKeys.objectEnumerator();
EOEntityClassDescription cd = (EOEntityClassDescription)EOClassDescription.classDescriptionForEntityName(destinationEntityName);
NSArray pks = cd.entity().primaryKeyAttributes();
if(pks.count() != 1) {
throw new IllegalArgumentException("The destination entity's primary key can't be compound.");
}
EOAttribute pk = (EOAttribute)pks.objectAtIndex(0);
// this could be more bullet proof
boolean hasStringPk = pk.className().equals("java.lang.String");
log.debug(pk.className());
while(e.hasMoreElements()) {
String s = (String)e.nextElement();
Object pkValue = null;
try {
if(s.length() > 0) {
if(!hasStringPk) {
pkValue = Integer.valueOf(s);
} else {
pkValue = s;
}
EOEnterpriseObject eo = EOUtilities.objectWithPrimaryKeyValue(sourceObject.editingContext(), destinationEntityName, pkValue);
selections.addObject(eo);
}
} catch(Exception ex) {
log.warn("{} with pkValue {}", ex.getMessage(), pkValue);
// we do nothing here, when we reconstruct the array on setSelection, we simply ignore this value
}
}
return selections;
}
public NSArray selections() {
if(selections == null) {
selections = ERXFakeRelationship.fakeRelationshipForKey(sourceObject(), relationshipKey(), destinationEntityName(), delimiter());
}
return selections;
}
public void setSelections(NSArray aValue) {
ERXFakeRelationship.setFakeRelationshipForKey(sourceObject(), aValue, relationshipKey(), destinationEntityName(), delimiter());
selections = aValue;
}
public EOEnterpriseObject selection() {
NSArray sel = selections();
if(sel.count() == 1)
return (EOEnterpriseObject)sel.objectAtIndex(0);
return null;
}
public void setSelection(EOEnterpriseObject aValue) {
NSArray sel;
if(aValue == null)
sel = new NSArray();
else
sel = new NSArray(aValue);
setSelections(sel);
}
// bindings we pull
public String sourceEntityName() {
if(sourceEntityName == null) {
sourceEntityName = (String)valueForBinding("sourceEntityName");
if(sourceEntityName == null) {
sourceEntityName = sourceObject().entityName();
}
}
return sourceEntityName;
}
public EOEnterpriseObject sourceObject() {
if(sourceObject == null) {
sourceObject = (EOEnterpriseObject)valueForBinding("sourceObject");
}
return sourceObject;
}
public String relationshipKey() {
if(relationshipKey == null) {
relationshipKey = (String)valueForBinding("relationshipKey");
}
return relationshipKey;
}
public String destinationDisplayKey() {
if(destinationDisplayKey == null) {
destinationDisplayKey = (String)valueForBinding("destinationDisplayKey");
if(destinationDisplayKey == null) {
destinationDisplayKey = "userPresentableDescription";
}
}
return destinationDisplayKey;
}
public String destinationEntityName() {
if(destinationEntityName == null) {
destinationEntityName = (String)valueForBinding("destinationEntityName");
}
return destinationEntityName;
}
public EODatabaseDataSource dataSource() {
if(dataSource == null) {
dataSource = (EODatabaseDataSource)valueForBinding("dataSource");
if(dataSource == null) {
dataSource = new EODatabaseDataSource(sourceObject().editingContext(), destinationEntityName());
}
}
return dataSource;
}
public String uiStyle() {
if(uiStyle == null) {
uiStyle = (String)valueForBinding("uiStyle");
if(uiStyle == null)
uiStyle = "browser";
}
return uiStyle;
}
boolean isMandatory() {
if(!isMandatoryRead) {
EOEntityClassDescription cd = (EOEntityClassDescription)EOClassDescription.classDescriptionForEntityName(sourceEntityName());
isMandatory = !cd.entity().attributeNamed(destinationDisplayKey()).allowsNull();
isMandatoryRead = true;
}
return isMandatory;
}
public void _invalidateCaches() {
theList = null;
theCurrentItem = null;
theCurrentValue = null;
isMandatoryRead = false;
selections = null;
// bindings from the parent component
sourceObject = null;
destinationEntityName = null;
sourceEntityName = null;
dataSource = null;
isMandatory = false;
delimiter = null;
relationshipKey = null;
destinationDisplayKey = null;
uiStyle = null;
}
@Override
public void reset() {
_invalidateCaches();
}
public boolean isBrowser() {
return uiStyle().equals("browser");
}
}