Package org.wicketstuff.security.components.markup.html.links

Source Code of org.wicketstuff.security.components.markup.html.links.SecureContainerLink

/*
* 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.wicketstuff.security.components.markup.html.links;

import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.model.IModel;
import org.wicketstuff.security.actions.Enable;
import org.wicketstuff.security.actions.WaspAction;
import org.wicketstuff.security.checks.ISecurityCheck;
import org.wicketstuff.security.checks.LinkSecurityCheck;
import org.wicketstuff.security.components.ISecureComponent;
import org.wicketstuff.security.components.SecureComponentHelper;

/**
* A secure link to handle panel replacements or any other type of {@link MarkupContainer} s. It is
* also usable as a link to switch between 2 or more panels. Security is enforced on the replacing
* class, not on the panel. This means that the panels do not need to be {@link ISecureComponent}s,
* but are allowed to be if so desired. The link however will only show up if the user has the
* {@link Enable} action for the class of the replacement panel. Please consult your implementation
* on how to do that. This link is typically placed as a child on the parent of the panel it is
* supposed to replace. Like so:<br/>
* <code>
* MarkupContainer parent=new WebMarkupContainer("parent);
* parent.add(new FirstPanel("replaceMe",new Model("hello"));
* parent.add(new SecureContainerLink("link",SecondPanel.class,parent,"replaceMe"){....});
* </code>
*
* @author marrink
*/
public abstract class SecureContainerLink<T> extends Link<T> implements ISecureComponent
{
  /**
   *
   */
  private static final long serialVersionUID = 1L;

  private Class<? extends MarkupContainer> replacementClass;

  private MarkupContainer containerParent;

  private String containerId;

  /**
   * Constructs a new replacement link.
   *
   * @param id
   *            id of the link
   * @param replacementPanel
   *            the class of the container replacing the component on the supplied parent
   * @param parentOfReplaceablePanel
   *            the parent component where the replacement needs to take place
   * @param panelId
   *            the id of the component to be replaced
   */
  public SecureContainerLink(String id, Class<? extends MarkupContainer> replacementPanel,
    MarkupContainer parentOfReplaceablePanel, String panelId)
  {
    this(id, null, replacementPanel, parentOfReplaceablePanel, panelId);

  }

  /**
   * Constructs a new replacement link.
   *
   * @param id
   *            id of the link
   * @param object
   *            model of the link
   * @param replacementPanel
   *            the class of the container replacing the component on the supplied parent
   * @param parentOfReplaceablePanel
   *            the parent component where the replacement needs to take place
   * @param panelId
   *            the id of the component to be replaced
   */
  public SecureContainerLink(String id, IModel<T> object,
    Class<? extends MarkupContainer> replacementPanel,
    MarkupContainer parentOfReplaceablePanel, String panelId)
  {
    super(id, object);
    setReplacementClass(replacementPanel);
    if (parentOfReplaceablePanel == null)
      throw new WicketRuntimeException("Parent required for replacing components.");
    containerParent = parentOfReplaceablePanel;
    if (panelId == null)
      throw new WicketRuntimeException("Id required from component to be replaced.");
    containerId = panelId;
  }

  /**
   * Performs the replacement, only if an actual replacement was constructed.
   *
   * @see org.apache.wicket.markup.html.link.Link#onClick()
   * @see #getReplacementFor(Component, String, Class)
   * @throws WicketRuntimeException
   *             if a problem occurs in replacing the container.
   */
  @Override
  public final void onClick()
  {
    Component replaceMe = getComponentToBeReplaced();
    if (replaceMe == null)
      throw new WicketRuntimeException("unable to find child with id: " + containerId +
        " on parent: " + containerParent);
    Class<? extends MarkupContainer> myReplacementClass = getReplacementClass();
    MarkupContainer replacement = getReplacementFor(replaceMe, containerId, myReplacementClass);
    if (replacement == null)
      return; // do nothing
    if (!containerId.equals(replacement.getId()))
      throw new WicketRuntimeException("The replacement does not have the specified id: " +
        containerId + ", but id: " + replacement.getId());
    if (myReplacementClass.isAssignableFrom(replacement.getClass()))
      containerParent.replace(replacement);
    else
      throw new WicketRuntimeException("The replacement for " + containerId + " on " +
        containerParent + " is not assignable from " + myReplacementClass);

  }

  /**
   * The component, usually a MarkupContainer or subclass, that will be replaced by the output
   * from {@link #getReplacementFor(Component, String, Class)}.
   *
   * @return the component or null if the id specified at the constructor is bogus.
   */
  protected final Component getComponentToBeReplaced()
  {
    return containerParent.get(containerId);
  }

  /**
   * Creates a replacement for a component. although the component to be replaced does not need to
   * be a {@link MarkupContainer} it typically is. The replacement however does need to be a
   * MarkupContainer, more specifically a (sub)class of replacementClass. Implementation may
   * choose at this point to do the next replacement with a different class by using
   * {@link #setReplacementClass(Class)} in order to create a switch like behavior. The intention
   * of this method is thus to create the new panel, for example:<br/>
   * <code>
   * protected MarkupContainer getReplacementFor(Component current, String id,
   *     Class replacementClass)
   *   {
   *     //does a one time replace
   *     if(MyPanel.class.isAssignableFrom(replacementClass)
   *     {
   *       //if this link is not a child of current, you might want to hide it after the replace has taken place
   *       this.setVisible(false);
   *       return new MyPanel(id, current.getModel());
   *     }
   *   }
   * </code> Or if this link should switch between panels and is situated somewhere higher in the
   * component hierarchy as these panels it is supposed to switch you could do something like
   * this: <br/>
   * <code>
   * protected MarkupContainer getReplacementFor(Component current, String id,
   *     Class replacementClass)
   *   {
   *     //continually switches between two panels
   *    
   *     //prepare the next replacement
   *     setReplacementClass(current.getClass();
   *     //do the switch
   *     if(MyPanel.class.isAssignableFrom(replacementClass)
   *     {
   *       return new MyPanel(id, current.getModel());
   *     }
   *     //other panel
   *     else
   *     {
   *       return new MyOtherPanel(id, current.getModel());
   *     }
   *   }
   * </code>
   *
   * @param current
   *            the component to be replaced
   * @param id
   *            the id of the new container
   * @param replacementClass
   *            the class of the replacement
   * @return a new replacement or null if the original component is not to be replaced
   * @see #setReplacementClass(Class)
   */
  protected abstract MarkupContainer getReplacementFor(Component current, String id,
    Class<? extends MarkupContainer> replacementClass);

  /**
   * Generates the securitycheck for this link. by default this is a {@link LinkSecurityCheck} but
   * implementations may choose to override this. Note that the returned LinkSecurityCheck should
   * not be placed in alternative rendering mode as this will completely change the intended
   * behavior.
   *
   * @return the securitycheck for this link or null if no security is to be enforced
   */
  protected ISecurityCheck generateSecurityCheck()
  {
    return new LinkSecurityCheck(this, getReplacementClass());
  }

  /**
   *
   * @see org.wicketstuff.security.components.ISecureComponent#getSecurityCheck()
   */
  public ISecurityCheck getSecurityCheck()
  {
    return SecureComponentHelper.getSecurityCheck(this);
  }

  /**
   *
   * @see org.wicketstuff.security.components.ISecureComponent#isActionAuthorized(java.lang.String)
   */
  public boolean isActionAuthorized(String waspAction)
  {
    return SecureComponentHelper.isActionAuthorized(this, waspAction);
  }

  /**
   *
   * @see org.wicketstuff.security.components.ISecureComponent#isActionAuthorized(WaspAction)
   */
  public boolean isActionAuthorized(WaspAction action)
  {
    return SecureComponentHelper.isActionAuthorized(this, action);
  }

  /**
   *
   * @see org.wicketstuff.security.components.ISecureComponent#isAuthenticated()
   */
  public boolean isAuthenticated()
  {
    return SecureComponentHelper.isAuthenticated(this);
  }

  /**
   *
   * @see org.wicketstuff.security.components.ISecureComponent#setSecurityCheck(org.wicketstuff.security.checks.ISecurityCheck)
   */
  public void setSecurityCheck(ISecurityCheck check)
  {
    SecureComponentHelper.setSecurityCheck(this, check);
  }

  /**
   * Gets replacementClass.
   *
   * @return replacementClass
   */
  protected final Class<? extends MarkupContainer> getReplacementClass()
  {
    return replacementClass;
  }

  /**
   * Sets replacementClass. Note by changing the replacement class a new securitycheck is
   * automatically created.
   *
   * @param replacementClass
   *            replacementClass
   * @see #generateSecurityCheck()
   * @throws WicketRuntimeException
   *             if the class is null or not a {@link MarkupContainer}
   */
  protected final void setReplacementClass(Class<? extends MarkupContainer> replacementClass)
  {
    if (replacementClass == null)
      throw new WicketRuntimeException("replacementClass cannot be null");
    this.replacementClass = replacementClass;
    setSecurityCheck(generateSecurityCheck());
  }
}
TOP

Related Classes of org.wicketstuff.security.components.markup.html.links.SecureContainerLink

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.