package er.captcha;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import javax.imageio.ImageIO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.octo.captcha.engine.CaptchaEngine;
import com.octo.captcha.service.CaptchaServiceException;
import com.octo.captcha.service.captchastore.FastHashMapCaptchaStore;
import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;
import com.octo.captcha.service.image.ImageCaptchaService;
import com.webobjects.appserver.WOActionResults;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WORequest;
import com.webobjects.appserver.WOResponse;
import com.webobjects.foundation.NSData;
import er.extensions.foundation.ERXProperties;
/**
* <span class="en">
* ERCaptcha presents a captcha image to the use along with a text field for the user to identify the image.
*
* @binding validated returns whether or not the user properly validated the image
* @binding resetText if set, a submit button will be added with this text that resets the image
*
* @property er.captcha.captchaEngineClass the class name of the CaptchaEngine to use
* </span>
*
* <span class="ja">
* ERCaptcha は JCaptcha ( http://jcaptcha.sourceforge.net/ ) ライブラリーの上に位置します。
* ダイナミック・イメージ生成の為に、 AWT クラスを使用している為アプリケーションを配布時で -Djava.awt.headless=true として実行する必要があります。
* ERCaptcha はキャプチャ・イメージと確認用のユーザが使用できるテキスト・フィールドを表現します。
*
* @binding validated - ユーザがイメージを有効で認識できたかどうかを戻します。
* @binding resetText - セットされている場合には、イメージをリセットする為のサブミット・ボタンが表示されます。
*
* @property er.captcha.captchaEngineClass - 使用する CaptchaEngine のクラス名
* </span>
* @author mschrag
*/
public class ERCaptcha extends WOComponent {
/**
* Do I need to update serialVersionUID?
* See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the
* <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a>
*/
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(ERCaptcha.class);
private static ImageCaptchaService _captchaService;
private NSData _captcha;
private String _response;
public static ImageCaptchaService captchaService() {
try {
if (_captchaService == null) {
String captchaEngineClass = ERXProperties.stringForKeyWithDefault("er.captcha.captchaEngineClass", ERCaptchaEngine.class.getName());
CaptchaEngine captchaEngine = (CaptchaEngine) Class.forName(captchaEngineClass).newInstance();
_captchaService = new DefaultManageableImageCaptchaService(new FastHashMapCaptchaStore(), captchaEngine, 180, 100000, 75000);
}
return _captchaService;
}
catch (Throwable t) {
throw new RuntimeException("Failed to initialize captcha engine.", t);
}
}
public ERCaptcha(WOContext context) {
super(context);
}
@Override
public boolean synchronizesVariablesWithBindings() {
return false;
}
public void setCaptcha(NSData captcha) {
_captcha = captcha;
}
public NSData captcha() {
return _captcha;
}
public String mimeType() {
return "image/jpeg";
}
public void setResponse(String response) {
_response = response;
}
public String response() {
return _response;
}
@Override
public void takeValuesFromRequest(WORequest request, WOContext context) {
super.takeValuesFromRequest(request, context);
if (context.wasFormSubmitted()) {
Boolean validated = Boolean.FALSE;
try {
validated = ERCaptcha.captchaService().validateResponseForID(context.elementID(), _response);
}
catch (CaptchaServiceException e) {
log.error("Captcha service failed.", e);
}
finally {
_captcha = null;
}
setValueForBinding(validated, "validated");
}
}
@Override
public void appendToResponse(WOResponse response, WOContext context) {
if (_captcha == null) {
try {
BufferedImage challenge = ERCaptcha.captchaService().getImageChallengeForID(context.elementID());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(challenge, "jpg", baos);
_captcha = new NSData(baos.toByteArray());
} catch (Throwable e) {
log.error("Failed to create JPEG for Captcha.", e);
}
}
super.appendToResponse(response, context);
}
public WOActionResults resetCaptcha() {
_captcha = null;
return null;
}
}