org.apache.wicket.behavior.Behavior.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.wicket.behavior.Behavior.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.wicket.behavior;

import org.apache.wicket.Application;
import org.apache.wicket.Component;
import org.apache.wicket.IComponentAwareEventSink;
import org.apache.wicket.IRequestListener;
import org.apache.wicket.event.IEvent;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.html.IComponentAwareHeaderContributor;
import org.apache.wicket.markup.parser.XmlTag.TagType;
import org.apache.wicket.util.io.IClusterable;
import org.apache.wicket.util.lang.Args;
import org.danekja.java.util.function.serializable.SerializableBiConsumer;
import org.danekja.java.util.function.serializable.SerializableFunction;

/**
 * Behaviors are kind of plug-ins for Components. They allow functionality to be added to a
 * component and get essential events forwarded by the component. They can be bound to a concrete
 * component (using the bind method which is called when the behavior is attached), but they don't
 * need to. They can modify the components markup by changing the rendered ComponentTag. Behaviors
 * can have their own models as well, and they are notified when these are to be detached by the
 * component.
 * <p>
 * You also cannot modify a components model with a behavior.
 * </p>
 * 
 * @see IRequestListener
 * @see org.apache.wicket.markup.html.IHeaderContributor
 * @see org.apache.wicket.behavior.AbstractAjaxBehavior
 * @see org.apache.wicket.AttributeModifier
 * 
 * @author Ralf Ebert
 * @author Eelco Hillenius
 * @author Igor Vaynberg (ivaynberg)
 */
public abstract class Behavior implements IClusterable, IComponentAwareEventSink, IComponentAwareHeaderContributor {
    private static final long serialVersionUID = 1L;

    /**
     * Constructor
     */
    public Behavior() {
        if (Application.exists()) {
            Application.get().getBehaviorInstantiationListeners().onInstantiation(this);
        }
    }

    /**
     * Called when a component is about to render.
     * 
     * @param component
     *            the component that has this behavior coupled
     */
    public void beforeRender(Component component) {
    }

    /**
     * Called when a component that has this behavior coupled was rendered.
     * 
     * @param component
     *            the component that has this behavior coupled
     */
    public void afterRender(Component component) {
    }

    /**
     * Bind this handler to the given component. This method is called by the host component
     * immediately after this behavior is added to it. This method is useful if you need to do
     * initialization based on the component it is attached and you can't wait to do it at render
     * time. Keep in mind that if you decide to keep a reference to the host component, it is not
     * thread safe anymore, and should thus only be used in situations where you do not reuse the
     * behavior for multiple components.
     * 
     * @param component
     *            the component to bind to
     */
    public void bind(Component component) {
    }

    /**
     * Notifies the behavior it is removed from the specified component
     * 
     * @param component
     *            the component this behavior is unbound from
     */
    public void unbind(Component component) {
    }

    /**
     * Allows the behavior to detach any state it has attached during request processing.
     * 
     * @param component
     *            the component that initiates the detachment of this behavior
     */
    public void detach(Component component) {
    }

    /**
     * In case an unexpected exception happened anywhere between
     * {@linkplain #onComponentTag(org.apache.wicket.Component, org.apache.wicket.markup.ComponentTag)} and
     * {@linkplain #afterRender(org.apache.wicket.Component)},
     * onException() will be called for any behavior. Typically, if you clean up resources in
     * {@link #afterRender(Component)}, you should do the same in the implementation of this method.
     * 
     * @param component
     *            the component that has a reference to this behavior and during which processing
     *            the exception occurred
     * @param exception
     *            the unexpected exception
     */
    public void onException(Component component, RuntimeException exception) {
    }

    /**
     * This method returns false if the behavior generates a callback url (for example ajax
     * behaviors)
     * 
     * @param component
     *            the component that has this behavior coupled.
     * 
     * @return boolean true or false.
     */
    public boolean getStatelessHint(Component component) {
        if (this instanceof IRequestListener) {
            // this behavior implements a callback interface, so it cannot be stateless
            return false;
        }
        return true;
    }

    /**
     * Called when a components is rendering and wants to render this behavior. If false is returned
     * this behavior will be ignored.
     * 
     * @param component
     *            the component that has this behavior coupled
     * 
     * @return true if this behavior must be executed/rendered
     */
    public boolean isEnabled(Component component) {
        return true;
    }

    /**
     * Called any time a component that has this behavior registered is rendering the component tag.
     * 
     * @param component
     *            the component that renders this tag currently
     * @param tag
     *            the tag that is rendered
     */
    public void onComponentTag(Component component, ComponentTag tag) {
    }

    /**
     * Specifies whether or not this behavior is temporary. Temporary behaviors are removed at the
     * end of request and never reattached. Such behaviors are useful for modifying component
     * rendering only when it renders next. Usecases include javascript effects, initial clientside
     * dom setup, etc.
     * 
     * @param component
     * 
     * @return true if this behavior is temporary
     */
    public boolean isTemporary(Component component) {
        return false;
    }

    /**
     * Checks whether or not an {@link IRequestListener} can be invoked on this behavior. For further
     * information please read the javadoc on {@link Component#canCallListener()},
     * this method has the same semantics.
     * 
     * WARNING: Read the javadoc of {@link Component#canCallListener()} for important
     * security-related information.
     * 
     * @param component
     *            component this behavior is attached to
     * @return {@literal true} iff the listener method can be invoked
     */
    public boolean canCallListener(Component component) {
        return isEnabled(component) && component.canCallListener();
    }

    /**
     * Render to the web response whatever the component wants to contribute to the head section.
     * 
     * @param component
     * 
     * @param response
     *            Response object
     */
    @Override
    public void renderHead(Component component, IHeaderResponse response) {
    }

    /**
     * Called immediately after the onConfigure method in a component. Since this is before the
     * rendering cycle has begun, the behavior can modify the configuration of the component (i.e.
     * setVisible(false))
     * 
     * @param component
     *            the component being configured
     */
    public void onConfigure(Component component) {
    }

    /**
     * Called to notify the behavior about any events sent to the component
     * 
     * @see org.apache.wicket.IComponentAwareEventSink#onEvent(org.apache.wicket.Component,
     *      org.apache.wicket.event.IEvent)
     */
    @Override
    public void onEvent(Component component, IEvent<?> event) {
    }

    /**
     * Called to notify that the component is being removed from its parent
     * @param component
     *      the removed component
     */
    public void onRemove(Component component) {
    }

    /**
     * Creates a {@link Behavior} that uses the given {@code SerializableConsumer consumer} to do
     * something with the component's tag.
     *
     * <p>
     * Usage:<br/>
     * <code>component.add(onTag(tag -> tag.put(key, value)));</code>
     * </p>
     *
     * @param onTagConsumer
     *            the {@code SerializableConsumer} that accepts the {@link ComponentTag}
     * @return The created behavior
     */
    public static Behavior onTag(SerializableBiConsumer<Component, ComponentTag> onTagConsumer) {
        Args.notNull(onTagConsumer, "onTagConsumer");

        return new Behavior() {
            @Override
            public void onComponentTag(Component component, ComponentTag tag) {
                onTagConsumer.accept(component, tag);
            }
        };
    }

    /**
     * Creates a {@link Behavior} that uses the given {@code SerializableFunction function} to do
     * something with a component's attribute.
     *
     * <p>
     * Usage:<br/>
     * <code>component.add(onAttribute("class",
     *              currentValue -> condition(currentValue) ? "positive" : "negative"));</code>
     * </p>
     *
     * @param name
     *            the name of the attribute to manipulate
     * @param onAttribute
     *            the {@code SerializableFunction} that accepts the old value of the attribute and
     *            returns a new value
     * @return The created behavior
     */
    public static Behavior onAttribute(String name, SerializableFunction<String, CharSequence> onAttribute) {
        Args.notEmpty(name, "name");
        Args.notNull(onAttribute, "onAttribute");

        return new Behavior() {
            private static final long serialVersionUID = 1L;

            @Override
            public void onComponentTag(Component component, ComponentTag tag) {
                if (tag.getType() != TagType.CLOSE) {
                    String oldValue = tag.getAttribute(name);
                    tag.put(name, onAttribute.apply(oldValue));
                }
            }
        };
    }

}