Package er.directtoweb.components

Source Code of er.directtoweb.components.ERDCustomComponent$Keys

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

import org.apache.log4j.Logger;

import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WOResponse;
import com.webobjects.directtoweb.D2WContext;
import com.webobjects.directtoweb.D2WPage;
import com.webobjects.foundation.NSDictionary;

import er.directtoweb.ERDirectToWeb;
import er.directtoweb.pages.ERD2WPage;
import er.extensions.components.ERXNonSynchronizingComponent;
import er.extensions.eof.ERXConstant;
import er.extensions.validation.ERXExceptionHolder;

/**
* <span class="en">
* Base class of many custom components.<br />
* Has a lot of nifty features including resolving bindings against the rule system and inherits all the value pulling methods from {@link ERXNonSynchronizingComponent}.
* Subclasses should be able to run stand alone without a D2W context. This is achieved by pulling values first from the bindings, then from the d2wContext and finally from an "extraBindings" binding.
* </span>
*
* <span class="ja">
* たくさんのカスタム・コンポーネントのベース・クラスである
*
* ルール・システムへのバインディングや {@link ERXNonSynchronizingComponent} の値バインディング取得機能等の必要な処理をたくさん含みます。
*
* サブクラスは D2W コンテキスト無しでスタンドアロンで実行可能です。最初はコンポーネント・バインディングを優先で取得を試し、
* だめなら、 d2wContext と後は "extraBindings" バインディングより。
*
* @d2wKey localContext - d2wContext (deprecated)
* @d2wKey d2wContext - d2wContext
* @d2wKey key - プロパティ・キー
* @d2wKey extraBindings - オプション・バインディング
* @d2wKey propertyKey - プロパティ・キー
* </span>
*/
public abstract class ERDCustomComponent extends ERXNonSynchronizingComponent implements ERXExceptionHolder {
  /**
   * 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;

    public static interface Keys {
        public static final String key = "key";
        public static final String localContext = "localContext";
        public static final String d2wContext = "d2wContext";
        public static final String extraBindings = "extraBindings";
        public static final String propertyKey = "propertyKey";
    }
   
    /** logging support */
    public final static Logger log = Logger.getLogger(ERDCustomComponent.class);
   
    /** Designated constructor */
    public ERDCustomComponent(WOContext context) {
        super(context);
    }

    /** Holds the {@link D2WContext}. */
    private D2WContext d2wContext;

    /** Holds the current D2W task. */
    private String task;

    /** Holds the property key. */
    private String key;

    /** Holds the extra bindings. */
    protected Object extraBindings;

    //CHECKME ak: who needs this?
    protected static final Integer TRUE = ERXConstant.OneInteger;
    protected static final Integer FALSE = ERXConstant.ZeroInteger;

    /** Sets the {@link D2WContext}. Applies when used inside a D2WCustomComponent.*/
    public void setLocalContext(D2WContext value) {
        setD2wContext(value);
    }

    /** Sets the {@link D2WContext}. Applies when used inside a property key repetition.*/
    public void setD2wContext(D2WContext value) {
        d2wContext = value;
    }

    /** The active {@link D2WContext}. Simply calls to {@link #d2wContext()}*/
    public D2WContext localContext() {
        return d2wContext();
    }

    /** The active {@link D2WContext}.*/
    public D2WContext d2wContext() {
        return d2wContextFromBindings();
    }

    /**
     * <span class="en">
     * Returns the active d2wContext. If the value was not set via KVC, tries to get the value from the bindings if the component is non-syncing
     * </span>
     *
     * <span class="ja">
     * アクティブな d2wContext を戻します。
     * KVC で設定されていなければ、非シンクロナイズ・コンポーネントのバインディングより取得を試し見る
     * </span>
     */
    protected D2WContext d2wContextFromBindings() {
        if (d2wContext == null && !synchronizesVariablesWithBindings()) {
            d2wContext = (D2WContext)super.valueForBinding(Keys.localContext);
            if(d2wContext == null) {
                d2wContext = (D2WContext)super.valueForBinding(Keys.d2wContext);
            }
        }
        return d2wContext;
    }

    /**
     * Gets the current D2W task.
     */
    public String task() {
        if (task == null) {
            task = (String)valueForBinding("task");
        }
        return task;
    }
   
    public boolean taskIsEdit() { return "edit".equals(task()); }
    public boolean taskIsInspect() { return "inspect".equals(task()); }
    public boolean taskIsList() { return "list".equals(task()); }

    /**
     * <span class="en">Validation Support. Passes errors to the parent. </span>
     * <span class="ja">Validation Support. エラーを親コンポーネントに渡す</span>
     */
    @Override
    public void validationFailedWithException (Throwable e, Object value, String keyPath) {
        parent().validationFailedWithException(e,value,keyPath);
    }

    /**
     * <span class="en">Implementation of the {@link ERXExceptionHolder} interface. Clears exceptions in the parent if possible.</span>
     * <span class="ja">{@link ERXExceptionHolder} インタフェース実装。可能であれば、親のエラーをクリアします。</span>
     */
    public void clearValidationFailed() {
        // Since this component can be used stand alone, we might not necessarily
        // have an exception holder as our parent --> testing
        if (parent() instanceof ERXExceptionHolder)
            ((ERXExceptionHolder)parent()).clearValidationFailed();
    }

    /** @deprecated use {@link #booleanValueForBinding(String)} */
    @Deprecated
    public boolean booleanForBinding(String binding) {
        return booleanValueForBinding(binding);
    }

    // CHECKME ak who needs this?
    public Integer integerBooleanForBinding(String binding) {
        return booleanValueForBinding(binding) ? ERDCustomComponent.TRUE : ERDCustomComponent.FALSE;
    }

    /**
     * <span class="en">
     * Checks if the binding can be pulled. If the component is synching, throws an Exception. Otherwise checks the superclass and if the value for the binding is not null.
     * </span>
     *
     * <span class="ja">
     * バインディングが取得可能かどうかをチェックします。シンクロナイズ・コンポーネントの場合にはエラーを発行します。
     * そうでなければ、スーパークラスをバインディングが非 null であるようにチェックします
     * </span>
     */
    @Override
    public boolean hasBinding(String binding) {
        // FIXME:  Turn this check off in production
        if (synchronizesVariablesWithBindings()) {
            throw new IllegalStateException("HasBinding being used in an object of class " + getClass().getName() + " that synchronizesVariablesWithBindings == true");
        }
        return (super.hasBinding(binding) || valueForBinding(binding) != null);
    }

    /** Utility to dump some debug info about this component and its parent */
    protected void logDebugInfo() {
        if (log.isDebugEnabled()) {
            log.debug("***** ERDCustomComponent: this: " + getClass().getName());
            log.debug("***** ERDCustomComponent: parent(): + (" + ((parent() == null) ? "null" : parent().getClass().getName()) + ")");
            log.debug("                      " + parent());
            log.debug("***** ERDCustomComponent: parent() instanceof ERDCustomComponent == " + (parent() instanceof ERDCustomComponent));
            log.debug("***** ERDCustomComponent: parent() instanceof D2WCustomComponentWithArgs == " + (parent() instanceof ERD2WCustomComponentWithArgs));
            log.debug("***** ERDCustomComponent: parent() instanceof D2WStatelessCustomComponentWithArgs == " + (parent() instanceof ERD2WStatelessCustomComponentWithArgs));
            log.debug("***** ERDCustomComponent: parent() instanceof D2WCustomQueryComponentWithArgs == " + (parent() instanceof ERDCustomQueryComponentWithArgs));
        }
    }

    /**
     * <span class="en">Utility to pull the value from the components parent, if the parent is a D2W wrapper component.</span>
     * <span class="ja">親コンポーネントが D2W ラパー・コンポーネントの場合のバインディング取得ユーティリティ</span>
     */
    protected Object parentValueForBinding(String binding) {
        WOComponent parent = parent();
        if (parent instanceof ERDCustomComponent ||
            parent instanceof ERD2WCustomComponentWithArgs ||
            parent instanceof ERD2WStatelessCustomComponentWithArgs) {
            log.debug("inside the parent instanceof branch");
            // this will eventually bubble up to a D2WCustomComponentWithArgs, where it will (depending on the actual binding)
            // go to the d2wContext
            return parent.valueForBinding(binding);
        }
        return null;
    }

    /**
     * <span class="en">Utility to pull the value from the components actual bindings. </span>
     * <span class="ja">コンポーネントのバインディングから取得するユーティリティ</span>
     */
    protected Object originalValueForBinding(String binding) {
        return super.valueForBinding(binding);
    }

    /**
     * <span class="en">Utility to pull the value from the {@link D2WContext}. </span>
     * <span class="ja">{@link D2WContext} から値を取得するユーティリティ</span>
     */
    protected Object d2wContextValueForBinding(String binding) {
        return d2wContextFromBindings().valueForKey(binding);
    }

    /** Utility to pull the value from the extra bindings if supplied. */
    protected Object extraBindingsValueForBinding(String binding) {
        if(extraBindings() instanceof NSDictionary)
            return ((NSDictionary)extraBindings()).objectForKey(binding);
        return null;
    }

    /**
     * <span class="en">
     * Fetches an object from the bindings.
     * Tries the actual supplied bindings, the supplied d2wContext, the parent and finally the extra bindings dictionary.
     * </span>
     *
     * <span class="ja">
     * バインディングを使って、オブジェクトをフェッチする
     * バインディングを次の順で取得を試す:コンポーネント、d2wContext、親コンポーネント、オプション・バインディング・ディクショナリー
     * </span>
     */
    @Override
    public Object valueForBinding(String binding) {
        Object value=null;
        logDebugInfo();
        if (super.hasBinding(binding)) {
            if (log.isDebugEnabled())
              log.debug("super.hasBinding(binding) == true for binding "+binding);
            value = originalValueForBinding(binding);
        } else if(d2wContextFromBindings() != null) {
          if (log.isDebugEnabled())
            log.debug("has d2wContext == true for binding "+binding);
            value = d2wContextValueForBinding(binding);
        } else {
            value = parentValueForBinding(binding);
        }
        if (value == null && binding != null && extraBindings() != null) {
          if (log.isDebugEnabled())
            log.debug("inside the extraBindings branch for binding "+binding);
            value = extraBindingsValueForBinding(binding);
        }
        if (log.isDebugEnabled()) {
            if (value != null)
                log.debug("returning " + value.getClass().getName() + ": " + value+" for binding "+binding);
            else
                log.debug("returning value: null for binding "+binding);
        }
        return value;
    }

    /** Used by stateful but non-synching subclasses */
    @Override
    public void resetCachedBindingsInStatefulComponent() {
        super.resetCachedBindingsInStatefulComponent();
        extraBindings = null;
        key = null;
        d2wContext = null;
        task = null;
    }

    /** Used by stateless subclasses. */
    @Override
    public void reset() {
        super.reset();
        extraBindings = null;
        key = null;
        d2wContext = null;
        task = null;
    }

    /** Sets the extra bindings. */
    public void setExtraBindings(Object value) { extraBindings = value; }

    /** Extra bindings supplied to the component. If this is a dictionary, it will be used for additional bindings.*/
    public Object extraBindings() {
        if (extraBindings == null && !synchronizesVariablesWithBindings())
            extraBindings = super.valueForBinding(Keys.extraBindings);
        return extraBindings;
    }

    /** Sets the property key. */
    public void setKey(String newKey) { key=newKey; }

    /** The active property key. */
    public String key() {
      //FIXME : バグフィックス:複数のカスタム・コンポーネントを複数のタブに設定すると正しく設定されず。
      //if(synchronizesVariablesWithBindings()) {
      //  key = null;
      //}

      if(!synchronizesVariablesWithBindings()) {
            if (key==null) {
                key=(String)super.valueForBinding(Keys.key);
            }
        }
        if (key==null && d2wContext() != null) {
            key=(String)d2wContext().valueForKey(Keys.propertyKey);
        }
        return key;
    }

    /** Overridden from superclass to turn on component synching, which is the default. */
    @Override
    public boolean synchronizesVariablesWithBindings() { return true; } // CHECKME why then does this class subclass ERXNonSynchronizingComponent?

    /** Is D2W debugging enabled. */
    public boolean d2wDebuggingEnabled() {
        return ERDirectToWeb.d2wDebuggingEnabled(session());
    }

    /**
     * <span class="en">Should the component name be shown. </span>
     * <span class="ja">コンポーネント名を表示する?</span>
     */
    public boolean d2wComponentNameDebuggingEnabled() {
        return ERDirectToWeb.d2wComponentNameDebuggingEnabled(session());
    }

    /**
     * <span class="en">Should the property keys be shown.</span>
     * <span class="ja">プロパティ・キーを表示する?</span>
     */
    public boolean d2wPropertyKeyDebuggingEnabled() {
        return ERDirectToWeb.d2wPropertyKeyDebuggingEnabled(session());
    }

    /**
     * <span class="en">
     * Finds the containing D2WPage, if possible.  There are certain situations when having a
     * reference to the containing D2W page is useful, e.g., when needing to use the userInfo
     * dictionary of {@link ERD2WPage} to pass information between subcomponents.
     *
     * @return the containing D2WPage
     * </span>
     *
     * <span class="ja">
     * 可能であれば、D2WPage の親コンポーネントを戻します。
     * 場合によって、親 D2W ページへのアクセスは必要です。
     * ユーザ情報ディクショナリーへのアクセス等でサブコンポーネントの情報交換が可能です。
     *
     * @return 親 D2WPage
     * </span>
     */
    public D2WPage d2wPage() {
        // Can't just use context().page(), because the d2wPage isn't necessarily the top-level
        // component.
        WOComponent component = this;

        do {
            component = component.parent();
        } while( component != null && !(component instanceof D2WPage) );

        return (D2WPage)component;
    }

    @Override
    public void appendToResponse(WOResponse r, WOContext c) {
        if(!ERDirectToWeb.shouldRaiseException(false)) {
            // in the case where we are non-synchronizing but not stateless, make sure we pull again
            if (!synchronizesVariablesWithBindings() && !isStateless()) {
                reset();
            }
            super.appendToResponse(r,c);
        } else {
            try {
                // in the case where we are non-synchronizing but not stateless, make sure we pull again
                if (!synchronizesVariablesWithBindings() && !isStateless()) {
                    reset();
                }
                super.appendToResponse(r,c);
            } catch(Exception ex) {
                ERDirectToWeb.reportException(ex, d2wContext());
            }
        }
    }
}
TOP

Related Classes of er.directtoweb.components.ERDCustomComponent$Keys

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.