/*
* WOToManyRelationship.java
* (c) Copyright 2001 Apple Computer, Inc. All rights reserved.
* This a modified version.
* Original license: http://www.opensource.apple.com/apsl/
*/
package com.webobjects.woextensions;
import java.util.Enumeration;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.eoaccess.EODatabaseDataSource;
import com.webobjects.eoaccess.EOEntity;
import com.webobjects.eoaccess.EOModelGroup;
import com.webobjects.eocontrol.EODataSource;
import com.webobjects.eocontrol.EOEditingContext;
import com.webobjects.eocontrol.EOEnterpriseObject;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSComparator;
import com.webobjects.foundation.NSForwardException;
import com.webobjects.foundation.NSKeyValueCoding;
import com.webobjects.foundation.NSLog;
import com.webobjects.foundation.NSMutableArray;
import com.webobjects.foundation.NSMutableDictionary;
public class WOToManyRelationship 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;
// ** passed-in (required)
protected String _sourceEntityName;
protected String _relationshipKey;
protected Object _sourceObject;
// ** passed-in (optional)
protected String _destinationDisplayKey;
protected EODatabaseDataSource _dataSource;
protected String _uiStyle;
protected boolean _isMandatory;
// ** internal
protected Object theCurrentItem;
protected NSArray _privateList;
protected NSArray _privateSelections;
/////////////////////////////////////////////////////////////////
// The following may be set/passed-in by user of this component
/////////////////////////////////////////////////////////////////
public WOToManyRelationship(WOContext aContext) {
super(aContext);
}
@Override
public boolean isStateless() {
return true;
}
public String sourceEntityName() {
return _sourceEntityName;
}
public void setSourceEntityName(String aValue) {
_sourceEntityName = aValue;
}
public String relationshipKey() {
return _relationshipKey;
}
public void setRelationshipKey(String aValue) {
_relationshipKey = aValue;
}
public Object sourceObject() {
return _sourceObject;
}
public void setSourceObject(Object aValue) {
_sourceObject = aValue;
}
public String destinationDisplayKey() {
return _destinationDisplayKey;
}
public void setDestinationDisplayKey(String aValue) {
_destinationDisplayKey = aValue;
}
public EODatabaseDataSource dataSource() {
return _dataSource;
}
public void setDataSource(EODatabaseDataSource aValue) {
_dataSource = aValue;
}
public String uiStyle() {
return _uiStyle;
}
public void setUiStyle(String aValue) {
_uiStyle = aValue;
}
boolean isMandatory() {
return _isMandatory;
}
public void setIsMandatory(Object aValue) {
try {
_isMandatory = _WOJExtensionsUtil.booleanValue(aValue);
}
catch (Throwable e) {
NSLog.err.appendln("WOToOneRelationship (setIsMandatory) - unable to set isMandatory value " + e.getMessage());
NSLog.err.appendln(e);
}
}
//////////////////////////////////////////////////
// The following are used internally/privately
//////////////////////////////////////////////////
public Object theCurrentItem() {
return theCurrentItem;
}
public void setTheCurrentItem(Object aValue) {
theCurrentItem = aValue;
}
protected NSArray _privateList() {
return _privateList;
}
public void set_privateList(NSArray aValue) {
_privateList = aValue;
}
public NSArray _privateSelections() {
return _privateSelections;
}
public void set_privateSelections(NSArray aValue) {
_privateSelections = aValue;
}
public void _invalidateCaches() {
// In order for this to behave like an element, all instance
// variables need to be flushed when this component sleeps
// so that it will pull via association.
setSourceEntityName(null);
setRelationshipKey(null);
setSourceObject(null);
setDataSource(null);
setDestinationDisplayKey(null);
setUiStyle(null);
setIsMandatory(null);
setTheCurrentItem(null);
set_privateList(null);
set_privateSelections(null);
}
@Override
public void reset() {
_invalidateCaches();
}
///////////////////////
// Internal Accessors
///////////////////////
protected String _localSourceEntityName() {
if (sourceEntityName() == null) {
setSourceEntityName((String) _WOJExtensionsUtil.valueForBindingOrNull("sourceEntityName", this));
if (sourceEntityName() == null) {
throw new IllegalStateException("<" + getClass().getName() + " sourceEntityName binding required. sourceEntityName value is null or missing>");
}
}
return sourceEntityName();
}
protected String _localRelationshipKey() {
if (relationshipKey() == null) {
setRelationshipKey((String) _WOJExtensionsUtil.valueForBindingOrNull("relationshipKey",this));
if (relationshipKey() == null) {
throw new IllegalStateException("<" + getClass().getName() + " relationshipKey binding required. relationshipKey value is null or missing>");
}
}
return relationshipKey();
}
protected Object _localSourceObject() {
if (sourceObject() == null) {
setSourceObject(valueForBinding("sourceObject"));
if (sourceObject() == null) {
throw new IllegalStateException("<" + getClass().getName() + " sourceObject binding required. sourceObject value is null or missing>");
}
}
return sourceObject();
}
protected String _localDestinationDisplayKey() {
String destinationDisplayKey = destinationDisplayKey();
if (destinationDisplayKey == null) {
setDestinationDisplayKey((String) _WOJExtensionsUtil.valueForBindingOrNull("destinationDisplayKey", this));
if (destinationDisplayKey() == null) {
setDestinationDisplayKey("userPresentableDescription");
}
return destinationDisplayKey();
}
return destinationDisplayKey;
}
public EOEntity entityWithEntityAndKeyPath(EOEntity entity, String keyPath) {
NSArray keys = NSArray.componentsSeparatedByString(keyPath, ".");
Enumeration keysEnumerator = keys.objectEnumerator();
String key = null;
EOEntity result = entity;
while (keysEnumerator.hasMoreElements()) {
key = (String) keysEnumerator.nextElement();
result = result.relationshipNamed(key).destinationEntity();
}
return result;
}
protected EODataSource _localDataSource() {
if (dataSource() == null) {
setDataSource((EODatabaseDataSource) _WOJExtensionsUtil.valueForBindingOrNull("dataSource", this));
if (dataSource() == null) {
String anEntityName = _localSourceEntityName();
EOModelGroup aModelGroup = EOModelGroup.defaultGroup();
EOEntity anEntity = aModelGroup.entityNamed(anEntityName);
if (anEntity == null) {
throw new IllegalStateException("<" + getClass().getName() + " could not find entity named " + anEntityName + ">");
}
EOEntity destinationEntity = entityWithEntityAndKeyPath(anEntity, _localRelationshipKey());
Object _source = _localSourceObject();
EOEditingContext anEditingContext = null;
if (_source instanceof EOEnterpriseObject) {
anEditingContext = ((EOEnterpriseObject) _source).editingContext();
}
if (anEditingContext == null) {
anEditingContext = session().defaultEditingContext();
}
EODatabaseDataSource aDatabaseDataSource = new EODatabaseDataSource(anEditingContext, destinationEntity.name());
setDataSource(aDatabaseDataSource);
}
}
return dataSource();
}
protected Object _localUiStyle() {
if (uiStyle() == null) {
setUiStyle((String) _WOJExtensionsUtil.valueForBindingOrNull("uiStyle", this));
// if still no value let's determine one
if (uiStyle() == null) {
setUiStyle((theList().count() <= 5) ? "checkbox" : "browser");
}
}
return uiStyle();
}
protected boolean _localIsMandatory() {
if (!isMandatory()) {
Object aValue = valueForBinding("isMandatory");
setIsMandatory(aValue);
}
return isMandatory();
}
/*
* -updateSourceObject does the real work here updating
* the relationship (or setting the keys for a query).
*/
public void updateSourceObject(NSArray newValues) {
// add new values to relationship, remove old values
Object aSourceObject = _localSourceObject();
boolean isDictionary = (aSourceObject instanceof NSMutableDictionary);
NSMutableDictionary _dictionary = (isDictionary) ? (NSMutableDictionary) aSourceObject : null;
EOEnterpriseObject _eo = (!isDictionary) ? (EOEnterpriseObject) aSourceObject : null;
String masterKey = _localRelationshipKey();
NSMutableArray currentValues = (NSMutableArray) NSKeyValueCoding.Utility.valueForKey(aSourceObject, masterKey);
int count = currentValues.count();
EOEnterpriseObject o;
for (int i = count - 1; i >= 0; i--) {
o = (EOEnterpriseObject) currentValues.objectAtIndex(i);
if (newValues == null || newValues.indexOfIdenticalObject(o) == NSArray.NotFound) { // not found
if (isDictionary) {
currentValues.removeObject(o);
}
else {
_eo.removeObjectFromBothSidesOfRelationshipWithKey(o, masterKey);
}
}
}
count = (newValues == null) ? 0 : newValues.count();
for (int i = count - 1; i >= 0; i--) {
o = (EOEnterpriseObject) newValues.objectAtIndex(i);
if (currentValues.indexOfIdenticalObject(o) == NSArray.NotFound) { // not found
if (isDictionary) {
currentValues.addObject(o);
}
else {
_eo.addObjectToBothSidesOfRelationshipWithKey(o, masterKey);
}
}
}
}
////////////////////////////////////
// Accessed through HTML and WOD
////////////////////////////////////
/*
* -selections and -setSelections: are called by WOF when
* syncing up the contents of this component. These are
* accessed only through the declarations.
*/
public void setSelections(NSArray aValue) {
NSArray aTempValue = aValue;
// set selections to null if it's an empty array
if (aValue == null || aValue.count() == 0) {
if (isMandatory() && theList().count() > 0) {
Object anObject = theList().objectAtIndex(0);
aTempValue = new NSArray<>(anObject);
}
else {
aTempValue = null;
}
}
// deal with isMandatory
set_privateSelections(aTempValue);
updateSourceObject(aTempValue);
}
public NSArray selections() {
if (_privateSelections() == null) {
set_privateSelections((NSArray) NSKeyValueCoding.Utility.valueForKey(_localSourceObject(), _localRelationshipKey()));
// deal with isMandatory
if (_privateSelections() == null && _localIsMandatory()) {
if (theList().count() > 0) {
Object anObject = theList().objectAtIndex(0);
set_privateSelections(new NSArray<>(anObject));
}
}
}
return _privateSelections();
}
public NSArray theList() {
NSMutableArray<EOEnterpriseObject> aSortedArray;
// ** This is cached because WOBrowser and WOCheckBoxList
// ** might ask for list many times.
if (_privateList() == null) {
// 81398 sort contents
aSortedArray = _localDataSource().fetchObjects().mutableClone();
try {
_WOJExtensionsUtil._sortEOsUsingSingleKey(aSortedArray, _localDestinationDisplayKey());
}
catch (NSComparator.ComparisonException e) {
throw NSForwardException._runtimeExceptionForThrowable(e);
}
set_privateList(aSortedArray);
}
return _privateList();
}
public Object theCurrentValue() {
return NSKeyValueCoding.Utility.valueForKey(theCurrentItem, _localDestinationDisplayKey());
}
public boolean isCheckBox() {
return _localUiStyle().equals("checkbox");
}
}