/*
* WOToOneRelationship.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 WOToOneRelationship 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 Object _privateSelection;
public static final String _noneString = "- none -";
public WOToOneRelationship(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;
}
protected boolean isMandatory()
{
return _isMandatory;
}
public void setIsMandatory(Object aValue) {
try {
_isMandatory = _WOJExtensionsUtil.booleanValue(aValue);
} catch (Throwable e) {
String error = "WOToOneRelationship (setIsMandatory) - unable to set isMandatory value "+e.getMessage();
NSLog.err.appendln(error);
}
}
//////////////////////////////////////////////////
// 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 Object _privateSelection()
{
return _privateSelection;
}
public void set_privateSelection(Object aValue) {
_privateSelection = aValue;
}
protected 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_privateSelection(null);
}
@Override
public void reset() {
_invalidateCaches();
}
///////////////////////
// Internal Accessors
///////////////////////
protected Object _localSourceObject()
{
if (null==sourceObject()) {
setSourceObject(valueForBinding("sourceObject"));
if (null==sourceObject()) {
throw new IllegalStateException("<"+getClass().getName()+" sourceObject binding required. sourceObject value is nil or missing>");
}
}
return sourceObject();
}
protected boolean _localIsMandatory() {
if (!isMandatory()) {
Object aValue = valueForBinding("isMandatory");
setIsMandatory(aValue);
}
return isMandatory();
}
protected String _localSourceEntityName() {
if (null==sourceEntityName()) {
setSourceEntityName((String) _WOJExtensionsUtil.valueForBindingOrNull("sourceEntityName",this));
if (null==sourceEntityName()) {
throw new IllegalStateException("<"+getClass().getName()+" sourceEntityName binding required. sourceEntityName value is nil or missing>");
}
}
return sourceEntityName();
}
protected String _localRelationshipKey()
{
if (null==relationshipKey()) {
setRelationshipKey((String) _WOJExtensionsUtil.valueForBindingOrNull("relationshipKey",this));
if (null==relationshipKey()) {
throw new IllegalStateException("<"+getClass().getName()+" relationshipKey binding required. relationshipKey value is nil or missing>");
}
}
return relationshipKey();
}
protected String _localDestinationDisplayKey() {
String destinationDisplayKey = destinationDisplayKey();
if (null==destinationDisplayKey) {
setDestinationDisplayKey( (String) _WOJExtensionsUtil.valueForBindingOrNull("destinationDisplayKey",this));
if (null==destinationDisplayKey()) {
setDestinationDisplayKey("userPresentableDescription");
}
return destinationDisplayKey();
} else
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 (null==dataSource()) {
setDataSource((EODatabaseDataSource) _WOJExtensionsUtil.valueForBindingOrNull("dataSource",this));
if (null==dataSource()) {
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 (null== uiStyle()) {
setUiStyle((String) _WOJExtensionsUtil.valueForBindingOrNull("uiStyle",this));
// if still no value let's determine one
if (null==uiStyle()) {
int aSize = theList().count();
if (aSize < 5) {
setUiStyle("radio");
}
if ((aSize >= 5) && (aSize < 20)) {
setUiStyle("popup");
}
if (aSize >= 20) {
setUiStyle("browser");
}
}
}
return uiStyle();
}
/*
* -updateSourceObject does the real work here updating
* the relationship (or setting the keys for a query).
*/
public void updateSourceObject(Object anEO) {
String masterKey = _localRelationshipKey();
Object aSourceObject = _localSourceObject();
boolean isDictionary = (aSourceObject instanceof NSMutableDictionary);
NSMutableDictionary _dictionary = (isDictionary) ? (NSMutableDictionary)aSourceObject : null;
EOEnterpriseObject _eo = !(isDictionary) ? (EOEnterpriseObject)aSourceObject : null;
if (anEO != null) {
if (isDictionary) {
_dictionary.setObjectForKey(anEO, masterKey);
}
else if (_eo.valueForKey(masterKey) != anEO) {
_eo.addObjectToBothSidesOfRelationshipWithKey((EOEnterpriseObject) anEO, masterKey);
}
}
else { // remove
if (isDictionary) {
_dictionary.removeObjectForKey(masterKey);
}
else if (_eo.valueForKey(masterKey) != null) {
_eo.removeObjectFromBothSidesOfRelationshipWithKey((EOEnterpriseObject) _eo.valueForKey(masterKey), masterKey);
}
}
}
////////////////////////////////////
// Accessed through HTML and WOD
////////////////////////////////////
/*
* -selection and -setSelection: are called by WOF when
* syncing up the contents of this component. These are
* accessed only through the declarations.
*/
public void setSelection(Object anEO) {
Object aValue = null;
// deal with array when ui is browser
if ((anEO!=null) && (anEO instanceof NSArray)) {
NSArray anEOArray = (NSArray)anEO;
if (anEOArray.count() == 0) {
anEO = null;
} else {
anEO = anEOArray.objectAtIndex(0);
}
}
if (anEO==_noneString) {
aValue = null;
} else {
aValue = anEO;
}
set_privateSelection(aValue);
// this set method needs to trigger the setSourceObject:
// it's the only way our value will get back into the parent
updateSourceObject(aValue);
}
public Object selection() {
if (_privateSelection()==null) {
set_privateSelection( NSKeyValueCoding.Utility.valueForKey(_localSourceObject(), _localRelationshipKey()));
}
// deal with isMandatory
if ((_privateSelection()==null) && !_localIsMandatory()) {
setSelection(_noneString);
}
return _privateSelection();
}
public NSArray theList() {
NSMutableArray aSortedArray;
NSArray anUnsortedArray;
if (_privateList()==null) {
EODataSource aDataSource = _localDataSource();
anUnsortedArray = aDataSource.fetchObjects();
// 81398 sort contents
aSortedArray = new NSMutableArray(anUnsortedArray);
try {
_WOJExtensionsUtil._sortEOsUsingSingleKey(aSortedArray, _localDestinationDisplayKey());
} catch (NSComparator.ComparisonException e) {
throw NSForwardException._runtimeExceptionForThrowable(e);
}
if (!_localIsMandatory()) {
aSortedArray.insertObjectAtIndex(_noneString, 0);
}
set_privateList(aSortedArray);
}
return _privateList();
}
public void setTheList(NSArray aValue) {
}
public Object theCurrentValue() {
// handle the case where it's the - none - string
if (theCurrentItem==_noneString) {
return theCurrentItem;
}
return NSKeyValueCoding.Utility.valueForKey(theCurrentItem , _localDestinationDisplayKey());
}
public boolean isRadio() {
if (_localUiStyle().equals("radio")) {
return true;
}
return false;
}
public boolean isPopup() {
if (_localUiStyle().equals("popup")) {
return true;
}
return false;
}
public boolean isBrowser() {
if (_localUiStyle().equals("browser")) {
return true;
}
return false;
}
}