View Javadoc

1   /*
2    * JCaptcha, the open source java framework for captcha definition and integration
3    * Copyright (c)  2007 jcaptcha.net. All Rights Reserved.
4    * See the LICENSE.txt file distributed with this package.
5    */
6   
7   package com.octo.captcha.image;
8   
9   import com.octo.captcha.Captcha;
10  
11  
12  import javax.imageio.ImageIO;
13  import javax.imageio.stream.MemoryCacheImageInputStream;
14  import javax.imageio.stream.MemoryCacheImageOutputStream;
15  import java.awt.image.BufferedImage;
16  import java.io.IOException;
17  
18  /***
19   * <p>String question about a BufferedImage challenge. Abstract.</p>
20   *
21   * @author <a href="mailto:mag@jcaptcha.net">Marc-Antoine Garrigue</a>
22   * @version 1.0
23   */
24  public abstract class ImageCaptcha implements Captcha {
25  
26      private Boolean hasChallengeBeenCalled = Boolean.FALSE;
27  
28      protected String question;
29  
30      protected transient BufferedImage challenge;
31  
32      protected ImageCaptcha(String question, BufferedImage challenge) {
33          this.challenge = challenge;
34          this.question = question;
35      }
36  
37      /***
38       * Accessor captcha question
39       *
40       * @return the question
41       */
42      public final String getQuestion() {
43          return question;
44      }
45  
46      /***
47       * @return the challenge
48       */
49      public final Object getChallenge() {
50          return getImageChallenge();
51      }
52  
53      /***
54       * @return the image challenge
55       */
56      public final BufferedImage getImageChallenge() {
57          hasChallengeBeenCalled = Boolean.TRUE;
58          return challenge;
59      }
60  
61  
62      /***
63       * Dispose the challenge, once this method is call the getChallenge method will return null.<br> It has been added
64       * for technical reasons : a captcha is always used in a two step fashion<br> First submit the challenge, and then
65       * wait until the response arrives.<br> It had been asked to have a method to dispose the challenge that is no
66       * longer used after being dipslayed. So here it is!
67       */
68      public final void disposeChallenge() {
69          this.challenge = null;
70      }
71  
72      /***
73       * This method should return true if the getChalenge method has been called (has been added in order to properly
74       * manage the captcha state.
75       *
76       * @return true if getChallenge has been called false otherwise.
77       */
78      public Boolean hasGetChalengeBeenCalled() {
79          return hasChallengeBeenCalled;
80      }
81  
82      /***
83       * This method have to be implemented in order to serialize the image challenge to JPEG format
84       * @param out The target outputStream in which the captcha will be serialized
85       * @throws IOException
86       */
87      private void writeObject(java.io.ObjectOutputStream out)
88              throws IOException {
89  
90          // Serialize captcha fields with defaut method
91          out.defaultWriteObject();
92  
93          // If the challenge has not been disposed
94          if (this.challenge != null) {
95              // use png encoding
96              ImageIO.write(this.challenge, "png", new MemoryCacheImageOutputStream(out));
97          }
98      }
99  
100     /***
101      * This method have to be implemented in order to unserialize the image challenge from JPEG format
102      * @param in The source inputStream from which the captcha will be unserialized
103      * @throws IOException
104      * @throws ClassNotFoundException
105      */
106     private void readObject(java.io.ObjectInputStream in)
107             throws IOException, ClassNotFoundException {
108 
109         // UnSerialize captcha fields with default method
110         in.defaultReadObject();
111         
112         try {
113 
114             this.challenge =ImageIO.read(new MemoryCacheImageInputStream(in));
115         } catch (IOException e) {
116             if (!hasChallengeBeenCalled.booleanValue()) {
117                 // If the getChallenge method has not been called the challenge should be available for unmarhslling.
118                 // In this case, the thrown Exception is not related to the dispose status 
119                 throw e;
120             }
121         }
122     }
123 }