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 }