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.service;
8   
9   import java.util.Locale;
10  
11  import org.slf4j.Logger;
12  import org.slf4j.LoggerFactory;
13  
14  import com.octo.captcha.Captcha;
15  import com.octo.captcha.engine.CaptchaEngine;
16  import com.octo.captcha.service.captchastore.CaptchaStore;
17  
18  /***
19   * This is a base class for CaptchaService implementations. It implements the lyfe cycle stuff. It uses  : a
20   * CaptchaStore to store captcha during the life cycle, and a CaptchaEngine to build captchas. All concrete
21   * implementation (that uses a specific capthcaStore and captchaEngine) should provide a default non argument
22   * constructor (by subclassing this class, and calling the constructor of the abstract class)
23   *
24   * @author Marc-Antoine Garrigue mailto:mag@jcaptcha.net
25   */
26  public abstract class AbstractCaptchaService implements CaptchaService {
27  
28      protected CaptchaStore store;
29      protected CaptchaEngine engine;
30      protected Logger logger;
31  
32  
33      protected AbstractCaptchaService(CaptchaStore captchaStore,
34                                       CaptchaEngine captchaEngine) {
35          if (captchaEngine == null || captchaStore == null)
36              throw new IllegalArgumentException("Store or gimpy can't be null");
37          this.engine = captchaEngine;
38          this.store = captchaStore;
39          
40          logger = LoggerFactory.getLogger(this.getClass());
41          
42          logger.info("Init " + this.store.getClass().getName());
43          this.store.initAndStart();
44      }
45  
46  
47      /***
48       * Method to retrive the challenge corresponding to the given ticket from the store.
49       *
50       * @param ID the ticket provided by the buildCaptchaAndGetID method
51       * @return the challenge
52       * @throws CaptchaServiceException if the ticket is invalid
53       */
54      public Object getChallengeForID(String ID) throws CaptchaServiceException {
55          return this.getChallengeForID(ID, Locale.getDefault());
56      }
57  
58      /***
59       * Method to retrive the challenge corresponding to the given ticket.
60       *
61       * @param ID     ticket
62       * @param locale the desired localized capthca
63       * @return the localized challenge
64       * @throws CaptchaServiceException if the ticket is invalid
65       */
66      public Object getChallengeForID(String ID, Locale locale)
67              throws CaptchaServiceException {
68          Captcha captcha;
69          Object challenge;
70          //check if has capthca
71          if (!this.store.hasCaptcha(ID)) {
72              //if not generate and store
73              captcha = generateAndStoreCaptcha(locale, ID);
74          } else {
75              //else get it
76              captcha = this.store.getCaptcha(ID);
77              if (captcha == null) {
78                  captcha = generateAndStoreCaptcha(locale, ID);
79              } else {
80                  //if dirty
81                  if (captcha.hasGetChalengeBeenCalled().booleanValue()) {
82                      //get a new one and store it
83                      captcha = generateAndStoreCaptcha(locale, ID);
84                  } 
85                  //else nothing
86              }
87          }
88          challenge = getChallengeClone(captcha);
89          captcha.disposeChallenge();
90  
91          return challenge;
92      }
93  
94  
95      /***
96       * Method to retrive the question corresponding to the given ticket.
97       *
98       * @param ID     ticket
99       * @param locale the desired localized capthca
100      * @return the localized question
101      * @throws CaptchaServiceException if the ticket is invalid
102      */
103     public String getQuestionForID(String ID, Locale locale) throws CaptchaServiceException {
104         Captcha captcha;
105         //check if has capthca
106         if (!this.store.hasCaptcha(ID)) {
107             //if not generate it
108             captcha = generateAndStoreCaptcha(locale, ID);
109         } else {
110             captcha = this.store.getCaptcha(ID);
111             if (captcha == null) {
112                 captcha = generateAndStoreCaptcha(locale, ID);
113             }else if (locale != null) {
114                 Locale storedlocale = this.store.getLocale(ID);
115                 if (!locale.equals(storedlocale)) {
116                 captcha = generateAndStoreCaptcha(locale, ID);
117                 }
118             }
119 
120         }
121         return captcha.getQuestion();
122     }
123 
124     /***
125      * Method to retrive the question corresponding to the given ticket from the store.
126      *
127      * @param ID the ticket provided by the buildCaptchaAndGetID method
128      * @return the question
129      * @throws CaptchaServiceException if the ticket is invalid
130      */
131     public String getQuestionForID(String ID) throws CaptchaServiceException {
132         return this.getQuestionForID(ID, Locale.getDefault());
133     }
134 
135     /***
136      * Method to validate a response to the challenge corresponding to the given ticket and remove the coresponding
137      * captcha from the store.
138      *
139      * @param ID the ticket provided by the buildCaptchaAndGetID method
140      * @return true if the response is correct, false otherwise.
141      * @throws CaptchaServiceException if the ticket is invalid
142      */
143     public Boolean validateResponseForID(String ID, Object response)
144             throws CaptchaServiceException {
145         if (!store.hasCaptcha(ID)) {
146             throw new CaptchaServiceException("Invalid ID, could not validate unexisting or already validated captcha");
147         } else {
148             Boolean valid = store.getCaptcha(ID).validateResponse(response);
149             store.removeCaptcha(ID);
150             return valid;
151         }
152     }
153 
154 
155     protected Captcha generateAndStoreCaptcha(Locale locale, String ID) {
156         Captcha captcha = engine.getNextCaptcha(locale);
157         this.store.storeCaptcha(ID, captcha, locale);
158         return captcha;
159     }
160 
161 
162     /***
163      * This method must be implemented by sublcasses and : Retrieve the challenge from the captcha Make and return a
164      * clone of the challenge Return the clone It has be design in order to let the service dispose the challenge of the
165      * captcha after rendering. It should be implemented for all captcha type (@see ImageCaptchaService implementations
166      * for exemple)
167      *
168      * @return a Challenge Clone
169      */
170     protected abstract Object getChallengeClone(Captcha captcha);
171 
172 
173 }