001    package hirondelle.web4jtools.metrics.base;
002    
003    import hirondelle.web4j.model.ModelCtorException;
004    import hirondelle.web4j.security.SafeText;
005    import hirondelle.web4j.model.Check;
006    import hirondelle.web4j.model.ModelUtil;
007    import hirondelle.web4j.model.Validator;
008    import java.io.*;
009    import static hirondelle.web4j.util.Consts.FAILS;
010    import static hirondelle.web4j.util.Consts.FILE_SEPARATOR;
011    import hirondelle.web4j.util.Util;
012    
013    /**
014    * Basic information on the target project. 
015    */
016    public final class BaseInfo {
017      
018      /**
019      * Full constructor.
020      * 
021      * @param aProjectName simple name or alias for the project, displayed as a reminder (required).
022      * @param aBaseDirectory base or root directory for your project's source files.
023      * @param aBaseURIForFetchingImages URI for running web app; when a simple image file 
024      * name is concatenated with this URI, then the image will be fetched. Used for listing all image files in 
025      * the target project.
026      */ 
027      public BaseInfo(SafeText aProjectName, SafeText aBaseDirectory, SafeText aBaseURIForFetchingImages) throws ModelCtorException {
028        fProjecName = aProjectName;
029        fBaseDirectory = aBaseDirectory;
030        fBaseURIForFetchingImages = aBaseURIForFetchingImages;
031        validateState();
032      }
033      
034      public SafeText getProjectName() {  return fProjecName; }
035      public SafeText getBaseDirectory() {  return fBaseDirectory; }
036      public SafeText getBaseURIForFetchingImages() {  return fBaseURIForFetchingImages; }
037      
038      /** Intended for debugging only.  */
039      @Override public String toString() {
040        return ModelUtil.toStringFor(this);
041      }
042    
043      @Override public boolean equals( Object aThat ) {
044        Boolean result = ModelUtil.quickEquals(this, aThat);
045        if ( result == null ){
046          BaseInfo that = (BaseInfo) aThat;
047          result = ModelUtil.equalsFor(this.getSignificantFields(), that.getSignificantFields());
048        }
049        return result;    
050      }
051    
052      @Override public int hashCode() {
053        if ( fHashCode == 0 ) {
054          fHashCode = ModelUtil.hashCodeFor(getSignificantFields());
055        }
056        return fHashCode;
057      }
058      
059      // PRIVATE //
060      private SafeText fProjecName;
061      private SafeText fBaseDirectory;
062      private SafeText fBaseURIForFetchingImages;  
063      private int fHashCode;
064      
065      private void validateState() throws ModelCtorException {
066        ModelCtorException ex = new ModelCtorException();
067        if( FAILS == Check.required(fProjecName) ) {
068          ex.add("Project Name is required.");
069        }
070        if ( FAILS == Check.required(fBaseDirectory, validDirectory())) {
071          ex.add("Base Directory is required: an existing, read-able directory, ending with a " + Util.quote(FILE_SEPARATOR) + ".");
072        }
073        if ( ex.isNotEmpty() ) throw ex;
074      }
075      
076      private Validator validDirectory() {
077        return new Validator() {
078          public boolean isValid(Object aObject) {
079            SafeText text = (SafeText)aObject;
080            File file = new File(text.getRawString());
081            return file.isDirectory() && file.exists() && file.canRead() && file.isAbsolute() && endsWithSeparator(text);
082          }
083        };
084      }
085      
086      private boolean endsWithSeparator(SafeText aDir){
087        return aDir.getRawString().endsWith(FILE_SEPARATOR);
088      }
089      
090      private Object[] getSignificantFields(){
091        return new Object[] {fProjecName, fBaseDirectory, fBaseURIForFetchingImages};
092      }
093    }