Add method to retrieve a single URI.
authorDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Tue, 7 Sep 2010 10:16:14 +0000 (12:16 +0200)
committerDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Tue, 7 Sep 2010 10:16:14 +0000 (12:16 +0200)
src/main/java/net/pterodactylus/fcp/highlevel/FcpClient.java
src/main/java/net/pterodactylus/fcp/highlevel/GetResult.java [new file with mode: 0644]

index 91a27f0..dee33c3 100644 (file)
@@ -28,11 +28,13 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
-import java.util.Set;
 import java.util.Map.Entry;
+import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 
 import net.pterodactylus.fcp.AddPeer;
+import net.pterodactylus.fcp.AllData;
+import net.pterodactylus.fcp.ClientGet;
 import net.pterodactylus.fcp.ClientHello;
 import net.pterodactylus.fcp.CloseConnectionDuplicateClientName;
 import net.pterodactylus.fcp.DataFound;
@@ -67,6 +69,7 @@ import net.pterodactylus.fcp.SimpleProgress;
 import net.pterodactylus.fcp.WatchGlobal;
 import net.pterodactylus.util.filter.Filter;
 import net.pterodactylus.util.filter.Filters;
+import net.pterodactylus.util.io.TemporaryInputStream;
 import net.pterodactylus.util.thread.ObjectWrapper;
 
 /**
@@ -303,6 +306,72 @@ public class FcpClient {
        }
 
        /**
+        * Returns the file with the given URI.
+        *
+        * @param uri
+        *            The URI to get
+        * @return The result of the get request
+        * @throws IOException
+        *             if an I/O error occurs
+        * @throws FcpException
+        *             if an FCP error occurs
+        */
+       public GetResult getURI(final String uri) throws IOException, FcpException {
+               checkConnected(true);
+               final GetResult getResult = new GetResult();
+               new ExtendedFcpAdapter() {
+
+                       @SuppressWarnings("synthetic-access")
+                       private final String identifier = createIdentifier("client-get");
+
+                       @Override
+                       @SuppressWarnings("synthetic-access")
+                       public void run() throws IOException {
+                               ClientGet clientGet = new ClientGet(uri, identifier);
+                               fcpConnection.sendMessage(clientGet);
+                       }
+
+                       @Override
+                       public void receivedGetFailed(FcpConnection fcpConnection, GetFailed getFailed) {
+                               if (!getFailed.getIdentifier().equals(identifier)) {
+                                       return;
+                               }
+                               if (getFailed.getCode() == 27) {
+                                       /* redirect! */
+                                       String newUri = getFailed.getRedirectURI();
+                                       getResult.realUri(newUri);
+                                       try {
+                                               fcpConnection.sendMessage(new ClientGet(newUri, identifier));
+                                       } catch (IOException ioe1) {
+                                               getResult.success(false).exception(ioe1);
+                                               completionLatch.countDown();
+                                       }
+                               } else {
+                                       getResult.success(false).errorCode(getFailed.getCode());
+                                       completionLatch.countDown();
+                               }
+                       }
+
+                       @Override
+                       public void receivedAllData(FcpConnection fcpConnection, AllData allData) {
+                               if (!allData.getIdentifier().equals(identifier)) {
+                                       return;
+                               }
+                               InputStream temporaryInputStream;
+                               try {
+                                       temporaryInputStream = new TemporaryInputStream(allData.getPayloadInputStream());
+                                       getResult.success(true).contentType(allData.getContentType()).contentLength(allData.getDataLength()).inputStream(temporaryInputStream);
+                               } catch (IOException ioe1) {
+                                       getResult.success(false).exception(ioe1);
+                               }
+                               completionLatch.countDown();
+                       }
+
+               }.execute();
+               return getResult;
+       }
+
+       /**
         * Disconnects the FCP client.
         */
        public void disconnect() {
diff --git a/src/main/java/net/pterodactylus/fcp/highlevel/GetResult.java b/src/main/java/net/pterodactylus/fcp/highlevel/GetResult.java
new file mode 100644 (file)
index 0000000..15bbb8d
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * jFCPlib - GetResult.java - Copyright © 2010 David Roden
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.fcp.highlevel;
+
+import java.io.InputStream;
+import java.util.EventListener;
+
+/**
+ * A get result encapsulates the result of {@link FcpClient#getURI(String)}. It
+ * is used to allow synchronous retrieval of a file without resorting to
+ * {@link EventListener} interfaces to notify the application of intermediary
+ * results, such as redirects.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class GetResult {
+
+       /** Whether the request was successful. */
+       private boolean success;
+
+       /** The error code, if an error occured. */
+       private int errorCode;
+
+       /** The exception, if an exception occured. */
+       private Throwable exception;
+
+       /** The real URI, if a redirect was found. */
+       private String realUri;
+
+       /** The content type of the file. */
+       private String contentType;
+
+       /** The length of the file. */
+       private long contentLength;
+
+       /** An input stream containing the data of the file. */
+       private InputStream inputStream;
+
+       /**
+        * Returns whether the request was successful.
+        *
+        * @return {@code true} if the request was successful, {@code false}
+        *         otherwise
+        */
+       public boolean isSuccess() {
+               return success;
+       }
+
+       /**
+        * Sets whether the request was successful.
+        *
+        * @param success
+        *            {@code true} if the request was successful, {@code false}
+        *            otherwise
+        * @return This result, to allow method chaning
+        */
+       GetResult success(boolean success) {
+               this.success = success;
+               return this;
+       }
+
+       /**
+        * Returns the error code of the request. The error code is the error code
+        * that is transferred in FCP’s “GetFailed” message. The error code is not
+        * valid if {@link #isSuccess()} is {@code true}. If an exception occured
+        * (i.e. if {@link #getException()} returns a non-{@code null} value) the
+        * error code might also be invalid.
+        *
+        * @return The error code of the request
+        */
+       public int getErrorCode() {
+               return errorCode;
+       }
+
+       /**
+        * Sets the error code of the request.
+        *
+        * @param errorCode
+        *            The error code of the request
+        * @return This result, to allow method chaining
+        */
+       GetResult errorCode(int errorCode) {
+               this.errorCode = errorCode;
+               return this;
+       }
+
+       /**
+        * Returns the exception, if any occured.
+        *
+        * @return The occured exception, or {@code null} if there was no exception
+        */
+       public Throwable getException() {
+               return exception;
+       }
+
+       /**
+        * Sets the exception that occured.
+        *
+        * @param exception
+        *            The occured exception
+        * @return This result, to allow method chaining
+        */
+       GetResult exception(Throwable exception) {
+               this.exception = exception;
+               return this;
+       }
+
+       /**
+        * Returns the real URI in case of a redirect.
+        *
+        * @return The real URI, or {@code null} if there was no redirect
+        */
+       public String getRealUri() {
+               return realUri;
+       }
+
+       /**
+        * Sets the real URI in case of a redirect.
+        *
+        * @param realUri
+        *            The real URI
+        * @return This result, to allow method chaining
+        */
+       GetResult realUri(String realUri) {
+               this.realUri = realUri;
+               return this;
+       }
+
+       /**
+        * Returns the content type of the result.
+        *
+        * @return The content type of the result
+        */
+       public String getContentType() {
+               return contentType;
+       }
+
+       /**
+        * Sets the content type of the result.
+        *
+        * @param contentType
+        *            The content type of the result
+        * @return This result, to allow method chaining
+        */
+       GetResult contentType(String contentType) {
+               this.contentType = contentType;
+               return this;
+       }
+
+       /**
+        * Returns the content length of the result.
+        *
+        * @return The content length of the result
+        */
+       public long getContentLength() {
+               return contentLength;
+       }
+
+       /**
+        * Sets the content length of the result.
+        *
+        * @param contentLength
+        *            The content length of the result
+        * @return This result, to allow method chaining
+        */
+       GetResult contentLength(long contentLength) {
+               this.contentLength = contentLength;
+               return this;
+       }
+
+       /**
+        * Returns the data.
+        *
+        * @return The data
+        */
+       public InputStream getInputStream() {
+               return inputStream;
+       }
+
+       /**
+        * Sets the input stream that will deliver the data.
+        *
+        * @param inputStream
+        *            The input stream containing the data
+        * @return This result, to allow method chaining
+        */
+       GetResult inputStream(InputStream inputStream) {
+               this.inputStream = inputStream;
+               return this;
+       }
+
+       //
+       // OBJECT METHODS
+       //
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public String toString() {
+               return getClass().getName() + "[success=" + success + ",errorCode=" + errorCode + ",exception=" + exception + ",realUri=" + realUri + ",contentType=" + contentType + ",contentLength=" + contentLength + ",inputStream=" + inputStream + "]";
+       }
+
+}