/*
* Copyright (C) NetStruxr, Inc. All rights reserved.
*
* This software is published under the terms of the NetStruxr
* Public Software License version 0.5, a copy of which has been
* included with this distribution in the LICENSE.NPL file. */
package er.directtoweb.components.relationships;
import org.apache.log4j.Logger;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.directtoweb.D2W;
import com.webobjects.directtoweb.EditPageInterface;
import com.webobjects.directtoweb.EditRelationshipPageInterface;
import com.webobjects.eocontrol.EOEditingContext;
import com.webobjects.eocontrol.EOEnterpriseObject;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSDictionary;
import er.directtoweb.components.ERDCustomEditComponent;
import er.extensions.eof.ERXEOControlUtilities;
import er.extensions.foundation.ERXValueUtilities;
/**
* Used to edit a toMany relationship by allowing the user to pick the eos that belong in the relationship.<br />
*
* @binding object
* @binding key
* @binding emptyListMessage
* @binding listPageConfiguration
* @binding list
* @d2wKey createButtonComponentName
* @d2wKey useNestedEditingContext
*/
public class ERDList extends ERDCustomEditComponent {
/**
* 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;
/* logging support */
static final Logger log = Logger.getLogger(ERDList.class);
protected NSArray list;
public ERDList(WOContext context) { super(context); }
@Override
public boolean synchronizesVariablesWithBindings() { return false; }
@Override
public void reset() {
list = null;
super.reset();
}
public NSDictionary settings() {
String pc = d2wContext().dynamicPage();
if(pc != null) {
return new NSDictionary(pc, "parentPageConfiguration");
}
return null;
}
public WOComponent createObjectAction() {
WOComponent nextPage = context().page();
// if creationDelegate binding is provided then just call the delegate with the right params.
// delegate is responsible for making sure the right page is returned after creating hte object.
if (useCreationDelegate()) {
EOEnterpriseObject obj = masterObjectKeyPathForCreationDelegate();
// defaults to object(), if masterObjectKeyPath is not provided
obj = (obj == null) ? object() : obj;
String relationshipName = relationshipName();
// defaults to key(), if the relationshipName binding is not provided
relationshipName = relationshipName == null ? key () : relationshipName;
nextPage = createObjectDelegate().create(obj, (String) valueForBinding ("destinationEntityName"), relationshipName);
}
else {
String editRelationshipConfigurationName = (String)valueForBinding("editRelationshipConfigurationName");
if(editRelationshipConfigurationName != null && editRelationshipConfigurationName.length() > 0) {
nextPage = D2W.factory().pageForConfigurationNamed(editRelationshipConfigurationName, session());
if(nextPage instanceof EditRelationshipPageInterface) {
EditRelationshipPageInterface epi = (EditRelationshipPageInterface)nextPage;
epi.setMasterObjectAndRelationshipKey(object(), key());
epi.setNextPage(context().page());
} else if(nextPage instanceof EditPageInterface) {
Object value = d2wContext().valueForKey("useNestedEditingContext");
boolean createNestedContext = ERXValueUtilities.booleanValue(value);
EOEnterpriseObject object = ERXEOControlUtilities.editableInstanceOfObject(object(), createNestedContext);
EOEditingContext ec = object.editingContext();
ec.lock();
try {
EOEnterpriseObject eo = ERXEOControlUtilities.createAndAddObjectToRelationship(ec, object, key(), (String)valueForBinding("destinationEntityName"), null);
EditPageInterface epi = (EditPageInterface)nextPage;
epi.setObject(eo);
epi.setNextPage(context().page());
} finally {
ec.unlock();
}
}
} else {
ERXEOControlUtilities.createAndAddObjectToRelationship(object().editingContext(), object(), key(), (String)valueForBinding("destinationEntityName"), null);
}
}
return nextPage;
}
// we will get asked quite a lot of times, so caching is in order
public NSArray list() {
if (list == null) {
try {
if (hasBinding("list")) {
list = (NSArray)valueForBinding("list");
} else {
list = (NSArray)objectKeyPathValue();
}
} catch(java.lang.ClassCastException ex) {
// (ak) This happens quite often when you haven't set up all display keys...
// the statement makes this more easy to debug
log.error(ex + " while getting " + key() + " of " + object());
}
if (list == null)
list = NSArray.EmptyArray;
}
return list;
}
// This is fine because we only use the D2WList if we have at least one element in the list.
public boolean erD2WListOmitCenterTag() {
return hasBinding("erD2WListOmitCenterTag") ? booleanValueForBinding("erD2WListOmitCenterTag") : false;
}
@Override
public Object valueForKey(String key) {
Object o = super.valueForKey(key);
if (key.indexOf("emptyListMessage")!=-1) {
log.debug("key = emptyListMessage, value = "+o);
}
return o;
}
@Override
public Object valueForBinding(String key) {
Object o = super.valueForBinding(key);
if (key.indexOf("emptyListMessage")!=-1) {
log.debug("key = emptyListMessage, value = "+o);
}
return o;
}
public String emptyListMessage() {
log.info("asked for emptyListMessage");
return "nix";
}
/**
* Interface that all createObjectDelegate classes should implement
*/
public static interface CreateObjectDelegate {
/**
* method used to create a newInstance of
* <code>destinationEntityNameM</code>.
* <p>
* Note: this delegate is responsible for making sure that the object is created properly and
* the right page is returned.
*
* @param parentObject
* object to which the newly created object should be linked
* @param destinationEntityName
* entity name of the destination in the list that we are
* creating
* @param relationshipNameToAddTo
* relationship name that should be used to link the newly
* created instance to the <code>parentObject</code>
* @return {@link WOComponent} editPage for the destination entity (usually...)
*/
public WOComponent create (Object parentObject, String destinationEntityName, String relationshipNameToAddTo);
}
/**
* @return {@link CreateObjectDelegate} instance from the rule
* file/bindings. this is responsible for creating the object and
* displaying the appropriate page.
* <p>
* Note: if this is binding is present, then the usual method of
* figuring out what to create from
* <code>destinationEntityName</code> and <code>object</code>
* binding doesn't happen.
*/
public CreateObjectDelegate createObjectDelegate () {
Object obj = valueForBinding ("createObjectDelegate");
CreateObjectDelegate delegate = new DefaultCreateObjectDelegate ();
if (obj != null && obj instanceof CreateObjectDelegate) {
delegate = (CreateObjectDelegate) obj;
}
return delegate;
}
/**
* @return true, if <code>createObjectDelegate</code> resolved to a valid
* object. false, otherwise
*/
public Boolean hasCreationDelegate () {
return createObjectDelegate () != null;
}
/**
* @return {@link Boolean} if true, createObjectAction method will use
* delegate (either the one that is provided or the default one.
*/
public Boolean useCreationDelegate () {
return ERXValueUtilities.booleanValue (valueForBinding ("useCreationDelegate"));
}
/**
* @return the keyPath to be used to compute the master object used by
* {@link CreateObjectDelegate}. whatever this keypath resolves to
* will be used to attach the newly created object.
*/
public EOEnterpriseObject masterObjectKeyPathForCreationDelegate () {
return (EOEnterpriseObject) valueForBinding ("masterObjectKeyPathForCreationDelegate");
}
/**
* @return {@link String} relationshipName to connect <code>masterObj</code>
* and the newly created object. this will be used to add the newly
* createdObjects to both sides of relationship.
*/
public String relationshipName () {
return (String) valueForBinding ("relationshipNameForCreationDelegate");
}
/**
* Default creation delegate class. if useCreationDelegate binding is true
* and no valid createObjectDelegate is present, then this class will be
* used.
*
* @author santoash
*/
public class DefaultCreateObjectDelegate implements CreateObjectDelegate {
/**
* {@inheritDoc}
*/
public WOComponent create (Object parentObject, String destinationEntityName, String relationshipNameToAddTo) {
if (! (parentObject instanceof EOEnterpriseObject)) {
throw new IllegalArgumentException ("only instances of EOEnterpriseObject can be handled by DefaultCreateObjectDelegate.");
}
EOEnterpriseObject masterObj = (EOEnterpriseObject) parentObject;
EOEnterpriseObject newEO = ERXEOControlUtilities.createAndAddObjectToRelationship (masterObj.editingContext (), masterObj, relationshipNameToAddTo, destinationEntityName, null);
EditPageInterface epi = D2W.factory ().editPageForEntityNamed (destinationEntityName, session ());
epi.setObject (newEO);
return (WOComponent) epi;
}
}
}