diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/Captcha.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/Captcha.java
index 2ce6aa4..cb12d5a 100644
--- a/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/Captcha.java
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/Captcha.java
@@ -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. null 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 true if the captcha was resolved and
+ * {@link #getAnswer()} will not return null.
*/
- String getAnswer();
+ boolean isResolved();
/**
- * @return true if, and only if, the service was able to
- * automatically resolve the captcha result
+ * Get this CAPTCHA's attachment.
+ *
+ * Important note: 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.
+ *
+ * Important note: Attachments are for {@link CaptchaService}
+ * implementations usage! You should not touch any of the attachments!
+ *
+ * @param attachment
+ * the attachment
+ */
+ void setAttachment(Object attachment);
}
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/CaptchaResolver.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/CaptchaResolver.java
deleted file mode 100644
index 60141e4..0000000
--- a/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/CaptchaResolver.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- *
- */
-package com.rogiel.httpchannel.captcha;
-
-/**
- * @author Rogiel
- */
-public interface CaptchaResolver {
- /**
- * Tries to resolve the captcha
- *
- * @param captcha
- * the captcha
- * @return true if the captcha was resolve, false
- * to abort
- */
- boolean resolve(Captcha captcha);
-}
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/CaptchaService.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/CaptchaService.java
index 6ec0439..d9ff0ed 100644
--- a/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/CaptchaService.java
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/CaptchaService.java
@@ -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 Rogiel
- *
*/
public interface CaptchaService {
+ /**
+ * Authenticates the service instance into the CAPTCHA solving server, if
+ * any. Implementations that do not use authentication, should do nothing
+ * and return -1
+ *
+ * @param username
+ * @param password
+ * @return amount of remaining CAPTCHA solving, -1 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;
}
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/ImageCaptcha.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/ImageCaptcha.java
index 6094cdc..375e947 100644
--- a/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/ImageCaptcha.java
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/ImageCaptcha.java
@@ -9,14 +9,66 @@ import java.net.URL;
* @author Rogiel
*
*/
-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 + "]";
+ }
}
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/ImageCaptchaService.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/ImageCaptchaService.java
index 9c497cd..7f07051 100644
--- a/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/ImageCaptchaService.java
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/ImageCaptchaService.java
@@ -3,32 +3,10 @@
*/
package com.rogiel.httpchannel.captcha;
-import java.net.MalformedURLException;
-import java.net.URL;
-
/**
* @author Rogiel
*
*/
-public interface ImageCaptchaService extends
- CaptchaService {
- /**
- * 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 {
- /**
- * Tries to automatically resolve the captcha
- *
- * @param captcha
- * the captcha to be resolved
- * @return true if the captcha was successfully resolved
- */
- boolean resolve(C captcha);
}
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/exception/AuthenticationCaptchaServiceException.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/exception/AuthenticationCaptchaServiceException.java
new file mode 100644
index 0000000..6db3f76
--- /dev/null
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/exception/AuthenticationCaptchaServiceException.java
@@ -0,0 +1,49 @@
+/**
+ *
+ */
+package com.rogiel.httpchannel.captcha.exception;
+
+
+/**
+ * @author Rogiel
+ *
+ */
+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);
+ }
+
+}
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/exception/CaptchaServiceException.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/exception/CaptchaServiceException.java
new file mode 100644
index 0000000..7b9a7ae
--- /dev/null
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/exception/CaptchaServiceException.java
@@ -0,0 +1,50 @@
+/**
+ *
+ */
+package com.rogiel.httpchannel.captcha.exception;
+
+import com.rogiel.httpchannel.service.exception.ChannelServiceException;
+
+/**
+ * @author Rogiel
+ *
+ */
+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);
+ }
+
+}
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/exception/InvalidCaptchaServiceException.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/exception/InvalidCaptchaServiceException.java
new file mode 100644
index 0000000..969e3f0
--- /dev/null
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/exception/InvalidCaptchaServiceException.java
@@ -0,0 +1,49 @@
+/**
+ *
+ */
+package com.rogiel.httpchannel.captcha.exception;
+
+
+/**
+ * @author Rogiel
+ *
+ */
+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);
+ }
+
+}
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/exception/UnsolvableCaptchaServiceException.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/exception/UnsolvableCaptchaServiceException.java
new file mode 100644
index 0000000..7cba7d9
--- /dev/null
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/exception/UnsolvableCaptchaServiceException.java
@@ -0,0 +1,49 @@
+/**
+ *
+ */
+package com.rogiel.httpchannel.captcha.exception;
+
+
+/**
+ * @author Rogiel
+ *
+ */
+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);
+ }
+
+}
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/AbstractService.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/AbstractService.java
index 90dbdaf..348401c 100644
--- a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/AbstractService.java
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/AbstractService.java
@@ -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 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) 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);
}
}
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/Authenticator.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/Authenticator.java
index 4bf92c2..38ce16b 100644
--- a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/Authenticator.java
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/Authenticator.java
@@ -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 {
* 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
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/DownloadChannel.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/DownloadChannel.java
index f53112b..f3791a4 100644
--- a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/DownloadChannel.java
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/DownloadChannel.java
@@ -32,13 +32,4 @@ import java.nio.channels.ReadableByteChannel;
* @author Rogiel
*/
public interface DownloadChannel extends HttpChannel, ReadableByteChannel {
- /**
- * @return the file size
- */
- long getFilesize();
-
- /**
- * @return the file name
- */
- String getFilename();
}
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/Downloader.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/Downloader.java
index b701c41..457eaf6 100644
--- a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/Downloader.java
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/Downloader.java
@@ -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 {
* 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 position equal to
- * zero.
+ * zero, in such scenario, reutilizing the same {@link Downloader} instance
+ * is safe.
*
* 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 {
* @throws DownloadNotResumableException
* if the download cannot be started at position. Will
* only be thrown if position > 0.
- * @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 {
* @throws DownloadNotResumableException
* if the download cannot be started at position. Will
* only be thrown if position > 0.
+ * @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)}
+ *
+ * Note that {@link DownloadNotResumableException} is never thrown because
+ * this channel always starts at 0 offset.
*
* @param listener
* the listener to keep a track on the download progress
@@ -125,14 +143,25 @@ public interface Downloader {
* @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)}
+ *
+ * Note that {@link DownloadNotResumableException} is never thrown because
+ * this channel always starts at 0 offset.
*
* @return the {@link DownloadChannel} instance
* @throws IOException
@@ -146,10 +175,18 @@ public interface Downloader {
* @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.
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/HttpChannel.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/HttpChannel.java
new file mode 100644
index 0000000..15e9c8e
--- /dev/null
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/HttpChannel.java
@@ -0,0 +1,23 @@
+/**
+ *
+ */
+package com.rogiel.httpchannel.service;
+
+import java.io.Closeable;
+import java.nio.channels.Channel;
+
+/**
+ * @author Rogiel
+ *
+ */
+public interface HttpChannel extends Channel, Closeable {
+ /**
+ * @return the file size
+ */
+ long getFilesize();
+
+ /**
+ * @return the file name
+ */
+ String getFilename();
+}
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/Service.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/Service.java
index ba652ed..986cea6 100644
--- a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/Service.java
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/Service.java
@@ -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
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/UploadChannel.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/UploadChannel.java
index 193cc85..e3ec2d5 100644
--- a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/UploadChannel.java
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/UploadChannel.java
@@ -36,16 +36,6 @@ import com.rogiel.httpchannel.service.exception.UploadLinkNotFoundException;
* @author Rogiel
*/
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
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/Uploader.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/Uploader.java
index 074c62e..56f5b01 100644
--- a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/Uploader.java
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/Uploader.java
@@ -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 {
* @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.
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/exception/InvalidCaptchaException.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/exception/InvalidCaptchaException.java
index c3b227e..8d02ca0 100644
--- a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/exception/InvalidCaptchaException.java
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/exception/InvalidCaptchaException.java
@@ -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 Rogiel
diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/exception/UnresolvedCaptchaException.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/exception/NoCaptchaServiceException.java
similarity index 74%
rename from httpchannel-api/src/main/java/com/rogiel/httpchannel/service/exception/UnresolvedCaptchaException.java
rename to httpchannel-api/src/main/java/com/rogiel/httpchannel/service/exception/NoCaptchaServiceException.java
index da86cf0..e18d912 100644
--- a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/exception/UnresolvedCaptchaException.java
+++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/exception/NoCaptchaServiceException.java
@@ -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 Rogiel
*/
-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);
}
}
diff --git a/httpchannel-captcha/httpchannel-captcha-captchatrader/pom.xml b/httpchannel-captcha/httpchannel-captcha-captchatrader/pom.xml
new file mode 100644
index 0000000..62ad5db
--- /dev/null
+++ b/httpchannel-captcha/httpchannel-captcha-captchatrader/pom.xml
@@ -0,0 +1,49 @@
+
+ 4.0.0
+
+ httpchannel-captcha
+ com.rogiel.httpchannel
+ 1.0.0
+ ..
+
+ com.rogiel.httpchannel.captcha
+ httpchannel-captcha-captchatrader
+ HttpChannel/Captcha/CaptchaTrader
+ This module provides an CaptchService that resolves image captchas.
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.1.2
+ jar
+ compile
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+ org.apache.httpcomponents
+ httpmime
+ 4.1.2
+ jar
+ compile
+
+
+ org.apache.commons
+ commons-io
+ 1.3.2
+ jar
+ compile
+
+
+ com.googlecode.json-simple
+ json-simple
+ 1.1
+
+
+
\ No newline at end of file
diff --git a/httpchannel-captcha/httpchannel-captcha-captchatrader/src/main/java/com/captchatrader/CaptchaTrader.java b/httpchannel-captcha/httpchannel-captcha-captchatrader/src/main/java/com/captchatrader/CaptchaTrader.java
new file mode 100644
index 0000000..0d78ce9
--- /dev/null
+++ b/httpchannel-captcha/httpchannel-captcha-captchatrader/src/main/java/com/captchatrader/CaptchaTrader.java
@@ -0,0 +1,207 @@
+/**
+ *
+ */
+package com.captchatrader;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.util.List;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.entity.mime.MultipartEntity;
+import org.apache.http.entity.mime.content.StringBody;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+import org.omg.CORBA.Any;
+
+import com.captchatrader.exception.ApplicationKeyDisabledException;
+import com.captchatrader.exception.CaptchaTraderException;
+import com.captchatrader.exception.ConnectionLimitException;
+import com.captchatrader.exception.DailyLimitException;
+import com.captchatrader.exception.ImageTooLargeException;
+import com.captchatrader.exception.IncorrectRespondsException;
+import com.captchatrader.exception.InsuficientCreditsException;
+import com.captchatrader.exception.InternalErrorException;
+import com.captchatrader.exception.InvalidApplicationKeyException;
+import com.captchatrader.exception.InvalidParametersException;
+import com.captchatrader.exception.InvalidTicketException;
+import com.captchatrader.exception.InvalidURLException;
+import com.captchatrader.exception.InvalidUserException;
+import com.captchatrader.exception.NotAnImageException;
+import com.captchatrader.exception.SubmissionErrorException;
+import com.captchatrader.exception.UserNotValidatedException;
+
+/**
+ * @author Rogiel
+ *
+ */
+public class CaptchaTrader {
+ /**
+ * The {@link HttpClient} instance
+ */
+ private final HttpClient client = new DefaultHttpClient();
+ private final JSONParser json = new JSONParser();
+
+ private final URI apiURL;
+ private final String applicationKey;
+ private final String username;
+ private final String password;
+
+ /**
+ * Creates a new API instance with the given application key
+ *
+ * @param applicationKey
+ * the key
+ */
+ public CaptchaTrader(URI apiURL, String applicationKey, String username,
+ String password) {
+ this.apiURL = apiURL;
+ this.applicationKey = applicationKey;
+ this.username = username;
+ this.password = password;
+ }
+
+ /**
+ * Creates a new API instance with the given application key
+ *
+ * @param applicationKey
+ * the key
+ * @throws MalformedURLException
+ */
+ public CaptchaTrader(String applicationKey, String username, String password) {
+ this(URI.create("http://api.captchatrader.com/"), applicationKey,
+ username, password);
+ }
+
+ /**
+ * Submit a CAPTCHA already hosted on an existing website.
+ *
+ * @param url
+ * The URL of the CAPTCHA image.
+ * @return The decoded CAPTCHA.
+ * @throws Any
+ * exceptions sent by the server.
+ */
+ public ResolvedCaptcha submit(URL url) throws CaptchaTraderException,
+ IOException {
+ final URI requestUri = apiURL.resolve("submit");
+ final HttpPost request = new HttpPost(requestUri);
+ final MultipartEntity entity = new MultipartEntity();
+
+ entity.addPart("api_key", new StringBody(applicationKey));
+ entity.addPart("username", new StringBody(username));
+ entity.addPart("password", new StringBody(password));
+ entity.addPart("value", new StringBody(url.toString()));
+
+ request.setEntity(entity);
+ final List