001 package hirondelle.web4jtools.codegenerator.feature; 002 003 import hirondelle.web4j.model.ModelCtorException; 004 import hirondelle.web4j.model.ModelUtil; 005 import hirondelle.web4jtools.util.Check; 006 import hirondelle.web4j.util.Util; 007 import static hirondelle.web4j.util.Consts.FAILS; 008 import hirondelle.web4jtools.codegenerator.codes.ApplyOperation; 009 import hirondelle.web4jtools.codegenerator.codes.ShowOperation; 010 import hirondelle.web4jtools.codegenerator.codes.UiStyle; 011 012 /** 013 * Model Object for your feature's basic information. 014 * 015 * <P>When generating code for a new feature, you start by entering this data. 016 */ 017 public final class Feature { 018 019 /** 020 * Constructor. 021 * 022 * <P>The feature name is used to generate names for many different items that form 023 * part of the implementation. For example, the base name of "Jet Engine" (with the space) 024 * will be used to generate names such as : 025 * <ul> 026 * <li><tt>JetEngineAction.java</tt> - the Action class 027 * <li><tt>JetEngine.java</tt> - the Model Object 028 * <li><tt>fJetEngine</tt> - a field reference in the Action class 029 * <li>and so on... 030 * </ul> 031 * 032 * <P>The formatting of the name depends on the context in which it is used, and is mostly 033 * controlled by the {@link hirondelle.web4jtools.util.Functions} utility class. You can implement 034 * custom coding conventions by altering the implementation of <tt>Functions</tt>. 035 * 036 * <P>Warning : the text items in this class are modeled as <tt>String</tt>, not 037 * {@link hirondelle.web4j.security.SafeText}. If rendering this data in markup, it is 038 * strongly recommended that the text be escaped for special characters using <tt>w:safe()</tt>. 039 * 040 * @param aName for the feature, 2..50 characters, required 041 * @param aUiStyle denotes the style of user interaction, required 042 * @param aPackageName name of the package for generated items, 2..200 characters, valid package name, required 043 * @param aShowOperation either <tt>List</tt> or <tt>Fetch</tt>, optional. Used only with <tt>ActionTemplateShowAndApply</tt>. 044 * @param aApplyOperation one of <tt>Add</tt>, <tt>Change</tt>, or <tt>Delete</tt>, optional. Used only with <tt>ActionTemplateShowAndApply</tt>. 045 */ 046 public Feature(String aName, String aUiStyle, String aPackageName, String aShowOperation, String aApplyOperation) throws ModelCtorException { 047 fName = aName; 048 fUiStyle = Util.textHasContent(aUiStyle) ? UiStyle.valueOf(aUiStyle) : null; 049 fPackageName = aPackageName; 050 fShowOperation = Util.textHasContent(aShowOperation) ? ShowOperation.valueOf(aShowOperation) : null; 051 fApplyOperation = Util.textHasContent(aApplyOperation) ? ApplyOperation.valueOf(aApplyOperation) : null; 052 validateState(); 053 } 054 055 public String getName() { return fName; } 056 public UiStyle getUiStyle() { return fUiStyle; } 057 public String getPackageName() { return fPackageName; } 058 public ShowOperation getShowOperation() { return fShowOperation; } 059 public ApplyOperation getApplyOperation() { return fApplyOperation; } 060 061 /** Intended for debugging only. */ 062 @Override public String toString() { 063 return ModelUtil.toStringFor(this); 064 } 065 066 @Override public boolean equals( Object aThat ) { 067 Boolean result = ModelUtil.quickEquals(this, aThat); 068 if ( result == null ){ 069 Feature that = (Feature) aThat; 070 result = ModelUtil.equalsFor(this.getSignificantFields(), that.getSignificantFields()); 071 } 072 return result; 073 } 074 075 @Override public int hashCode() { 076 if ( fHashCode == 0 ) { 077 fHashCode = ModelUtil.hashCodeFor(getSignificantFields()); 078 } 079 return fHashCode; 080 } 081 082 // PRIVATE // 083 private final String fName; 084 private final UiStyle fUiStyle; 085 private final String fPackageName; 086 private final ShowOperation fShowOperation; 087 private final ApplyOperation fApplyOperation; 088 private int fHashCode; 089 090 private void validateState() throws ModelCtorException { 091 ModelCtorException ex = new ModelCtorException(); 092 if ( FAILS == Check.required(fName, Check.range(2,50))) { 093 ex.add("Feature Name is required, 2..50 chars."); 094 } 095 if ( FAILS == Check.required(fUiStyle) ) { 096 ex.add("UI Style is required."); 097 } 098 if ( FAILS == Check.required(fPackageName, Check.range(2,200))) { 099 ex.add("Package name is required, 2..200 characters."); 100 } 101 102 if ( fUiStyle == UiStyle.ListAndEdit ) { 103 if ( fShowOperation != null ) { 104 ex.add("Show Operation applies only if UI Style is Show and Apply"); 105 } 106 if ( fApplyOperation != null ) { 107 ex.add("Apply Operation applies only if UI Style is Show and Apply"); 108 } 109 } 110 111 if ( fUiStyle == UiStyle.ShowAndApply ){ 112 if ( fShowOperation == null ){ 113 ex.add("Please select a Show Operation."); 114 } 115 if ( fApplyOperation == null ){ 116 ex.add("Please select an Apply Operation."); 117 } 118 } 119 120 if ( ! ex.isEmpty() ) throw ex; 121 } 122 123 private Object[] getSignificantFields(){ 124 return new Object[]{fName, fUiStyle, fPackageName, fShowOperation, fApplyOperation}; 125 } 126 }