001 package hirondelle.fish.test.doubles; 002 003 import java.sql.SQLException; 004 import hirondelle.web4j.database.DAOException; 005 import hirondelle.web4j.database.DuplicateException; 006 import hirondelle.web4j.util.Util; 007 008 /** 009 Change the exception behavior of fake DAOs. 010 One of the advantages of using fake DAOs is that they can be made to 011 throw specific exceptions when desired. 012 By default, fake DAO operations will always succeed, in the sense of not throwing 013 an explicit exception. 014 015 <P>You control the behavior of a fake DAO using these methods : 016 <ul> 017 <li>call {@link #setBehavior(DbOperation, DbOperationResult)} to specify the desired behavior 018 for a given operation. If you don't call this method, then by default the fake DAO operation 019 will succeed. 020 <li>call {@link #possiblyThrowExceptionFor(DbOperation)} on the first line of your fake 021 DAO method. If the operation has been set to fail, then an exception will be thrown. 022 If not, then the operation will complete successfully. 023 </ul> 024 025 <P>For an illustration, see {@link hirondelle.fish.main.member.MemberDAOFake} and 026 {@link hirondelle.fish.main.member.TESTMemberDAO}. 027 028 <P><b>Implementation Note</b><br> 029 This class uses simple <tt>System</tt> properties to store the desired behavior. Such an implementation 030 is suitable only for a single threaded environment. 031 */ 032 public final class FakeDAOBehavior { 033 034 /** 035 Name of a <tt>System</tt> property used to swap implementations 036 between real and fake DAOs. When the property has the value <tt>true</tt>, 037 then fake DAOs are used. See 038 {@link hirondelle.fish.main.member.MemberDAOFake} for an illustration. 039 040 Value - {@value}. 041 */ 042 public static final String USE_FAKE_DAOS = "useFakeDAOs"; 043 044 /** 045 Enumeration of the basic DAO operations. 046 */ 047 public static enum DbOperation { 048 Add("FakeDAOAdd"), 049 Change("FakeDAOChange"), 050 Delete("FakeDAODelete"), 051 FetchForChange("FakeDAOFetchForChange"), 052 List("FakeDAOList"); 053 public String toString(){ 054 return fName; 055 } 056 private DbOperation(String aName){ 057 fName = aName; 058 } 059 private String fName; 060 } 061 062 /** Enumeration of how a basic DAO operation may succeed or fail. */ 063 public static enum DbOperationResult {Succeed, ThrowDAOException, ThrowDuplicateException} 064 065 /** 066 Possibly throw an exception for the given operation. 067 068 <P>An exception is thrown only if it has been indicated by calling 069 {@link #setBehavior(DbOperation, DbOperationResult)}. 070 */ 071 public static void possiblyThrowExceptionFor(DbOperation aOperation) throws DAOException, DuplicateException { 072 DbOperationResult opResult = getOperationResult(aOperation); 073 if (FakeDAOBehavior.DbOperationResult.Succeed == opResult) return; 074 if (FakeDAOBehavior.DbOperationResult.ThrowDAOException == opResult) throw new DAOException(FORCED_FAILURE, FORCED_EXCEPTION); 075 if (FakeDAOBehavior.DbOperationResult.ThrowDuplicateException == opResult) throw new DuplicateException(FORCED_FAILURE, FORCED_EXCEPTION); 076 } 077 078 /** Set the desired behavior of a fake DAO operation. */ 079 public static void setBehavior(DbOperation aDbOperation, DbOperationResult aDbOperationResult){ 080 System.setProperty(aDbOperation.toString(), aDbOperationResult.toString() ); 081 } 082 083 // PRIVATE // 084 private static final String FORCED_FAILURE = "Forced failure in fake DAO."; 085 private static final Throwable FORCED_EXCEPTION = new SQLException(FORCED_FAILURE); 086 087 private static DbOperationResult getOperationResult(DbOperation aOperation){ 088 DbOperationResult result = DbOperationResult.Succeed; //default value, if absent 089 String property = System.getProperty(aOperation.toString()); 090 if ( Util.textHasContent(property)) { 091 result = DbOperationResult.valueOf(property); 092 } 093 return result; 094 } 095 }