Filtering data with D2W
Philippe Rabier - twitter.com/prabier
Sophiacom
What is the problem to solve?
Company
EOEntityA
EOEntityB
User
EOEntityC
• Use D2W
• Limit the visibility of the data
• Use conventions to name relationships (for example, any toOne
relationship to Company entity, is called company)
• Minimize the code
• Be magic!
The Requirements
Feedback fromYou ’N Push
First Solution
Working at the editingContext level
modified fetchspec
notification
ec factory
ec
company
objectsWithFetch
Specification()
creates
businessFP
fetchspec
How the qualifier is modified?
	 public void alterFetchSpecification(final NSNotification aNotification)
	 {
	 	 EOEditingContext ec = (EOEditingContext) aNotification.object();
	 	 if (shouldAddRestrictionQualifier)
	 	 {
	 	 	 Company aCompany = (NOClient) ec.userInfoForKey(NBEditingContextFactory.COMPANY_KEY);
	 	 	 final EOFetchSpecification fs = (EOFetchSpecification) aNotification.userInfo().valueForKey(COEditingContext.FETCH_SPEC_KEY);
	 	 	 if (aCompany != null && fs != null)
	 	 	 {
	 	 	 	 EOEntity aEntity = EOUtilities.entityNamed(ec, fs.entityName());
	 	 	 	 EOQualifier fsQualifier = fs.qualifier();
	 	 	 	 if (fsQualifier != null)
	 	 	 	 {
	 	 	 	 	 NSSet<String> keys = fsQualifier.allQualifierKeys();
	 	 	 	 	 for (String aKey : keys)
	 	 	 	 	 {
	 	 	 	 	 	 if (aKey.contains("company"))
	 	 	 	 	 	 {
	 	 	 	 	 	 	 shouldAddRestrictionQualifier = false;
	 	 	 	 	 	 	 break;
	 	 	 	 	 	 }
	 	 	 	 	 }
	 	 	 	 }
	 	 	 	 if (shouldAddRestrictionQualifier)
	 	 	 	 {
	 	 	 	 	 EOQualifier aRestrictionQualifier = clientRestrictionQualifier(aEntity, aClient);
	 	 	 	 	 if (aRestrictionQualifier != null)
	 	 	 	 	 {
	 	 	 	 	 	 if (fsQualifier != null)
	 	 	 	 	 	 	 fsQualifier = new EOAndQualifier(new NSArray<EOQualifier>(new EOQualifier[] {fsQualifier, aRestrictionQualifier}));
	 	 	 	 	 	 else
	 	 	 	 	 	 	 fsQualifier = aRestrictionQualifier;
	 	 	 	 	 	 fs.setQualifier(fsQualifier);
	 	 	 	 	 }
	 	 	 	 }
	 	 	 }
	 	 }
	 }
How the qualifier is modified?
	 public EOQualifier companyRestrictionQualifier(final EOEntity entity, final Company company)
	 {
	 	 EOQualifier aQualifier = null;
	 	 if (entity.name().equals(Company.Keys.ENTITY_NAME))
	 	 	 aQualifier = new EOKeyValueQualifier(Company.Keys.NAME, EOQualifier.QualifierOperatorEqual, company.name());
	 	 else if (entity.relationshipNamed("company") != null)
	 	 	 aQualifier = new EOKeyValueQualifier("company", EOQualifier.QualifierOperatorEqual, company);
	 	 else if (entity.relationshipNamed("entityB") != null)
	 	 	 aQualifier = new EOKeyValueQualifier("entityB.company", EOQualifier.QualifierOperatorEqual, client);
	 	 else if (entity.relationshipNamed("entityC") != null)
	 	 	 ...;
	 	 if (log.isDebugEnabled())
	 	 	 log.debug("method: qualifier: " + aQualifier);
	 	 return aQualifier;
	 }
It works great
but there is a little problem
it’s too low level
An Example of Problem
	 public void validateForSave() throws ValidationException
	 {
	 	 super.validateForSave();
	 	 ERXEOControlUtilities.validateUniquenessOf(this, NOUser.Keys.LOGIN);
	 	 ERXEOControlUtilities.validateUniquenessOf(this, NOUser.Keys.EMAIL);
	 }
	 public void validateForSave() throws ValidationException
	 {
	 	 super.validateForSave();
	 	 editingContext().setUserInfoForKey(Boolean.FALSE, NBEditingContextFactory.NO_RESTRICTION_QUAL_KEY);
	 	 ERXEOControlUtilities.validateUniquenessOf(this, NOUser.Keys.LOGIN);
	 	 ERXEOControlUtilities.validateUniquenessOf(this, NOUser.Keys.EMAIL);
	 	 editingContext().setUserInfoForKey(Boolean.TRUE, NBEditingContextFactory.NO_RESTRICTION_QUAL_KEY);
	 }
Second Solution
• Displaying a list
• Using a query component
• Using ERD2WEditToManyRelationship component
• Using ERD2WEditToOneRelationship component
When should we filter?
• Modify the NavigationController object
• Change the data source
Displaying a list
	 public WOComponent listPageForEntityName(final String entityName)
	 {
	 	 ListPageInterface newListPageInterface = D2W.factory().listPageForEntityNamed(entityName, session());
	 	 EODatabaseDataSource dataSource = new EODatabaseDataSource(ERXEC.newEditingContext(), entityName);
	 	 EOEntity entity = ERXEOAccessUtilities.entityNamed(null, entityName);
	 	 EOQualifier auxQual = NBBusinessLogicPrincipal.getSharedInstance().clientRestrictionQualifier(entity,
	 	 	 	 ((Session)session()).getCompany());
	 	 dataSource.setAuxiliaryQualifier(auxQual);
	 	 newListPageInterface.setDataSource(dataSource);
	 	 return (WOComponent) newListPageInterface;
	 }
• Use a query delegate
• Override the method queryDataSource(ERD2WQueryPage sender)
Using a query component
{
author = 100;
class = "com.webobjects.directtoweb.Rule";
lhs = {
class = "com.webobjects.eocontrol.EOKeyValueQualifier";
key = pageConfiguration;
selectorName = isEqualTo;
value = QueryMyEntity;
};
rhs = {
class = "er.directtoweb.ERDDelayedObjectCreationAssignment";
keyPath = queryDataSourceDelegate;
value = "ca.wowodc.very.util.pascal.delegate.SomeOneElse";
};
}
• Maybe subclass the 2 component is the best solution
• Use restrictingFetchSpecification key. If all fetchspec have the
same name, it’s possible to build a generic rule.
• Need to be modified to add the possibility to set a binding to
the fetchspec
• Maybe a lot of pain to create many fetchspec in the EOModel
EditRelationship components
How the qualifier is modified?
public Object restrictedChoiceList() {
String restrictedChoiceKey=(String)d2wContext().valueForKey("restrictedChoiceKey");
if( restrictedChoiceKey!=null && restrictedChoiceKey.length()>0 )
return valueForKeyPath(restrictedChoiceKey);
String fetchSpecName=(String)d2wContext().valueForKey("restrictingFetchSpecification");
if(fetchSpecName != null) {
EORelationship relationship = ERXUtilities.relationshipWithObjectAndKeyPath(object(),
(String)d2wContext().valueForKey("propertyKey"));
if(relationship != null)
return EOUtilities.objectsWithFetchSpecificationAndBindings(object().editingContext(),
relationship.destinationEntity().name(),fetchSpecName,null);
}
return null;
}
@prabier
Follow me!
Q&A
TBD

Filtering data with D2W

  • 1.
    Filtering data withD2W Philippe Rabier - twitter.com/prabier Sophiacom
  • 2.
    What is theproblem to solve?
  • 3.
  • 4.
    • Use D2W •Limit the visibility of the data • Use conventions to name relationships (for example, any toOne relationship to Company entity, is called company) • Minimize the code • Be magic! The Requirements
  • 5.
  • 6.
    First Solution Working atthe editingContext level
  • 7.
  • 8.
    How the qualifieris modified? public void alterFetchSpecification(final NSNotification aNotification) { EOEditingContext ec = (EOEditingContext) aNotification.object(); if (shouldAddRestrictionQualifier) { Company aCompany = (NOClient) ec.userInfoForKey(NBEditingContextFactory.COMPANY_KEY); final EOFetchSpecification fs = (EOFetchSpecification) aNotification.userInfo().valueForKey(COEditingContext.FETCH_SPEC_KEY); if (aCompany != null && fs != null) { EOEntity aEntity = EOUtilities.entityNamed(ec, fs.entityName()); EOQualifier fsQualifier = fs.qualifier(); if (fsQualifier != null) { NSSet<String> keys = fsQualifier.allQualifierKeys(); for (String aKey : keys) { if (aKey.contains("company")) { shouldAddRestrictionQualifier = false; break; } } } if (shouldAddRestrictionQualifier) { EOQualifier aRestrictionQualifier = clientRestrictionQualifier(aEntity, aClient); if (aRestrictionQualifier != null) { if (fsQualifier != null) fsQualifier = new EOAndQualifier(new NSArray<EOQualifier>(new EOQualifier[] {fsQualifier, aRestrictionQualifier})); else fsQualifier = aRestrictionQualifier; fs.setQualifier(fsQualifier); } } } } }
  • 9.
    How the qualifieris modified? public EOQualifier companyRestrictionQualifier(final EOEntity entity, final Company company) { EOQualifier aQualifier = null; if (entity.name().equals(Company.Keys.ENTITY_NAME)) aQualifier = new EOKeyValueQualifier(Company.Keys.NAME, EOQualifier.QualifierOperatorEqual, company.name()); else if (entity.relationshipNamed("company") != null) aQualifier = new EOKeyValueQualifier("company", EOQualifier.QualifierOperatorEqual, company); else if (entity.relationshipNamed("entityB") != null) aQualifier = new EOKeyValueQualifier("entityB.company", EOQualifier.QualifierOperatorEqual, client); else if (entity.relationshipNamed("entityC") != null) ...; if (log.isDebugEnabled()) log.debug("method: qualifier: " + aQualifier); return aQualifier; }
  • 10.
    It works great butthere is a little problem it’s too low level
  • 11.
    An Example ofProblem public void validateForSave() throws ValidationException { super.validateForSave(); ERXEOControlUtilities.validateUniquenessOf(this, NOUser.Keys.LOGIN); ERXEOControlUtilities.validateUniquenessOf(this, NOUser.Keys.EMAIL); } public void validateForSave() throws ValidationException { super.validateForSave(); editingContext().setUserInfoForKey(Boolean.FALSE, NBEditingContextFactory.NO_RESTRICTION_QUAL_KEY); ERXEOControlUtilities.validateUniquenessOf(this, NOUser.Keys.LOGIN); ERXEOControlUtilities.validateUniquenessOf(this, NOUser.Keys.EMAIL); editingContext().setUserInfoForKey(Boolean.TRUE, NBEditingContextFactory.NO_RESTRICTION_QUAL_KEY); }
  • 12.
  • 13.
    • Displaying alist • Using a query component • Using ERD2WEditToManyRelationship component • Using ERD2WEditToOneRelationship component When should we filter?
  • 14.
    • Modify theNavigationController object • Change the data source Displaying a list public WOComponent listPageForEntityName(final String entityName) { ListPageInterface newListPageInterface = D2W.factory().listPageForEntityNamed(entityName, session()); EODatabaseDataSource dataSource = new EODatabaseDataSource(ERXEC.newEditingContext(), entityName); EOEntity entity = ERXEOAccessUtilities.entityNamed(null, entityName); EOQualifier auxQual = NBBusinessLogicPrincipal.getSharedInstance().clientRestrictionQualifier(entity, ((Session)session()).getCompany()); dataSource.setAuxiliaryQualifier(auxQual); newListPageInterface.setDataSource(dataSource); return (WOComponent) newListPageInterface; }
  • 15.
    • Use aquery delegate • Override the method queryDataSource(ERD2WQueryPage sender) Using a query component { author = 100; class = "com.webobjects.directtoweb.Rule"; lhs = { class = "com.webobjects.eocontrol.EOKeyValueQualifier"; key = pageConfiguration; selectorName = isEqualTo; value = QueryMyEntity; }; rhs = { class = "er.directtoweb.ERDDelayedObjectCreationAssignment"; keyPath = queryDataSourceDelegate; value = "ca.wowodc.very.util.pascal.delegate.SomeOneElse"; }; }
  • 16.
    • Maybe subclassthe 2 component is the best solution • Use restrictingFetchSpecification key. If all fetchspec have the same name, it’s possible to build a generic rule. • Need to be modified to add the possibility to set a binding to the fetchspec • Maybe a lot of pain to create many fetchspec in the EOModel EditRelationship components
  • 17.
    How the qualifieris modified? public Object restrictedChoiceList() { String restrictedChoiceKey=(String)d2wContext().valueForKey("restrictedChoiceKey"); if( restrictedChoiceKey!=null && restrictedChoiceKey.length()>0 ) return valueForKeyPath(restrictedChoiceKey); String fetchSpecName=(String)d2wContext().valueForKey("restrictingFetchSpecification"); if(fetchSpecName != null) { EORelationship relationship = ERXUtilities.relationshipWithObjectAndKeyPath(object(), (String)d2wContext().valueForKey("propertyKey")); if(relationship != null) return EOUtilities.objectsWithFetchSpecificationAndBindings(object().editingContext(), relationship.destinationEntity().name(),fetchSpecName,null); } return null; }
  • 18.
  • 19.