Package hirondelle.web4j.model

Source Code of hirondelle.web4j.model.Id

package hirondelle.web4j.model;

import java.io.Serializable;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
import hirondelle.web4j.model.ModelUtil;
import hirondelle.web4j.util.Consts;
import hirondelle.web4j.util.Util;
import hirondelle.web4j.security.SafeText;

/**
Building block class for identifiers.
<P>Identifiers are both common and important. Unfortunately, there is no class in the
JDK specifically for identifiers.
<P>An <tt>Id</tt> class is useful for these reasons :
<ul>
<li>it allows model classes to read at a higher level of abstraction. Identifiers are
labeled as such, and stand out very clearly from other items
<li>it avoids a common <a href="http://www.javapractices.com/Topic192.cjp">problem</a>
in modeling identifiers as numbers.
</ul>

<P>The underlying database column may be modeled as either text or as a number.
If the underlying column is of a numeric type, however, then a Data Access Object
will need to pass <tt>Id</tt> parameters to {@link hirondelle.web4j.database.Db}
using {@link #asInteger} or {@link #asLong}.

<P><em>Design Note :</em><br>
This class is <tt>final</tt>, immutable, {@link Serializable},
and {@link Comparable}, in imitation of the other building block classes
such as {@link String}, {@link Integer}, and so on.
*/
public final class Id implements Serializable, Comparable<Id> {

  /**
   Construct an identifier using an arbitrary {@link String}.
   
   This class uses a {@link SafeText} object internally.
   @param aText is non-null, and contains characters that are allowed
   by {@link hirondelle.web4j.security.PermittedCharacters}.
  */
  public Id(String aText) {
    fId = new SafeText(aText);
    validateState();
  }
 
  /**
   Factory method.
  
   Simply a slightly more compact way of building an object, as opposed to 'new'.
  */
  public static Id from(String aText){
    return new Id(aText);
  }

  /**
   Return this id as an {@link Integer}, if possible.
  
   <P>See class comment.
  
   <P>If this <tt>Id</tt> is not convertible to an {@link Integer}, then a {@link RuntimeException} is
   thrown.
  */
  public Integer asInteger(){
    return new Integer(fId.getRawString());
  }

  /**
   Return this id as a {@link Long}, if possible.
  
   <P>See class comment.
  
   <P>If this <tt>Id</tt> is not convertible to a {@link Long},
   then a {@link RuntimeException} is thrown.
  */
  public Long asLong(){
    return new Long(fId.getRawString());
  }
 
  /**
   Return the id, with special characters escaped.
  
   <P>The return value either has content (with no leading or trailing spaces),
   or is empty.
   See {@link hirondelle.web4j.util.EscapeChars#forHTML(String)} for a list of escaped
   characters.
  */
  @Override public String toString(){
    return fId.toString();
  }
 
  /** Return the text passed to the constructor. */
  public String getRawString(){
    return fId.getRawString();
  }
 
  /** Return the text with special  XML characters esacped. See {@link SafeText#getXmlSafe()}.  */
  public String getXmlSafe() {
    return fId.getXmlSafe();
  }
 
  @Override public boolean equals(Object aThat){
    Boolean result = ModelUtil.quickEquals(this, aThat);
    if ( result == null ){
      Id that = (Id) aThat;
      result = ModelUtil.equalsFor(this.getSignificantFields(), that.getSignificantFields());
    }
    return result;   
  }

  @Override public int hashCode(){
    return ModelUtil.hashCodeFor(getSignificantFields());
  }
 
  public int compareTo(Id aThat) {
    final int EQUAL = 0;
    if ( this == aThat ) return EQUAL;
    int comparison = this.fId.compareTo(aThat.fId);
    if ( comparison != EQUAL ) return comparison;
    return EQUAL;
  }
 
  // PRIVATE
 
  /** @serial  */
  private SafeText fId;
 
  /**
   For evolution of this class, see Sun guidelines :
   http://java.sun.com/j2se/1.5.0/docs/guide/serialization/spec/version.html#6678
  */
  private static final long serialVersionUID = 7526472295633676147L;
 
  /**
   Always treat de-serialization as a full-blown constructor, by
   validating the final state of the de-serialized object.
  */
  private void readObject(ObjectInputStream aInputStream) throws ClassNotFoundException, IOException {
     //always perform the default de-serialization first
     aInputStream.defaultReadObject();
     //make defensive copy of mutable fields (none here)
     //ensure that object state has not been corrupted or tampered with maliciously
     validateState();
  }

  /**
   This is the default implementation of writeObject.
   Customise if necessary.
  */
  private void writeObject(ObjectOutputStream aOutputStream) throws IOException {
    //perform the default serialization for all non-transient, non-static fields
    aOutputStream.defaultWriteObject();
  }
 
  private void validateState() {
    if( ! Util.textHasContent(fId) ) {
      if ( ! Consts.EMPTY_STRING.equals(fId.getRawString()) ) {
        throw new IllegalArgumentException(
          "Id must have content, or be the empty String. Erroneous Value : " + Util.quote(fId)
        );
      }
    }
  }
 
  private Object[] getSignificantFields(){
    return new Object[] {fId};
  }
}
TOP

Related Classes of hirondelle.web4j.model.Id

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.