Package er.directtoweb.pages

Source Code of er.directtoweb.pages.ERD2WQueryPage

/*
* 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.pages;

import java.util.Enumeration;

import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WODisplayGroup;
import com.webobjects.appserver.WORequest;
import com.webobjects.appserver.WOResponse;
import com.webobjects.directtoweb.D2W;
import com.webobjects.directtoweb.D2WContext;
import com.webobjects.directtoweb.ListPageInterface;
import com.webobjects.directtoweb.NextPageDelegate;
import com.webobjects.eoaccess.EODatabaseDataSource;
import com.webobjects.eoaccess.EOEntity;
import com.webobjects.eocontrol.EOAndQualifier;
import com.webobjects.eocontrol.EODataSource;
import com.webobjects.eocontrol.EOFetchSpecification;
import com.webobjects.eocontrol.EOQualifier;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSKeyValueCoding;
import com.webobjects.foundation.NSMutableArray;
import com.webobjects.foundation.NSMutableDictionary;
import com.webobjects.foundation.NSValidation;

import er.directtoweb.delegates.ERDQueryDataSourceDelegateInterface;
import er.directtoweb.delegates.ERDQueryValidationDelegate;
import er.directtoweb.interfaces.ERDQueryPageInterface;
import er.extensions.appserver.ERXDisplayGroup;
import er.extensions.appserver.ERXResponseRewriter;
import er.extensions.foundation.ERXValueUtilities;
import er.extensions.localization.ERXLocalizer;

/**
* Superclass for all query pages.<br />
* In addition to the rest of the goodies of ERD2WPage, it lets you save and
* restore the initial query bindings by supplying a NS(Mutable)Dictionary which
* contains the keys "queryMin", "queryMax" etc from the respective fields of
* the WODisplayGroup.
* @d2wKey fetchSpecificationName
* @d2wKey enableQueryForNullValues
* @d2wKey isDeep
* @d2wKey usesDistinct
* @d2wKey refrehRefetchedObjects
* @d2wKey fetchLimit
* @d2wKey prefetchingRelationshipKeyPaths
* @d2wKey showListInSamePage
* @d2wKey listConfigurationName
* @d2wKey queryDataSourceDelegate
* @d2wKey queryValidationDelegate
* @d2wKey enableQueryForNullValues
* @d2wKey canQueryPropertyForNullValues
*/
public class ERD2WQueryPage extends ERD2WPage implements ERDQueryPageInterface {
  /**
   * 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;

    protected WODisplayGroup displayGroup;

    protected boolean didLoadQueryBindings;
    protected NSDictionary queryBindings;

    protected EOFetchSpecification fetchSpecification;
   
    protected ERDQueryDataSourceDelegateInterface queryDataSourceDelegate;
    protected ERDQueryValidationDelegate queryValidationDelegate;

    protected NSArray _nullablePropertyKeys;
    protected NSMutableDictionary keysToQueryForNull = new NSMutableDictionary();

    public ERD2WQueryPage(WOContext context) {
        super(context);
        createDisplayGroup();
    }

    protected void createDisplayGroup() {
        displayGroup = new ERXDisplayGroup();
    }

    protected void pullQueryBindingsForName(String name) {
        NSDictionary queryBindings = queryBindings();
        if (queryBindings != null) {
            NSDictionary source = (NSDictionary) queryBindings.objectForKey(name);
            if (source != null) {
                NSMutableDictionary destination = (NSMutableDictionary) NSKeyValueCoding.Utility.valueForKey(displayGroup, name);
                destination.addEntriesFromDictionary(source);
            }
        }
    }
   
  /**
   * <span class="ja">
   * ディスプレイ・グループの全クエリ設定を取り除きます。
   *
   * @return カレント・ページ
   * </span>
   */
    public WOComponent clearAction() {
        displayGroup().queryBindings().removeAllObjects();
        displayGroup().queryMin().removeAllObjects();
        displayGroup().queryMax().removeAllObjects();
        displayGroup().queryOperator().removeAllObjects();
        displayGroup().queryMatch().removeAllObjects();
       if (displayGroup() instanceof ERXDisplayGroup) {
            ERXDisplayGroup dg = (ERXDisplayGroup) displayGroup();
            dg.clearExtraQualifiers();
        }
        return context().page();
    }
   
    public EOFetchSpecification fetchSpecification() {
        if(fetchSpecification == null) {
            String name = fetchSpecificationName();
            if(name != null) {
                fetchSpecification = entity().fetchSpecificationNamed(name);
            }
        }
        return fetchSpecification;
    }
   
    public void setFetchSpecification(EOFetchSpecification value) {
        fetchSpecification=value;
        if(fetchSpecification != null) {
            d2wContext().takeValueForKey(value.qualifier().bindingKeys(), "displayPropertyKeys");
        }
    }

    public void setFetchSpecificationName(String value) {
        d2wContext().takeValueForKey(value,"fetchSpecificationName");
        //_fetchSpecificationName=name;
        EOEntity e=entity();
        setFetchSpecification(e.fetchSpecificationNamed(value));
    }

    public String fetchSpecificationName() {
        return (String)d2wContext().valueForKey("fetchSpecificationName");
    }

    public EOFetchSpecification queryFetchSpecification() {
        NSDictionary valuesFromBinding=displayGroup.queryMatch();
        if(fetchSpecification() != null) {
          return fetchSpecification().fetchSpecificationWithQualifierBindings(valuesFromBinding);
        }
        return null;
    }

    protected void pushQueryBindingsForName(String name) {
        NSDictionary queryBindings = queryBindings();
        if (queryBindings != null && (queryBindings instanceof NSMutableDictionary)) {
            NSMutableDictionary mutableQueryBindings = (NSMutableDictionary) queryBindings;
            NSDictionary source = (NSDictionary) NSKeyValueCoding.Utility.valueForKey(displayGroup, name);
            mutableQueryBindings.setObjectForKey(source.mutableClone(), name);
        }
    }

    @Override
    public void takeValuesFromRequest(WORequest request, WOContext context) {
        super.takeValuesFromRequest(request, context);
        substituteValueForNullableQueryKeys();
        saveQueryBindings();
    }

    @Override
    public void appendToResponse(WOResponse response, WOContext context) {
        loadQueryBindings();
        super.appendToResponse(response, context);
       
        if (ERXValueUtilities.booleanValueWithDefault(d2wContext().valueForKey("enableQueryForNullValues"), false)) {
            ERXResponseRewriter.addScriptResourceInHead(response, context, "ERDirectToWeb", "ERD2WQueryPage.js");
        }
    }

    protected void saveQueryBindings() {
        NSDictionary queryBindings = queryBindings();
        if (queryBindings != null) {
            pushQueryBindingsForName("queryMin");
            pushQueryBindingsForName("queryMax");
            pushQueryBindingsForName("queryMatch");
            pushQueryBindingsForName("queryOperator");
            pushQueryBindingsForName("queryBindings");
        }
    }

    protected void loadQueryBindings() {
        if (!didLoadQueryBindings) {
            NSDictionary queryBindings = queryBindings();
            if (queryBindings != null) {
                pullQueryBindingsForName("queryMin");
                pullQueryBindingsForName("queryMax");
                pullQueryBindingsForName("queryMatch");
                pullQueryBindingsForName("queryOperator");
                pullQueryBindingsForName("queryBindings");
                didLoadQueryBindings = true;
            }
        }
    }

    @Override
    public void awake() {
        super.awake();
    }

    public boolean isDeep() {
        return ERXValueUtilities.booleanValue(d2wContext().valueForKey("isDeep"));
    }

    public NSDictionary queryBindings() {
        if (queryBindings == null) {
            queryBindings = (NSDictionary) valueForBinding("queryBindings");
        }
        return queryBindings;
    }

    public void setQueryBindings(NSDictionary dictionary) {
        queryBindings = dictionary;
    }

    public boolean usesDistinct() {
        return ERXValueUtilities.booleanValue(d2wContext().valueForKey("usesDistinct"));
    }

    public boolean refreshRefetchedObjects() {
        return ERXValueUtilities.booleanValue(d2wContext().valueForKey("refreshRefetchedObjects"));
    }

    public int fetchLimit() {
        return ERXValueUtilities.intValueWithDefault(d2wContext().valueForKey("fetchLimit"), 0);
    }

    public NSArray prefetchingRelationshipKeyPaths(){
        return ERXValueUtilities.arrayValue(d2wContext().valueForKey("prefetchingRelationshipKeyPaths"));
    }

    // add the ability to AND the existing qualifier from the DG
    public EOQualifier qualifier() {
        EOQualifier q = displayGroup.qualifier();
        EOQualifier q2 = displayGroup.qualifierFromQueryValues();
        return q == null ? q2 : (q2 == null ? q : new EOAndQualifier(new NSArray(new Object[] { q, q2 })));
    }

    protected Boolean showResults = null;

    public boolean showResults() {
        return Boolean.TRUE.equals(showResults);
    }

    public void setShowResults(boolean value) {
        showResults = value;
    }

    public WOComponent queryAction() {
        WOComponent nextPage = null;

        // If we have a validation delegate, validate the query values before actually performing the query.
        ERDQueryValidationDelegate queryValidationDelegate = queryValidationDelegate();
        if (queryValidationDelegate != null) {
            clearValidationFailed();
            setErrorMessage(null);
            try {
                queryValidationDelegate.validateQuery(this);
            } catch (NSValidation.ValidationException ex) {
          setErrorMessage(ERXLocalizer.currentLocalizer().localizedTemplateStringForKeyWithObject("CouldNotQuery", ex));
          validationFailedWithException(ex, null, "queryExceptionKey");
        }
            if (hasErrors()) {
                return context().page();
            }
        }

        if (ERXValueUtilities.booleanValue(d2wContext().valueForKey("showListInSamePage"))) {
            setShowResults(true);
        } else {
          nextPage = nextPageFromDelegate();
            if (nextPage == null) {
                String listConfigurationName = (String) d2wContext().valueForKey("listConfigurationName");
                ListPageInterface listpageinterface;
                if (listConfigurationName != null) {
                    listpageinterface = (ListPageInterface) D2W.factory().pageForConfigurationNamed(listConfigurationName, session());
                } else {
                    listpageinterface = D2W.factory().listPageForEntityNamed(entity().name(), session());
                }
                listpageinterface.setDataSource(queryDataSource());
                listpageinterface.setNextPage(context().page());
                nextPage = (WOComponent) listpageinterface;
            }
        }
        return nextPage;
    }

    // returning a null query data source if cancel was clicked
    private boolean _wasCancelled;
   
    public WOComponent cancelAction() {
        WOComponent result = null;
        try {
            _wasCancelled = true;
            result = nextPageFromDelegate();
            if (result == null) {
                // CHECKME AK: or return null?? no way of knowing...
                result = nextPage();
            }
        } finally {
            _wasCancelled = false;
        }
        return result;
    }

    //CHECKME AK: this variable doesn't seem like such a good idea, in particular as there is no setter??
    public WOComponent returnPage;

    public WOComponent returnAction() {
        return returnPage != null ? returnPage : nextPage();
    }

    @Override
    public boolean showCancel() {
        return nextPage() != null;
    }

    /**
     * Assembles the data source for the search results page, configured for the current query.  If a
     * {@link #queryDataSourceDelegate()} is defined, the delegate's implementation is invoked. Otherwise,
     * the {@link #defaultQueryDataSource()} is returned.
     * @return the prepared data source
     */
    public EODataSource queryDataSource() {
        if (_wasCancelled) {
            return null;
        }
       
        ERDQueryDataSourceDelegateInterface delegate = queryDataSourceDelegate();
        if (delegate != null) {
            return delegate.queryDataSource(this);
        } else {
            return defaultQueryDataSource();
        }
    }

    /**
     * Sets the query data source.
     * @param datasource to be used as the query data source
     */
    public void setQueryDataSource(EODataSource datasource) {
        setDataSource(datasource);
    }
   
    /**
     * Default implementation of which assembles the data source for the search results page, configured
     * for the current query.
     * @return the prepared data source
     */
    public EODataSource defaultQueryDataSource() {
        EODataSource ds = dataSource();
        if (ds == null || !(ds instanceof EODatabaseDataSource)) {
            ds = new EODatabaseDataSource(session().defaultEditingContext(), entity().name());
            setDataSource(ds);
        }
        EOFetchSpecification fs = queryFetchSpecification();
        if (fs == null) {
            fs = ((EODatabaseDataSource) ds).fetchSpecification();
            fs.setQualifier(qualifier());
            fs.setIsDeep(isDeep());
            fs.setUsesDistinct(usesDistinct());
            fs.setRefreshesRefetchedObjects(refreshRefetchedObjects());
        } else {
            ((EODatabaseDataSource) ds).setFetchSpecification(fs);
        }
        int limit = fetchLimit();
        if (limit != 0)
            fs.setFetchLimit(limit);
        NSArray prefetchingRelationshipKeyPaths = prefetchingRelationshipKeyPaths();
        if (prefetchingRelationshipKeyPaths != null && prefetchingRelationshipKeyPaths().count() > 0) {
            fs.setPrefetchingRelationshipKeyPaths(prefetchingRelationshipKeyPaths);
        }
        return ds;
    }
   
    /**
     * Gets the query data source delegate.
     * @return the query data source delegate
     */
    public ERDQueryDataSourceDelegateInterface queryDataSourceDelegate() {
        if (queryDataSourceDelegate == null) {
            queryDataSourceDelegate = (ERDQueryDataSourceDelegateInterface)d2wContext().valueForKey("queryDataSourceDelegate");
        }
        return queryDataSourceDelegate;
    }
   
    /**
     * Sets the query data source delegate.
     * @param delegate to use as the query data source delegate
     */
    public void setQueryDataSourceDelegate(ERDQueryDataSourceDelegateInterface delegate) {
        queryDataSourceDelegate = delegate;
    }

    /**
     * <span class="en">
     * Gets the query validation delegate.
     *
     * @return the query validation delegate
     * </span>
     *
     * <span class="ja">
     * クエリ検証デリゲートを戻します。
     *
     * @return クエリ検証デリゲート
     * </span>
     */
    public ERDQueryValidationDelegate queryValidationDelegate() {
        if (null == queryValidationDelegate) {
            queryValidationDelegate = (ERDQueryValidationDelegate)d2wContext().valueForKey("queryValidationDelegate");
        }
        return queryValidationDelegate;
    }

    /**
     * <span class="en">
     * Sets the query validation delegate.
     *
     * @param delegate to use as the query validation delegate
     * </span>
     *
     * <span class="ja">
     * クエリ検証デリゲートをセットします。
     *
     * @param delegate - クエリ検証デリゲート (@see ERDQueryValidationDelegate)
     * </span>
     */
    public void setQueryValidationDelegate(ERDQueryValidationDelegate delegate) {
        queryValidationDelegate = delegate;
    }

    /**
     * Gets the display group.
     * @return the display group
     */
    public WODisplayGroup displayGroup() {
        return displayGroup;
    }
   
    public String headerTemplate() {
      return fetchLimit() != 0 ? "ERD2WQueryPage.restrictedMessage" : "ERD2WQueryPage.plainMessage";
    }

    /**
     * Set a search value for the display group query match. When the value is null is gets removed from the
     * dict, when the operator is null and the value isn't, "=" is chosen.
     * When operator is "&lt;" is uses <code>queryMatch()</code>, if it is "&gt;" is uses <code>queryMin()</code>,
     * so you can use it with the various date range components.
     * @param value to assign to the queryMatch dictionary for the given key
     * @param operator used for comparing the value
     * @param key to use
     */
    public void setQueryMatchForKey(Object value, String operator, String key) {
        NSMutableDictionary queryDict = displayGroup().queryMatch();
        NSMutableDictionary operatorDict = displayGroup().queryOperator();
        if(">".equals(operator)) {
            queryDict = displayGroup().queryMin();
            operatorDict = new NSMutableDictionary();
        } else if ("<".equals(operator)) {
            queryDict = displayGroup().queryMax();
            operatorDict = new NSMutableDictionary();
        }
        if(value != null) {
            queryDict.setObjectForKey(value, key);
            if(operator != null) {
                operatorDict.setObjectForKey(operator, key);
            } else {
                operatorDict.removeObjectForKey(key);
            }
        } else {
            queryDict.removeObjectForKey(key);
            operatorDict.removeObjectForKey(key);
        }
    }

    public void setCancelDelegate(NextPageDelegate cancelDelegate) {
        // FIXME not implemented!
       
    }

    /**
     * Discovers the property keys that can be queried for a NULL value.
     * @return the array of nullable and/or non-mandatory property keys
     */
    public NSArray nullablePropertyKeys() {
        if (null == _nullablePropertyKeys) {
            NSMutableArray array = new NSMutableArray();
            String preKey = propertyKey();
            D2WContext d2wContext = d2wContext();
            for (Enumeration keysEnum = displayPropertyKeys().objectEnumerator(); keysEnum.hasMoreElements();) {
                String key = (String)keysEnum.nextElement();
                setPropertyKey(key);

                Object isMandatory = d2wContext.valueForKey("isMandatory");
                if (isMandatory != null && !ERXValueUtilities.booleanValue(isMandatory)) {
                    array.addObject(key);
                }
            }
            _nullablePropertyKeys = array;
            setPropertyKey(preKey); // Restore the property key.
        }
        return _nullablePropertyKeys;
    }

    /**
     * Determines if the null query checkbox for the current D2W property key should be checked.
     * @return true if the checkbox should be checked
     */
    public boolean isNullQueryCheckedForCurrentProperty() {
        return Boolean.TRUE.equals(keysToQueryForNull.valueForKey(propertyKey()));
    }

    /**
     * Sets the flag denoting a property key is being queried for a null value.
     * @param value of the checkbox' checked attribute
     */
    public void setIsNullQueryCheckedForCurrentProperty(boolean value) {
        keysToQueryForNull.takeValueForKey(value, propertyKey());
    }

    /**
     * Determines if the null query checkbox can be shown for the current D2W property key should be checked.
     * @return true if the checkbox should be checked
     */
    public boolean canQueryCurrentPropertyForNullValue() {
        boolean enabled = ERXValueUtilities.booleanValueWithDefault(d2wContext().valueForKey("enableQueryForNullValues"), false);
        boolean propertyAllowsQuery = ERXValueUtilities.booleanValueWithDefault(d2wContext().valueForKey("canQueryPropertyForNullValues"), true);
        return (enabled && propertyAllowsQuery && nullablePropertyKeys().containsObject(propertyKey()));
    }

    /**
     * When querying for properties with a null value, and the null value checkbox for a property key is checked, this
     * method substitutes <code>NSKeyValueCoding.NullValue</code> into the display group's query dictionaries for that
     * property key.
     */
    protected void substituteValueForNullableQueryKeys() {
        WODisplayGroup displayGroup = displayGroup();
        for(Enumeration nullableKeysEnum = nullablePropertyKeys().objectEnumerator(); nullableKeysEnum.hasMoreElements();) {
            String key = (String)nullableKeysEnum.nextElement();
            Boolean value = (Boolean)keysToQueryForNull.objectForKey(key);
            if (Boolean.TRUE.equals(value)) {
                displayGroup.queryOperator().takeValueForKey(EOQualifier.stringForOperatorSelector(EOQualifier.QualifierOperatorEqual), key);
                if (displayGroup.queryBindings().valueForKey(key) != null) {
                    displayGroup.queryBindings().takeValueForKey(NSKeyValueCoding.NullValue, key);
                } else {
                    displayGroup.queryMatch().takeValueForKey(NSKeyValueCoding.NullValue, key);
                }
            }
        }
    }

}
TOP

Related Classes of er.directtoweb.pages.ERD2WQueryPage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.