1
0
mirror of https://github.com/Rogiel/httpchannel synced 2025-12-06 07:32:50 +00:00

Implements CaptchaTrader service

This commit is contained in:
2012-01-17 12:28:22 -02:00
parent e943b08ede
commit 08d22a12fe
81 changed files with 2750 additions and 543 deletions

View File

@@ -9,25 +9,45 @@ package com.rogiel.httpchannel.captcha;
*/
public interface Captcha {
/**
* Sets the captcha answer
*
* @return the captcha ID
*/
String getID();
/**
* @return the resolved captcha answer
*/
String getAnswer();
/**
* @param answer
* the captcha answer
*/
void setAnswer(String answer);
/**
* Returns the captcha answer. <code>null</code> if the service was not able
* to resolve it automatically. In such case, {@link #setAnswer(String)}
* must be used to set the correct answer.
*
* @return the captcha answer
* @return <code>true</code> if the captcha was resolved and
* {@link #getAnswer()} will not return <code>null</code>.
*/
String getAnswer();
boolean isResolved();
/**
* @return <code>true</code> if, and only if, the service was able to
* automatically resolve the captcha result
* Get this CAPTCHA's attachment.
* <p>
* <b>Important note</b>: Attachments are for {@link CaptchaService}
* implementations usage! You should not touch any of the attachments!
*
* @return the attachment
*/
boolean wasAutomaticallyResolved();
Object getAttachment();
/**
* Sets this CAPTCHA's attachment.
* <p>
* <b>Important note</b>: Attachments are for {@link CaptchaService}
* implementations usage! You should not touch any of the attachments!
*
* @param attachment
* the attachment
*/
void setAttachment(Object attachment);
}

View File

@@ -1,19 +0,0 @@
/**
*
*/
package com.rogiel.httpchannel.captcha;
/**
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public interface CaptchaResolver {
/**
* Tries to resolve the captcha
*
* @param captcha
* the captcha
* @return <code>true</code> if the captcha was resolve, <code>false</code>
* to abort
*/
boolean resolve(Captcha captcha);
}

View File

@@ -3,9 +3,52 @@
*/
package com.rogiel.httpchannel.captcha;
import com.rogiel.httpchannel.captcha.exception.AuthenticationCaptchaServiceException;
import com.rogiel.httpchannel.captcha.exception.InvalidCaptchaServiceException;
import com.rogiel.httpchannel.captcha.exception.UnsolvableCaptchaServiceException;
/**
* @author <a href="http://www.rogiel.com">Rogiel</a>
*
*/
public interface CaptchaService<C extends Captcha> {
/**
* Authenticates the service instance into the CAPTCHA solving server, if
* any. Implementations that do not use authentication, should do nothing
* and return <code>-1</code>
*
* @param username
* @param password
* @return amount of remaining CAPTCHA solving, <code>-1</code> if no limit
* is applied
*/
int authenticate(String username, String password)
throws AuthenticationCaptchaServiceException;
/**
* Tries to resolve the captcha and returns the correct answer.
*
* @param captcha
* @throws UnsolvableCaptchaServiceException
* if the CAPTCHA could not be solved by the service
*/
void solve(C captcha) throws UnsolvableCaptchaServiceException;
/**
* Notifies the service that the given captcha answer was correct
*
* @param captcha
* the captcha
* @throws InvalidCaptchaServiceException
* normally thrown if the CAPTCHA was not solved by this service
*/
void valid(C captcha) throws InvalidCaptchaServiceException;
/**
* Notifies the service that the given captcha answer was incorrect
*
* @param captcha
* @throws InvalidCaptchaServiceException
* normally thrown if the CAPTCHA was not solved by this service
*/
void invalid(C captcha) throws InvalidCaptchaServiceException;
}

View File

@@ -9,14 +9,66 @@ import java.net.URL;
* @author <a href="http://www.rogiel.com">Rogiel</a>
*
*/
public interface ImageCaptcha extends Captcha {
public class ImageCaptcha implements Captcha {
/**
* @return the captcha identifier
* The CAPTCHA ID
*/
String getID();
private final String ID;
/**
* The CAPTCHA Image {@link URL}
*/
private final URL imageURL;
/**
* The CAPTCHA answer
*/
private String answer;
/**
* The CAPTCHA attachment
*/
private Object attachment;
/**
* @return the captcha image {@link URL}
*/
URL getImageURL();
public ImageCaptcha(String id, URL imageURL) {
this.ID = id;
this.imageURL = imageURL;
}
@Override
public String getID() {
return ID;
}
public URL getImageURL() {
return imageURL;
}
@Override
public String getAnswer() {
return answer;
}
@Override
public void setAnswer(String answer) {
this.answer = answer;
}
@Override
public boolean isResolved() {
return answer != null;
}
@Override
public Object getAttachment() {
return attachment;
}
@Override
public void setAttachment(Object attachment) {
this.attachment = attachment;
}
@Override
public String toString() {
return "ImageCaptcha [ID=" + ID + ", imageURL=" + imageURL
+ ", answer=" + answer + ", attachment=" + attachment + "]";
}
}

View File

@@ -3,32 +3,10 @@
*/
package com.rogiel.httpchannel.captcha;
import java.net.MalformedURLException;
import java.net.URL;
/**
* @author <a href="http://www.rogiel.com">Rogiel</a>
*
*/
public interface ImageCaptchaService<C extends ImageCaptcha> extends
CaptchaService<C> {
/**
* Creates a new captcha from the given HTML content
*
* @param image
* the image {@link URL}
* @return a new captcha
* @throws MalformedURLException
* if any error occur while creating the Image {@link URL}
*/
C create(String html) throws MalformedURLException;
public interface ImageCaptchaService extends CaptchaService<ImageCaptcha> {
/**
* Tries to automatically resolve the captcha
*
* @param captcha
* the captcha to be resolved
* @return <code>true</code> if the captcha was successfully resolved
*/
boolean resolve(C captcha);
}

View File

@@ -0,0 +1,49 @@
/**
*
*/
package com.rogiel.httpchannel.captcha.exception;
/**
* @author <a href="http://www.rogiel.com">Rogiel</a>
*
*/
public class AuthenticationCaptchaServiceException extends CaptchaServiceException {
/**
* The Java Serialization API ID
*/
private static final long serialVersionUID = 1L;
/**
* Creates a new instance
*/
public AuthenticationCaptchaServiceException() {
}
/**
* @param message
* the message
* @param cause
* the cause
*/
public AuthenticationCaptchaServiceException(String message, Throwable cause) {
super(message, cause);
}
/**
* @param message
* the message
*/
public AuthenticationCaptchaServiceException(String message) {
super(message);
}
/**
* @param cause
* the cause
*/
public AuthenticationCaptchaServiceException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,50 @@
/**
*
*/
package com.rogiel.httpchannel.captcha.exception;
import com.rogiel.httpchannel.service.exception.ChannelServiceException;
/**
* @author <a href="http://www.rogiel.com">Rogiel</a>
*
*/
public class CaptchaServiceException extends ChannelServiceException {
/**
* The Java Serialization API ID
*/
private static final long serialVersionUID = 1L;
/**
* Creates a new instance
*/
public CaptchaServiceException() {
}
/**
* @param message
* the message
* @param cause
* the cause
*/
public CaptchaServiceException(String message, Throwable cause) {
super(message, cause);
}
/**
* @param message
* the message
*/
public CaptchaServiceException(String message) {
super(message);
}
/**
* @param cause
* the cause
*/
public CaptchaServiceException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,49 @@
/**
*
*/
package com.rogiel.httpchannel.captcha.exception;
/**
* @author <a href="http://www.rogiel.com">Rogiel</a>
*
*/
public class InvalidCaptchaServiceException extends CaptchaServiceException {
/**
* The Java Serialization API ID
*/
private static final long serialVersionUID = 1L;
/**
* Creates a new instance
*/
public InvalidCaptchaServiceException() {
}
/**
* @param message
* the message
* @param cause
* the cause
*/
public InvalidCaptchaServiceException(String message, Throwable cause) {
super(message, cause);
}
/**
* @param message
* the message
*/
public InvalidCaptchaServiceException(String message) {
super(message);
}
/**
* @param cause
* the cause
*/
public InvalidCaptchaServiceException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,49 @@
/**
*
*/
package com.rogiel.httpchannel.captcha.exception;
/**
* @author <a href="http://www.rogiel.com">Rogiel</a>
*
*/
public class UnsolvableCaptchaServiceException extends CaptchaServiceException {
/**
* The Java Serialization API ID
*/
private static final long serialVersionUID = 1L;
/**
* Creates a new instance
*/
public UnsolvableCaptchaServiceException() {
}
/**
* @param message
* the message
* @param cause
* the cause
*/
public UnsolvableCaptchaServiceException(String message, Throwable cause) {
super(message, cause);
}
/**
* @param message
* the message
*/
public UnsolvableCaptchaServiceException(String message) {
super(message);
}
/**
* @param cause
* the cause
*/
public UnsolvableCaptchaServiceException(Throwable cause) {
super(cause);
}
}

View File

@@ -16,9 +16,13 @@
*/
package com.rogiel.httpchannel.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.rogiel.httpchannel.captcha.Captcha;
import com.rogiel.httpchannel.captcha.CaptchaResolver;
import com.rogiel.httpchannel.service.exception.UnresolvedCaptchaException;
import com.rogiel.httpchannel.captcha.CaptchaService;
import com.rogiel.httpchannel.captcha.exception.UnsolvableCaptchaServiceException;
import com.rogiel.httpchannel.service.exception.NoCaptchaServiceException;
/**
* This is an abstract {@link Service} implementation.
@@ -27,7 +31,11 @@ import com.rogiel.httpchannel.service.exception.UnresolvedCaptchaException;
* @version 1.0
*/
public abstract class AbstractService implements Service {
protected CaptchaResolver captchaResolver;
/**
* The service {@link Logger} instance
*/
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
protected CaptchaService<Captcha> captchaService;
@Override
public Service clone() {
@@ -39,17 +47,17 @@ public abstract class AbstractService implements Service {
}
@Override
public void setCaptchaResolver(CaptchaResolver captchaResolver) {
this.captchaResolver = captchaResolver;
@SuppressWarnings("unchecked")
public void setCaptchaService(
CaptchaService<? extends Captcha> captchaService) {
this.captchaService = (CaptchaService<Captcha>) captchaService;
}
protected void resolveCaptcha(Captcha captcha)
throws UnresolvedCaptchaException {
if (captchaResolver == null)
throw new UnresolvedCaptchaException();
if (!captchaResolver.resolve(captcha))
throw new UnresolvedCaptchaException();
if (captcha.getAnswer() == null)
throw new UnresolvedCaptchaException();
throws NoCaptchaServiceException, UnsolvableCaptchaServiceException {
if (captchaService == null)
throw new NoCaptchaServiceException(
"No CaptchaService is configured");
captchaService.solve((Captcha) captcha);
}
}

View File

@@ -18,10 +18,11 @@ package com.rogiel.httpchannel.service;
import java.io.IOException;
import com.rogiel.httpchannel.captcha.CaptchaResolver;
import com.rogiel.httpchannel.captcha.CaptchaService;
import com.rogiel.httpchannel.captcha.exception.UnsolvableCaptchaServiceException;
import com.rogiel.httpchannel.service.Authenticator.AuthenticatorConfiguration;
import com.rogiel.httpchannel.service.exception.AuthenticationInvalidCredentialException;
import com.rogiel.httpchannel.service.exception.UnresolvedCaptchaException;
import com.rogiel.httpchannel.service.exception.NoCaptchaServiceException;
/**
* This interfaces provides authentication for an service.
@@ -40,13 +41,16 @@ public interface Authenticator<C extends AuthenticatorConfiguration> {
* if any IO error occur
* @throws AuthenticationInvalidCredentialException
* if the credentials are not valid or cannot be used
* @throws UnresolvedCaptchaException
* @throws UnsolvableCaptchaServiceException
* if the service required captcha resolving but no
* {@link CaptchaResolver} was available or the resolver did not
* {@link CaptchaService} was available or the service did not
* solve the challenge
* @throws NoCaptchaServiceException
* if the service required an {@link CaptchaService}
* implementation to be present, but none was available
*/
void login() throws IOException, AuthenticationInvalidCredentialException,
UnresolvedCaptchaException;
UnsolvableCaptchaServiceException, NoCaptchaServiceException;
/**
* Logout into the {@link Service}. The session is restored to an not

View File

@@ -32,13 +32,4 @@ import java.nio.channels.ReadableByteChannel;
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public interface DownloadChannel extends HttpChannel, ReadableByteChannel {
/**
* @return the file size
*/
long getFilesize();
/**
* @return the file name
*/
String getFilename();
}

View File

@@ -18,13 +18,14 @@ package com.rogiel.httpchannel.service;
import java.io.IOException;
import com.rogiel.httpchannel.captcha.CaptchaResolver;
import com.rogiel.httpchannel.captcha.CaptchaService;
import com.rogiel.httpchannel.captcha.exception.UnsolvableCaptchaServiceException;
import com.rogiel.httpchannel.service.Downloader.DownloaderConfiguration;
import com.rogiel.httpchannel.service.exception.DownloadLimitExceededException;
import com.rogiel.httpchannel.service.exception.DownloadLinkNotFoundException;
import com.rogiel.httpchannel.service.exception.DownloadNotAuthorizedException;
import com.rogiel.httpchannel.service.exception.DownloadNotResumableException;
import com.rogiel.httpchannel.service.exception.UnresolvedCaptchaException;
import com.rogiel.httpchannel.service.exception.NoCaptchaServiceException;
/**
* This interfaces provides downloading for an service.
@@ -42,7 +43,8 @@ public interface Downloader<C extends DownloaderConfiguration> {
* very unlikely to be done. The most common usage usage scenario for this
* is when an {@link DownloadNotResumableException} is thrown and you wish
* to restart the download from start giving <tt>position</tt> equal to
* zero.
* zero, in such scenario, reutilizing the same {@link Downloader} instance
* is safe.
* <p>
* Please remember to close the channel by calling
* {@link DownloadChannel#close()}, otherwise some of the resources (such as
@@ -70,15 +72,19 @@ public interface Downloader<C extends DownloaderConfiguration> {
* @throws DownloadNotResumableException
* if the download cannot be started at <tt>position</tt>. Will
* only be thrown if <tt>position > 0</tt>.
* @throws UnresolvedCaptchaException
* @throws UnsolvableCaptchaServiceException
* if the service required captcha resolving but no
* {@link CaptchaResolver} was available or the resolver did not
* {@link CaptchaService} was available or the service did not
* solve the challenge
* @throws NoCaptchaServiceException
* if the service required an {@link CaptchaService}
* implementation to be present, but none was available
*/
DownloadChannel openChannel(DownloadListener listener, long position)
throws IOException, DownloadLinkNotFoundException,
DownloadLimitExceededException, DownloadNotAuthorizedException,
DownloadNotResumableException, UnresolvedCaptchaException;
DownloadNotResumableException, UnsolvableCaptchaServiceException,
NoCaptchaServiceException;
/**
* Opens a new {@link DownloadChannel} with not listener. For more details,
@@ -102,14 +108,26 @@ public interface Downloader<C extends DownloaderConfiguration> {
* @throws DownloadNotResumableException
* if the download cannot be started at <tt>position</tt>. Will
* only be thrown if <tt>position > 0</tt>.
* @throws UnsolvableCaptchaServiceException
* if the service required captcha resolving but no
* {@link CaptchaService} was available or the service did not
* solve the challenge
* @throws NoCaptchaServiceException
* if the service required an {@link CaptchaService}
* implementation to be present, but none was available
*
*/
DownloadChannel openChannel(long position) throws IOException,
DownloadLinkNotFoundException, DownloadLimitExceededException,
DownloadNotAuthorizedException, DownloadNotResumableException;
DownloadNotAuthorizedException, DownloadNotResumableException,
UnsolvableCaptchaServiceException, NoCaptchaServiceException;
/**
* Opens a new {@link DownloadChannel} positioned at start. For more
* details, see {@link #openChannel(DownloadListener, long)}
* <p>
* Note that {@link DownloadNotResumableException} is never thrown because
* this channel always starts at <code>0</code> offset.
*
* @param listener
* the listener to keep a track on the download progress
@@ -125,14 +143,25 @@ public interface Downloader<C extends DownloaderConfiguration> {
* @throws DownloadNotAuthorizedException
* if the user (or guest) account does not have necessary rights
* to download the file
* @throws UnsolvableCaptchaServiceException
* if the service required captcha resolving but no
* {@link CaptchaService} was available or the service did not
* solve the challenge
* @throws NoCaptchaServiceException
* if the service required an {@link CaptchaService}
* implementation to be present, but none was available
*/
DownloadChannel openChannel(DownloadListener listener) throws IOException,
DownloadLinkNotFoundException, DownloadLimitExceededException,
DownloadNotAuthorizedException;
DownloadNotAuthorizedException, UnsolvableCaptchaServiceException,
NoCaptchaServiceException;
/**
* Opens a new {@link DownloadChannel} with not listener and positioned at
* start. For more details, see {@link #openChannel(DownloadListener, long)}
* <p>
* Note that {@link DownloadNotResumableException} is never thrown because
* this channel always starts at <code>0</code> offset.
*
* @return the {@link DownloadChannel} instance
* @throws IOException
@@ -146,10 +175,18 @@ public interface Downloader<C extends DownloaderConfiguration> {
* @throws DownloadNotAuthorizedException
* if the user (or guest) account does not have necessary rights
* to download the file
* @throws UnsolvableCaptchaServiceException
* if the service required captcha resolving but no
* {@link CaptchaService} was available or the service did not
* solve the challenge
* @throws NoCaptchaServiceException
* if the service required an {@link CaptchaService}
* implementation to be present, but none was available
*/
DownloadChannel openChannel() throws IOException,
DownloadLinkNotFoundException, DownloadLimitExceededException,
DownloadNotAuthorizedException;
DownloadNotAuthorizedException, UnsolvableCaptchaServiceException,
NoCaptchaServiceException;
/**
* Returns this {@link Downloader} configuration.

View File

@@ -0,0 +1,23 @@
/**
*
*/
package com.rogiel.httpchannel.service;
import java.io.Closeable;
import java.nio.channels.Channel;
/**
* @author <a href="http://www.rogiel.com">Rogiel</a>
*
*/
public interface HttpChannel extends Channel, Closeable {
/**
* @return the file size
*/
long getFilesize();
/**
* @return the file name
*/
String getFilename();
}

View File

@@ -16,7 +16,8 @@
*/
package com.rogiel.httpchannel.service;
import com.rogiel.httpchannel.captcha.CaptchaResolver;
import com.rogiel.httpchannel.captcha.Captcha;
import com.rogiel.httpchannel.captcha.CaptchaService;
/**
* Base interface for all the services. Whenever the operation suported by the
@@ -53,13 +54,13 @@ public interface Service extends Cloneable {
int getMinorVersion();
/**
* Sets this service captcha resolver. Resolvers are safe to be switched
* Sets this service captcha service. CaptchaService are safe to be switched
* even after an transfer has begun.
*
* @param resolver
* the captcha resolver
* @param captchaService
* the captcha service
*/
void setCaptchaResolver(CaptchaResolver resolver);
void setCaptchaService(CaptchaService<? extends Captcha> captchaService);
/**
* @return a cloned version of this service

View File

@@ -36,16 +36,6 @@ import com.rogiel.httpchannel.service.exception.UploadLinkNotFoundException;
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public interface UploadChannel extends HttpChannel, WritableByteChannel {
/**
* @return the file size
*/
long getFilesize();
/**
* @return the file name
*/
String getFilename();
/**
* The link is located after you call {@link UploadChannel#close()}, but it
* can only be retrieved by calling this method. If {@link #close()} throwed

View File

@@ -18,9 +18,10 @@ package com.rogiel.httpchannel.service;
import java.io.IOException;
import com.rogiel.httpchannel.captcha.CaptchaResolver;
import com.rogiel.httpchannel.captcha.CaptchaService;
import com.rogiel.httpchannel.captcha.exception.UnsolvableCaptchaServiceException;
import com.rogiel.httpchannel.service.Uploader.UploaderConfiguration;
import com.rogiel.httpchannel.service.exception.UnresolvedCaptchaException;
import com.rogiel.httpchannel.service.exception.NoCaptchaServiceException;
/**
* This interfaces provides uploading for an service.
@@ -48,12 +49,16 @@ public interface Uploader<C extends UploaderConfiguration> {
* @return the {@link UploadChannel} instance
* @throws IOException
* if any IO error occur
* @throws UnresolvedCaptchaException
* @throws UnsolvableCaptchaServiceException
* if the service required captcha resolving but no
* {@link CaptchaResolver} was available or the resolver did not
* {@link CaptchaService} was available or the service did not
* solve the challenge
* @throws NoCaptchaServiceException
* if the service required an {@link CaptchaService}
* implementation to be present, but none was available
*/
UploadChannel openChannel() throws IOException, UnresolvedCaptchaException;
UploadChannel openChannel() throws IOException,
UnsolvableCaptchaServiceException, NoCaptchaServiceException;
/**
* Returns this {@link Uploader} configuration.

View File

@@ -16,10 +16,10 @@
*/
package com.rogiel.httpchannel.service.exception;
import com.rogiel.httpchannel.captcha.CaptchaResolver;
import com.rogiel.httpchannel.captcha.CaptchaService;
/**
* Exception thrown if the {@link CaptchaResolver} has returned an invalid
* Exception thrown if the {@link CaptchaService} has returned an invalid
* captcha
*
* @author <a href="http://www.rogiel.com">Rogiel</a>

View File

@@ -16,21 +16,21 @@
*/
package com.rogiel.httpchannel.service.exception;
import com.rogiel.httpchannel.captcha.CaptchaResolver;
import com.rogiel.httpchannel.captcha.CaptchaService;
/**
* Exception thrown if the {@link CaptchaResolver} has returned an invalid
* Exception thrown if the {@link CaptchaService} has returned an invalid
* captcha
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class UnresolvedCaptchaException extends ChannelServiceException {
public class NoCaptchaServiceException extends ChannelServiceException {
private static final long serialVersionUID = 1L;
/**
* Creates a new empty instance of this exception
*/
public UnresolvedCaptchaException() {
public NoCaptchaServiceException() {
super();
}
@@ -40,7 +40,7 @@ public class UnresolvedCaptchaException extends ChannelServiceException {
* @param cause
* the root cause
*/
public UnresolvedCaptchaException(String message, Throwable cause) {
public NoCaptchaServiceException(String message, Throwable cause) {
super(message, cause);
}
@@ -48,7 +48,7 @@ public class UnresolvedCaptchaException extends ChannelServiceException {
* @param message
* the message
*/
public UnresolvedCaptchaException(String message) {
public NoCaptchaServiceException(String message) {
super(message);
}
@@ -56,7 +56,7 @@ public class UnresolvedCaptchaException extends ChannelServiceException {
* @param cause
* the root cause
*/
public UnresolvedCaptchaException(Throwable cause) {
public NoCaptchaServiceException(Throwable cause) {
super(cause);
}
}