Open Source Repository

Home /hibernate/hibernate-3.2.6.ga | Repository Home


org/hibernate/engine/CascadeStyle.java
//$Id: CascadeStyle.java 10800 2006-11-13 19:34:44Z [email protected] $
package org.hibernate.engine;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import org.hibernate.MappingException;
import org.hibernate.util.ArrayHelper;

/**
 * A contract for defining the aspects of cascading various persistence actions.
 *
 @see CascadingAction
 
 @author Gavin King
 */
public abstract class CascadeStyle implements Serializable {

  /**
   * For this style, should the given action be cascaded?
   *
   @param action The action to be checked for cascade-ability.
   @return True if the action should be cascaded under this style; false otherwise.
   */
  public abstract boolean doCascade(CascadingAction action);
  
  /**
   * Probably more aptly named something like doCascadeToCollectionElements(); it is
   * however used from both the collection and to-one logic branches...
   <p/>
   * For this style, should the given action really be cascaded?  The default
   * implementation is simply to return {@link #doCascade}; for certain
   * styles (currently only delete-orphan), however, we need to be able to
   * control this seperately.
   *
   @param action The action to be checked for cascade-ability.
   @return True if the action should be really cascaded under this style;
   * false otherwise.
   */
  public boolean reallyDoCascade(CascadingAction action) {
    return doCascade(action);
  }

  /**
   * Do we need to delete orphaned collection elements?
   *
   @return True if this style need to account for orphan delete
   * operations; false othwerwise.
   */
  public boolean hasOrphanDelete() {
    return false;
  }

  public static final class MultipleCascadeStyle extends CascadeStyle {
    private final CascadeStyle[] styles;
    public MultipleCascadeStyle(CascadeStyle[] styles) {
      this.styles = styles;
    }
    public boolean doCascade(CascadingAction action) {
      for (int i=0; i<styles.length; i++) {
        if styles[i].doCascade(action) ) return true;
      }
      return false;
    }
    public boolean reallyDoCascade(CascadingAction action) {
      for (int i=0; i<styles.length; i++) {
        if styles[i].reallyDoCascade(action) ) return true;
      }
      return false;
    }
    public boolean hasOrphanDelete() {
      for (int i=0; i<styles.length; i++) {
        if styles[i].hasOrphanDelete() ) return true;
      }
      return false;
    }
    public String toString() {
      return ArrayHelper.toString(styles);
    }
  }
  
  /**
   * save / delete / update / evict / lock / replicate / merge / persist + delete orphans
   */
  public static final CascadeStyle ALL_DELETE_ORPHAN = new CascadeStyle() {
    public boolean doCascade(CascadingAction action) {
      return true;
    }
    public boolean hasOrphanDelete() {
      return true;
    }
    public String toString() {
      return "STYLE_ALL_DELETE_ORPHAN";
    }
  };
  
  /**
   * save / delete / update / evict / lock / replicate / merge / persist
   */
  public static final CascadeStyle ALL = new CascadeStyle() {
    public boolean doCascade(CascadingAction action) {
      return true;
    }
    public String toString() {
      return "STYLE_ALL";
    }
  };
  
  /**
   * save / update
   */
  public static final CascadeStyle UPDATE = new CascadeStyle() {
    public boolean doCascade(CascadingAction action) {
      return action==CascadingAction.SAVE_UPDATE || action==CascadingAction.SAVE_UPDATE_COPY;
    }
    public String toString() {
      return "STYLE_SAVE_UPDATE";
    }
  };
  
  /**
   * lock
   */
  public static final CascadeStyle LOCK = new CascadeStyle() {
    public boolean doCascade(CascadingAction action) {
      return action==CascadingAction.LOCK;
    }
    public String toString() {
      return "STYLE_LOCK";
    }
  };
  
  /**
   * refresh
   */
  public static final CascadeStyle REFRESH = new CascadeStyle() {
    public boolean doCascade(CascadingAction action) {
      return action==CascadingAction.REFRESH;
    }
    public String toString() {
      return "STYLE_REFRESH";
    }
  };
  
  /**
   * evict
   */
  public static final CascadeStyle EVICT = new CascadeStyle() {
    public boolean doCascade(CascadingAction action) {
      return action==CascadingAction.EVICT;
    }
    public String toString() {
      return "STYLE_EVICT";
    }
  };
  
  /**
   * replicate
   */
  public static final CascadeStyle REPLICATE = new CascadeStyle() {
    public boolean doCascade(CascadingAction action) {
      return action==CascadingAction.REPLICATE;
    }
    public String toString() {
      return "STYLE_REPLICATE";
    }
  };
  /**
   * merge
   */
  public static final CascadeStyle MERGE = new CascadeStyle() {
    public boolean doCascade(CascadingAction action) {
      return action==CascadingAction.MERGE;
    }
    public String toString() {
      return "STYLE_MERGE";
    }
  };
  
  /**
   * create
   */
  public static final CascadeStyle PERSIST = new CascadeStyle() {
    public boolean doCascade(CascadingAction action) {
      return action==CascadingAction.PERSIST
        || action==CascadingAction.PERSIST_ON_FLUSH;
    }
    public String toString() {
      return "STYLE_PERSIST";
    }
  };
  
  /**
   * delete
   */
  public static final CascadeStyle DELETE = new CascadeStyle() {
    public boolean doCascade(CascadingAction action) {
      return action==CascadingAction.DELETE;
    }
    public String toString() {
      return "STYLE_DELETE";
    }
  };
  
  /**
   * delete + delete orphans
   */
  public static final CascadeStyle DELETE_ORPHAN = new CascadeStyle() {
    public boolean doCascade(CascadingAction action) {
      return action==CascadingAction.DELETE || action==CascadingAction.SAVE_UPDATE;
    }
    public boolean reallyDoCascade(CascadingAction action) {
      return action==CascadingAction.DELETE;
    }
    public boolean hasOrphanDelete() {
      return true;
    }
    public String toString() {
      return "STYLE_DELETE_ORPHAN";
    }
  };
  
  /**
   * no cascades
   */
  public static final CascadeStyle NONE = new CascadeStyle() {
    public boolean doCascade(CascadingAction action) {
      return false;
    }
    public String toString() {
      return "STYLE_NONE";
    }
  };

  /**
   * package-protected constructor
   */
  CascadeStyle() {
  }

  static final Map STYLES = new HashMap();

  static {
    STYLES.put"all", ALL );
    STYLES.put"all-delete-orphan", ALL_DELETE_ORPHAN );
    STYLES.put"save-update", UPDATE );
    STYLES.put"persist", PERSIST );
    STYLES.put"merge", MERGE );
    STYLES.put"lock", LOCK );
    STYLES.put"refresh", REFRESH );
    STYLES.put"replicate", REPLICATE );
    STYLES.put"evict", EVICT );
    STYLES.put"delete", DELETE );
    STYLES.put"remove", DELETE )// adds remove as a sort-of alias for delete...
    STYLES.put"delete-orphan", DELETE_ORPHAN );
    STYLES.put"none", NONE );
  }

  /**
   * Factory method for obtaining named cascade styles
   *
   @param cascade The named cascade style name.
   @return The appropriate CascadeStyle
   */
  public static CascadeStyle getCascadeStyle(String cascade) {
    CascadeStyle style = (CascadeStyleSTYLES.get(cascade);
    if (style==null) {
      throw new MappingException("Unsupported cascade style: " + cascade);
    }
    else {
      return style;
    }  
  }
}