├── CHANGES.markdown
├── Example
├── .classpath
├── .project
├── .settings
│ └── org.eclipse.jdt.core.prefs
├── AndroidManifest.xml
├── default.properties
├── libs
│ └── commons-codec-1.4.jar
├── res
│ ├── drawable-hdpi
│ │ └── icon.png
│ ├── drawable-ldpi
│ │ └── icon.png
│ ├── drawable-mdpi
│ │ └── icon.png
│ ├── layout
│ │ ├── main.xml
│ │ ├── new_note.xml
│ │ └── sign_in.xml
│ └── values
│ │ └── strings.xml
└── src
│ └── com
│ ├── android
│ └── http
│ │ └── multipart
│ │ ├── ByteArrayPartSource.java
│ │ ├── FilePart.java
│ │ ├── FilePartSource.java
│ │ ├── MultipartEntity.java
│ │ ├── Part.java
│ │ ├── PartBase.java
│ │ ├── PartSource.java
│ │ └── StringPart.java
│ ├── catchnotes
│ └── api
│ │ ├── CatchAPI.java
│ │ ├── CatchAccount.java
│ │ ├── CatchMedia.java
│ │ ├── CatchNote.java
│ │ ├── CatchNoteRef.java
│ │ ├── CatchNotesXmlParser.java
│ │ └── VersionedCatchHttpClient.java
│ └── example
│ └── CatchApiDemo
│ └── Dashboard.java
├── LICENSE.txt
├── README.markdown
└── android-lib
├── libs
└── commons-codec-1.4.jar
└── src
└── com
├── android
└── http
│ └── multipart
│ ├── ByteArrayPartSource.java
│ ├── FilePart.java
│ ├── FilePartSource.java
│ ├── MultipartEntity.java
│ ├── Part.java
│ ├── PartBase.java
│ ├── PartSource.java
│ └── StringPart.java
└── catchnotes
└── api
├── CatchAPI.java
├── CatchAccount.java
├── CatchMedia.java
├── CatchNote.java
├── CatchNoteRef.java
├── CatchNotesXmlParser.java
└── VersionedCatchHttpClient.java
/CHANGES.markdown:
--------------------------------------------------------------------------------
1 | ### What's new in 1.0.0.
2 | * Initial release of API-v2 code.
3 |
--------------------------------------------------------------------------------
/Example/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | CatchApiDemo
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Example/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | #Thu May 05 10:45:08 CDT 2011
2 | eclipse.preferences.version=1
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
4 | org.eclipse.jdt.core.compiler.compliance=1.5
5 | org.eclipse.jdt.core.compiler.source=1.5
6 |
--------------------------------------------------------------------------------
/Example/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Example/default.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "build.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Project target.
11 | target=android-8
12 |
--------------------------------------------------------------------------------
/Example/libs/commons-codec-1.4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/catch/android-api/9fab8967757a64078fffa811ebb939364e5b3617/Example/libs/commons-codec-1.4.jar
--------------------------------------------------------------------------------
/Example/res/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/catch/android-api/9fab8967757a64078fffa811ebb939364e5b3617/Example/res/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/Example/res/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/catch/android-api/9fab8967757a64078fffa811ebb939364e5b3617/Example/res/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/Example/res/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/catch/android-api/9fab8967757a64078fffa811ebb939364e5b3617/Example/res/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/Example/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
13 |
18 |
23 |
28 |
29 |
--------------------------------------------------------------------------------
/Example/res/layout/new_note.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
15 |
16 |
--------------------------------------------------------------------------------
/Example/res/layout/sign_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
13 |
19 |
20 |
--------------------------------------------------------------------------------
/Example/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Watch logcat to see the results!\nadb logcat CatchApiDemo:D *:S
4 | Sign In
5 | Cancel
6 | Fetch Notes
7 | Add New Note
8 | Add Note
9 | Catch API Demo
10 | Sign in to a Catch.com account
11 | Enter the text of your note
12 |
13 |
--------------------------------------------------------------------------------
/Example/src/com/android/http/multipart/ByteArrayPartSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/ByteArrayPartSource.java,v 1.7 2004/04/18 23:51:37 jsdever Exp $
3 | * $Revision: 480424 $
4 | * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
5 | *
6 | * ====================================================================
7 | *
8 | * Licensed to the Apache Software Foundation (ASF) under one or more
9 | * contributor license agreements. See the NOTICE file distributed with
10 | * this work for additional information regarding copyright ownership.
11 | * The ASF licenses this file to You under the Apache License, Version 2.0
12 | * (the "License"); you may not use this file except in compliance with
13 | * the License. You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | * ====================================================================
23 | *
24 | * This software consists of voluntary contributions made by many
25 | * individuals on behalf of the Apache Software Foundation. For more
26 | * information on the Apache Software Foundation, please see
27 | * .
28 | *
29 | */
30 |
31 | package com.android.http.multipart;
32 |
33 | import java.io.ByteArrayInputStream;
34 | import java.io.InputStream;
35 |
36 | /**
37 | * A PartSource that reads from a byte array. This class should be used when
38 | * the data to post is already loaded into memory.
39 | *
40 | * @author Michael Becke
41 | *
42 | * @since 2.0
43 | */
44 | public class ByteArrayPartSource implements PartSource {
45 |
46 | /** Name of the source file. */
47 | private String fileName;
48 |
49 | /** Byte array of the source file. */
50 | private byte[] bytes;
51 |
52 | /**
53 | * Constructor for ByteArrayPartSource.
54 | *
55 | * @param fileName the name of the file these bytes represent
56 | * @param bytes the content of this part
57 | */
58 | public ByteArrayPartSource(String fileName, byte[] bytes) {
59 |
60 | this.fileName = fileName;
61 | this.bytes = bytes;
62 |
63 | }
64 |
65 | /**
66 | * @see PartSource#getLength()
67 | */
68 | public long getLength() {
69 | return bytes.length;
70 | }
71 |
72 | /**
73 | * @see PartSource#getFileName()
74 | */
75 | public String getFileName() {
76 | return fileName;
77 | }
78 |
79 | /**
80 | * @see PartSource#createInputStream()
81 | */
82 | public InputStream createInputStream() {
83 | return new ByteArrayInputStream(bytes);
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/Example/src/com/android/http/multipart/FilePart.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java,v 1.19 2004/04/18 23:51:37 jsdever Exp $
3 | * $Revision: 480424 $
4 | * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
5 | *
6 | * ====================================================================
7 | *
8 | * Licensed to the Apache Software Foundation (ASF) under one or more
9 | * contributor license agreements. See the NOTICE file distributed with
10 | * this work for additional information regarding copyright ownership.
11 | * The ASF licenses this file to You under the Apache License, Version 2.0
12 | * (the "License"); you may not use this file except in compliance with
13 | * the License. You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | * ====================================================================
23 | *
24 | * This software consists of voluntary contributions made by many
25 | * individuals on behalf of the Apache Software Foundation. For more
26 | * information on the Apache Software Foundation, please see
27 | * .
28 | *
29 | */
30 |
31 | package com.android.http.multipart;
32 |
33 | import java.io.File;
34 | import java.io.FileNotFoundException;
35 | import java.io.IOException;
36 | import java.io.InputStream;
37 | import java.io.OutputStream;
38 | import org.apache.http.util.EncodingUtils;
39 |
40 | /**
41 | * This class implements a part of a Multipart post object that
42 | * consists of a file.
43 | *
44 | * @author Matthew Albright
45 | * @author Jeff Dever
46 | * @author Adrian Sutton
47 | * @author Michael Becke
48 | * @author Mark Diggory
49 | * @author Mike Bowler
50 | * @author Oleg Kalnichevski
51 | *
52 | * @since 2.0
53 | *
54 | */
55 | public class FilePart extends PartBase {
56 |
57 | /** Default content encoding of file attachments. */
58 | public static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
59 |
60 | /** Default charset of file attachments. */
61 | public static final String DEFAULT_CHARSET = "ISO-8859-1";
62 |
63 | /** Default transfer encoding of file attachments. */
64 | public static final String DEFAULT_TRANSFER_ENCODING = "binary";
65 |
66 | /** Attachment's file name */
67 | protected static final String FILE_NAME = "; filename=";
68 |
69 | /** Attachment's file name as a byte array */
70 | private static final byte[] FILE_NAME_BYTES =
71 | EncodingUtils.getAsciiBytes(FILE_NAME);
72 |
73 | /** Source of the file part. */
74 | private PartSource source;
75 |
76 | /**
77 | * FilePart Constructor.
78 | *
79 | * @param name the name for this part
80 | * @param partSource the source for this part
81 | * @param contentType the content type for this part, if null the
82 | * {@link #DEFAULT_CONTENT_TYPE default} is used
83 | * @param charset the charset encoding for this part, if null the
84 | * {@link #DEFAULT_CHARSET default} is used
85 | */
86 | public FilePart(String name, PartSource partSource, String contentType, String charset) {
87 |
88 | super(
89 | name,
90 | contentType == null ? DEFAULT_CONTENT_TYPE : contentType,
91 | charset == null ? "ISO-8859-1" : charset,
92 | DEFAULT_TRANSFER_ENCODING
93 | );
94 |
95 | if (partSource == null) {
96 | throw new IllegalArgumentException("Source may not be null");
97 | }
98 | this.source = partSource;
99 | }
100 |
101 | /**
102 | * FilePart Constructor.
103 | *
104 | * @param name the name for this part
105 | * @param partSource the source for this part
106 | */
107 | public FilePart(String name, PartSource partSource) {
108 | this(name, partSource, null, null);
109 | }
110 |
111 | /**
112 | * FilePart Constructor.
113 | *
114 | * @param name the name of the file part
115 | * @param file the file to post
116 | *
117 | * @throws FileNotFoundException if the file is not a normal
118 | * file or if it is not readable.
119 | */
120 | public FilePart(String name, File file)
121 | throws FileNotFoundException {
122 | this(name, new FilePartSource(file), null, null);
123 | }
124 |
125 | /**
126 | * FilePart Constructor.
127 | *
128 | * @param name the name of the file part
129 | * @param file the file to post
130 | * @param contentType the content type for this part, if null the
131 | * {@link #DEFAULT_CONTENT_TYPE default} is used
132 | * @param charset the charset encoding for this part, if null the
133 | * {@link #DEFAULT_CHARSET default} is used
134 | *
135 | * @throws FileNotFoundException if the file is not a normal
136 | * file or if it is not readable.
137 | */
138 | public FilePart(String name, File file, String contentType, String charset)
139 | throws FileNotFoundException {
140 | this(name, new FilePartSource(file), contentType, charset);
141 | }
142 |
143 | /**
144 | * FilePart Constructor.
145 | *
146 | * @param name the name of the file part
147 | * @param fileName the file name
148 | * @param file the file to post
149 | *
150 | * @throws FileNotFoundException if the file is not a normal
151 | * file or if it is not readable.
152 | */
153 | public FilePart(String name, String fileName, File file)
154 | throws FileNotFoundException {
155 | this(name, new FilePartSource(fileName, file), null, null);
156 | }
157 |
158 | /**
159 | * FilePart Constructor.
160 | *
161 | * @param name the name of the file part
162 | * @param fileName the file name
163 | * @param file the file to post
164 | * @param contentType the content type for this part, if null the
165 | * {@link #DEFAULT_CONTENT_TYPE default} is used
166 | * @param charset the charset encoding for this part, if null the
167 | * {@link #DEFAULT_CHARSET default} is used
168 | *
169 | * @throws FileNotFoundException if the file is not a normal
170 | * file or if it is not readable.
171 | */
172 | public FilePart(String name, String fileName, File file, String contentType, String charset)
173 | throws FileNotFoundException {
174 | this(name, new FilePartSource(fileName, file), contentType, charset);
175 | }
176 |
177 | /**
178 | * Write the disposition header to the output stream
179 | * @param out The output stream
180 | * @throws IOException If an IO problem occurs
181 | * @see Part#sendDispositionHeader(OutputStream)
182 | */
183 | @Override
184 | protected void sendDispositionHeader(OutputStream out)
185 | throws IOException {
186 | super.sendDispositionHeader(out);
187 | String filename = this.source.getFileName();
188 | if (filename != null) {
189 | out.write(FILE_NAME_BYTES);
190 | out.write(QUOTE_BYTES);
191 | out.write(EncodingUtils.getAsciiBytes(filename));
192 | out.write(QUOTE_BYTES);
193 | }
194 | }
195 |
196 | /**
197 | * Write the data in "source" to the specified stream.
198 | * @param out The output stream.
199 | * @throws IOException if an IO problem occurs.
200 | * @see Part#sendData(OutputStream)
201 | */
202 | @Override
203 | protected void sendData(OutputStream out) throws IOException {
204 | if (lengthOfData() == 0) {
205 |
206 | // this file contains no data, so there is nothing to send.
207 | // we don't want to create a zero length buffer as this will
208 | // cause an infinite loop when reading.
209 | return;
210 | }
211 |
212 | byte[] tmp = new byte[4096];
213 | InputStream instream = source.createInputStream();
214 | try {
215 | int len;
216 | while ((len = instream.read(tmp)) >= 0) {
217 | out.write(tmp, 0, len);
218 | }
219 | } finally {
220 | // we're done with the stream, close it
221 | instream.close();
222 | }
223 | }
224 |
225 | /**
226 | * Returns the source of the file part.
227 | *
228 | * @return The source.
229 | */
230 | protected PartSource getSource() {
231 | return this.source;
232 | }
233 |
234 | /**
235 | * Return the length of the data.
236 | * @return The length.
237 | * @see Part#lengthOfData()
238 | */
239 | @Override
240 | protected long lengthOfData() {
241 | return source.getLength();
242 | }
243 |
244 | }
245 |
--------------------------------------------------------------------------------
/Example/src/com/android/http/multipart/FilePartSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePartSource.java,v 1.10 2004/04/18 23:51:37 jsdever Exp $
3 | * $Revision: 480424 $
4 | * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
5 | *
6 | * ====================================================================
7 | *
8 | * Licensed to the Apache Software Foundation (ASF) under one or more
9 | * contributor license agreements. See the NOTICE file distributed with
10 | * this work for additional information regarding copyright ownership.
11 | * The ASF licenses this file to You under the Apache License, Version 2.0
12 | * (the "License"); you may not use this file except in compliance with
13 | * the License. You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | * ====================================================================
23 | *
24 | * This software consists of voluntary contributions made by many
25 | * individuals on behalf of the Apache Software Foundation. For more
26 | * information on the Apache Software Foundation, please see
27 | * .
28 | *
29 | */
30 |
31 | package com.android.http.multipart;
32 |
33 | import java.io.ByteArrayInputStream;
34 | import java.io.File;
35 | import java.io.FileInputStream;
36 | import java.io.FileNotFoundException;
37 | import java.io.IOException;
38 | import java.io.InputStream;
39 |
40 | /**
41 | * A PartSource that reads from a File.
42 | *
43 | * @author Michael Becke
44 | * @author Mark Diggory
45 | * @author Mike Bowler
46 | *
47 | * @since 2.0
48 | */
49 | public class FilePartSource implements PartSource {
50 |
51 | /** File part file. */
52 | private File file = null;
53 |
54 | /** File part file name. */
55 | private String fileName = null;
56 |
57 | /**
58 | * Constructor for FilePartSource.
59 | *
60 | * @param file the FilePart source File.
61 | *
62 | * @throws FileNotFoundException if the file does not exist or
63 | * cannot be read
64 | */
65 | public FilePartSource(File file) throws FileNotFoundException {
66 | this.file = file;
67 | if (file != null) {
68 | if (!file.isFile()) {
69 | throw new FileNotFoundException("File is not a normal file.");
70 | }
71 | if (!file.canRead()) {
72 | throw new FileNotFoundException("File is not readable.");
73 | }
74 | this.fileName = file.getName();
75 | }
76 | }
77 |
78 | /**
79 | * Constructor for FilePartSource.
80 | *
81 | * @param fileName the file name of the FilePart
82 | * @param file the source File for the FilePart
83 | *
84 | * @throws FileNotFoundException if the file does not exist or
85 | * cannot be read
86 | */
87 | public FilePartSource(String fileName, File file)
88 | throws FileNotFoundException {
89 | this(file);
90 | if (fileName != null) {
91 | this.fileName = fileName;
92 | }
93 | }
94 |
95 | /**
96 | * Return the length of the file
97 | * @return the length of the file.
98 | * @see PartSource#getLength()
99 | */
100 | public long getLength() {
101 | if (this.file != null) {
102 | return this.file.length();
103 | } else {
104 | return 0;
105 | }
106 | }
107 |
108 | /**
109 | * Return the current filename
110 | * @return the filename.
111 | * @see PartSource#getFileName()
112 | */
113 | public String getFileName() {
114 | return (fileName == null) ? "noname" : fileName;
115 | }
116 |
117 | /**
118 | * Return a new {@link FileInputStream} for the current filename.
119 | * @return the new input stream.
120 | * @throws IOException If an IO problem occurs.
121 | * @see PartSource#createInputStream()
122 | */
123 | public InputStream createInputStream() throws IOException {
124 | if (this.file != null) {
125 | return new FileInputStream(this.file);
126 | } else {
127 | return new ByteArrayInputStream(new byte[] {});
128 | }
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/Example/src/com/android/http/multipart/MultipartEntity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/MultipartRequestEntity.java,v 1.1 2004/10/06 03:39:59 mbecke Exp $
3 | * $Revision: 502647 $
4 | * $Date: 2007-02-02 17:22:54 +0100 (Fri, 02 Feb 2007) $
5 | *
6 | * ====================================================================
7 | *
8 | * Licensed to the Apache Software Foundation (ASF) under one or more
9 | * contributor license agreements. See the NOTICE file distributed with
10 | * this work for additional information regarding copyright ownership.
11 | * The ASF licenses this file to You under the Apache License, Version 2.0
12 | * (the "License"); you may not use this file except in compliance with
13 | * the License. You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | * ====================================================================
23 | *
24 | * This software consists of voluntary contributions made by many
25 | * individuals on behalf of the Apache Software Foundation. For more
26 | * information on the Apache Software Foundation, please see
27 | * .
28 | *
29 | */
30 |
31 | package com.android.http.multipart;
32 |
33 | import java.io.ByteArrayInputStream;
34 | import java.io.ByteArrayOutputStream;
35 | import java.io.IOException;
36 | import java.io.InputStream;
37 | import java.io.OutputStream;
38 | import java.util.Random;
39 |
40 | import org.apache.http.Header;
41 | import org.apache.http.entity.AbstractHttpEntity;
42 | import org.apache.http.message.BasicHeader;
43 | import org.apache.http.params.HttpParams;
44 | import org.apache.http.protocol.HTTP;
45 | import org.apache.http.util.EncodingUtils;
46 |
47 | /**
48 | * Implements a request entity suitable for an HTTP multipart POST method.
49 | *
50 | * The HTTP multipart POST method is defined in section 3.3 of
51 | * RFC1867:
52 | *
53 | * The media-type multipart/form-data follows the rules of all multipart
54 | * MIME data streams as outlined in RFC 1521. The multipart/form-data contains
55 | * a series of parts. Each part is expected to contain a content-disposition
56 | * header where the value is "form-data" and a name attribute specifies
57 | * the field name within the form, e.g., 'content-disposition: form-data;
58 | * name="xxxxx"', where xxxxx is the field name corresponding to that field.
59 | * Field names originally in non-ASCII character sets may be encoded using
60 | * the method outlined in RFC 1522.
61 | *
62 | *
63 | *
This entity is designed to be used in conjunction with the
64 | * {@link org.apache.http.HttpRequest} to provide
65 | * multipart posts. Example usage:
66 | *
67 | * File f = new File("/path/fileToUpload.txt");
68 | * HttpRequest request = new HttpRequest("http://host/some_path");
69 | * Part[] parts = {
70 | * new StringPart("param_name", "value"),
71 | * new FilePart(f.getName(), f)
72 | * };
73 | * filePost.setEntity(
74 | * new MultipartRequestEntity(parts, filePost.getParams())
75 | * );
76 | * HttpClient client = new HttpClient();
77 | * int status = client.executeMethod(filePost);
78 | *
79 | *
80 | * @since 3.0
81 | */
82 | public class MultipartEntity extends AbstractHttpEntity {
83 | /** The Content-Type for multipart/form-data. */
84 | private static final String MULTIPART_FORM_CONTENT_TYPE = "multipart/form-data";
85 |
86 | /**
87 | * Sets the value to use as the multipart boundary.
88 | *
89 | * This parameter expects a value if type {@link String}.
90 | *
91 | */
92 | public static final String MULTIPART_BOUNDARY = "http.method.multipart.boundary";
93 |
94 | /**
95 | * The pool of ASCII chars to be used for generating a multipart boundary.
96 | */
97 | private static byte[] MULTIPART_CHARS = EncodingUtils.getAsciiBytes(
98 | "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
99 |
100 | /**
101 | * Generates a random multipart boundary string.
102 | */
103 | private static byte[] generateMultipartBoundary() {
104 | Random rand = new Random();
105 | byte[] bytes = new byte[rand.nextInt(11) + 30]; // a random size from 30 to 40
106 | for (int i = 0; i < bytes.length; i++) {
107 | bytes[i] = MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)];
108 | }
109 | return bytes;
110 | }
111 |
112 | /** The MIME parts as set by the constructor */
113 | protected Part[] parts;
114 |
115 | private byte[] multipartBoundary;
116 |
117 | private HttpParams params;
118 |
119 | private boolean contentConsumed = false;
120 |
121 | /**
122 | * Creates a new multipart entity containing the given parts.
123 | * @param parts The parts to include.
124 | * @param params The params of the HttpMethod using this entity.
125 | */
126 | public MultipartEntity(Part[] parts, HttpParams params) {
127 | if (parts == null) {
128 | throw new IllegalArgumentException("parts cannot be null");
129 | }
130 | if (params == null) {
131 | throw new IllegalArgumentException("params cannot be null");
132 | }
133 | this.parts = parts;
134 | this.params = params;
135 | }
136 |
137 | public MultipartEntity(Part[] parts) {
138 | setContentType(MULTIPART_FORM_CONTENT_TYPE);
139 | if (parts == null) {
140 | throw new IllegalArgumentException("parts cannot be null");
141 | }
142 | this.parts = parts;
143 | this.params = null;
144 | }
145 |
146 | /**
147 | * Returns the MIME boundary string that is used to demarcate boundaries of
148 | * this part. The first call to this method will implicitly create a new
149 | * boundary string. To create a boundary string first the
150 | * HttpMethodParams.MULTIPART_BOUNDARY parameter is considered. Otherwise
151 | * a random one is generated.
152 | *
153 | * @return The boundary string of this entity in ASCII encoding.
154 | */
155 | protected byte[] getMultipartBoundary() {
156 | if (multipartBoundary == null) {
157 | String temp = null;
158 | if (params != null) {
159 | temp = (String) params.getParameter(MULTIPART_BOUNDARY);
160 | }
161 | if (temp != null) {
162 | multipartBoundary = EncodingUtils.getAsciiBytes(temp);
163 | } else {
164 | multipartBoundary = generateMultipartBoundary();
165 | }
166 | }
167 | return multipartBoundary;
168 | }
169 |
170 | /**
171 | * Returns true if all parts are repeatable, false otherwise.
172 | */
173 | public boolean isRepeatable() {
174 | for (int i = 0; i < parts.length; i++) {
175 | if (!parts[i].isRepeatable()) {
176 | return false;
177 | }
178 | }
179 | return true;
180 | }
181 |
182 | /* (non-Javadoc)
183 | */
184 | public void writeTo(OutputStream out) throws IOException {
185 | Part.sendParts(out, parts, getMultipartBoundary());
186 | }
187 | /* (non-Javadoc)
188 | * @see org.apache.commons.http.AbstractHttpEntity.#getContentType()
189 | */
190 | @Override
191 | public Header getContentType() {
192 | StringBuffer buffer = new StringBuffer(MULTIPART_FORM_CONTENT_TYPE);
193 | buffer.append("; boundary=");
194 | buffer.append(EncodingUtils.getAsciiString(getMultipartBoundary()));
195 | return new BasicHeader(HTTP.CONTENT_TYPE, buffer.toString());
196 |
197 | }
198 |
199 | /* (non-Javadoc)
200 | */
201 | public long getContentLength() {
202 | try {
203 | return Part.getLengthOfParts(parts, getMultipartBoundary());
204 | } catch (Exception e) {
205 | return 0;
206 | }
207 | }
208 |
209 | public InputStream getContent() throws IOException, IllegalStateException {
210 | if(!isRepeatable() && this.contentConsumed ) {
211 | throw new IllegalStateException("Content has been consumed");
212 | }
213 | this.contentConsumed = true;
214 |
215 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
216 | Part.sendParts(baos, this.parts, this.multipartBoundary);
217 | ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
218 | return bais;
219 | }
220 |
221 | public boolean isStreaming() {
222 | return false;
223 | }
224 | }
225 |
--------------------------------------------------------------------------------
/Example/src/com/android/http/multipart/Part.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/Part.java,v 1.16 2005/01/14 21:16:40 olegk Exp $
3 | * $Revision: 480424 $
4 | * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
5 | *
6 | * ====================================================================
7 | *
8 | * Licensed to the Apache Software Foundation (ASF) under one or more
9 | * contributor license agreements. See the NOTICE file distributed with
10 | * this work for additional information regarding copyright ownership.
11 | * The ASF licenses this file to You under the Apache License, Version 2.0
12 | * (the "License"); you may not use this file except in compliance with
13 | * the License. You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | * ====================================================================
23 | *
24 | * This software consists of voluntary contributions made by many
25 | * individuals on behalf of the Apache Software Foundation. For more
26 | * information on the Apache Software Foundation, please see
27 | * .
28 | *
29 | */
30 |
31 | package com.android.http.multipart;
32 |
33 | import java.io.ByteArrayOutputStream;
34 | import java.io.IOException;
35 | import java.io.OutputStream;
36 |
37 | import org.apache.http.util.EncodingUtils;
38 |
39 | /**
40 | * Abstract class for one Part of a multipart post object.
41 | *
42 | * @author Matthew Albright
43 | * @author Jeff Dever
44 | * @author Adrian Sutton
45 | * @author Mike Bowler
46 | * @author Oleg Kalnichevski
47 | *
48 | * @since 2.0
49 | */
50 | public abstract class Part {
51 | /**
52 | * The boundary
53 | * @deprecated use {@link org.apache.http.client.methods.multipart#MULTIPART_BOUNDARY}
54 | */
55 | protected static final String BOUNDARY = "----------------314159265358979323846";
56 |
57 | /**
58 | * The boundary as a byte array.
59 | * @deprecated
60 | */
61 | protected static final byte[] BOUNDARY_BYTES = EncodingUtils.getAsciiBytes(BOUNDARY);
62 |
63 | /**
64 | * The default boundary to be used if {@link #setPartBoundary(byte[])} has not
65 | * been called.
66 | */
67 | private static final byte[] DEFAULT_BOUNDARY_BYTES = BOUNDARY_BYTES;
68 |
69 | /** Carriage return/linefeed */
70 | protected static final String CRLF = "\r\n";
71 |
72 | /** Carriage return/linefeed as a byte array */
73 | protected static final byte[] CRLF_BYTES = EncodingUtils.getAsciiBytes(CRLF);
74 |
75 | /** Content dispostion characters */
76 | protected static final String QUOTE = "\"";
77 |
78 | /** Content dispostion as a byte array */
79 | protected static final byte[] QUOTE_BYTES =
80 | EncodingUtils.getAsciiBytes(QUOTE);
81 |
82 | /** Extra characters */
83 | protected static final String EXTRA = "--";
84 |
85 | /** Extra characters as a byte array */
86 | protected static final byte[] EXTRA_BYTES =
87 | EncodingUtils.getAsciiBytes(EXTRA);
88 |
89 | /** Content dispostion characters */
90 | protected static final String CONTENT_DISPOSITION = "Content-Disposition: form-data; name=";
91 |
92 | /** Content dispostion as a byte array */
93 | protected static final byte[] CONTENT_DISPOSITION_BYTES =
94 | EncodingUtils.getAsciiBytes(CONTENT_DISPOSITION);
95 |
96 | /** Content type header */
97 | protected static final String CONTENT_TYPE = "Content-Type: ";
98 |
99 | /** Content type header as a byte array */
100 | protected static final byte[] CONTENT_TYPE_BYTES =
101 | EncodingUtils.getAsciiBytes(CONTENT_TYPE);
102 |
103 | /** Content charset */
104 | protected static final String CHARSET = "; charset=";
105 |
106 | /** Content charset as a byte array */
107 | protected static final byte[] CHARSET_BYTES =
108 | EncodingUtils.getAsciiBytes(CHARSET);
109 |
110 | /** Content type header */
111 | protected static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding: ";
112 |
113 | /** Content type header as a byte array */
114 | protected static final byte[] CONTENT_TRANSFER_ENCODING_BYTES =
115 | EncodingUtils.getAsciiBytes(CONTENT_TRANSFER_ENCODING);
116 |
117 | /**
118 | * Return the boundary string.
119 | * @return the boundary string
120 | * @deprecated uses a constant string. Rather use {@link #getPartBoundary}
121 | */
122 | public static String getBoundary() {
123 | return BOUNDARY;
124 | }
125 |
126 | /**
127 | * The ASCII bytes to use as the multipart boundary.
128 | */
129 | private byte[] boundaryBytes;
130 |
131 | /**
132 | * Return the name of this part.
133 | * @return The name.
134 | */
135 | public abstract String getName();
136 |
137 | /**
138 | * Returns the content type of this part.
139 | * @return the content type, or null to exclude the content type header
140 | */
141 | public abstract String getContentType();
142 |
143 | /**
144 | * Return the character encoding of this part.
145 | * @return the character encoding, or null to exclude the character
146 | * encoding header
147 | */
148 | public abstract String getCharSet();
149 |
150 | /**
151 | * Return the transfer encoding of this part.
152 | * @return the transfer encoding, or null to exclude the transfer encoding header
153 | */
154 | public abstract String getTransferEncoding();
155 |
156 | /**
157 | * Gets the part boundary to be used.
158 | * @return the part boundary as an array of bytes.
159 | *
160 | * @since 3.0
161 | */
162 | protected byte[] getPartBoundary() {
163 | if (boundaryBytes == null) {
164 | // custom boundary bytes have not been set, use the default.
165 | return DEFAULT_BOUNDARY_BYTES;
166 | } else {
167 | return boundaryBytes;
168 | }
169 | }
170 |
171 | /**
172 | * Sets the part boundary. Only meant to be used by
173 | * {@link Part#sendParts(OutputStream, Part[], byte[])}
174 | * and {@link Part#getLengthOfParts(Part[], byte[])}
175 | * @param boundaryBytes An array of ASCII bytes.
176 | * @since 3.0
177 | */
178 | void setPartBoundary(byte[] boundaryBytes) {
179 | this.boundaryBytes = boundaryBytes;
180 | }
181 |
182 | /**
183 | * Tests if this part can be sent more than once.
184 | * @return true if {@link #sendData(OutputStream)} can be successfully called
185 | * more than once.
186 | * @since 3.0
187 | */
188 | public boolean isRepeatable() {
189 | return true;
190 | }
191 |
192 | /**
193 | * Write the start to the specified output stream
194 | * @param out The output stream
195 | * @throws IOException If an IO problem occurs.
196 | */
197 | protected void sendStart(OutputStream out) throws IOException {
198 | out.write(EXTRA_BYTES);
199 | out.write(getPartBoundary());
200 | out.write(CRLF_BYTES);
201 | }
202 |
203 | /**
204 | * Write the content disposition header to the specified output stream
205 | *
206 | * @param out The output stream
207 | * @throws IOException If an IO problem occurs.
208 | */
209 | protected void sendDispositionHeader(OutputStream out) throws IOException {
210 | out.write(CONTENT_DISPOSITION_BYTES);
211 | out.write(QUOTE_BYTES);
212 | out.write(EncodingUtils.getAsciiBytes(getName()));
213 | out.write(QUOTE_BYTES);
214 | }
215 |
216 | /**
217 | * Write the content type header to the specified output stream
218 | * @param out The output stream
219 | * @throws IOException If an IO problem occurs.
220 | */
221 | protected void sendContentTypeHeader(OutputStream out) throws IOException {
222 | String contentType = getContentType();
223 | if (contentType != null) {
224 | out.write(CRLF_BYTES);
225 | out.write(CONTENT_TYPE_BYTES);
226 | out.write(EncodingUtils.getAsciiBytes(contentType));
227 | String charSet = getCharSet();
228 | if (charSet != null) {
229 | out.write(CHARSET_BYTES);
230 | out.write(EncodingUtils.getAsciiBytes(charSet));
231 | }
232 | }
233 | }
234 |
235 | /**
236 | * Write the content transfer encoding header to the specified
237 | * output stream
238 | *
239 | * @param out The output stream
240 | * @throws IOException If an IO problem occurs.
241 | */
242 | protected void sendTransferEncodingHeader(OutputStream out) throws IOException {
243 | String transferEncoding = getTransferEncoding();
244 | if (transferEncoding != null) {
245 | out.write(CRLF_BYTES);
246 | out.write(CONTENT_TRANSFER_ENCODING_BYTES);
247 | out.write(EncodingUtils.getAsciiBytes(transferEncoding));
248 | }
249 | }
250 |
251 | /**
252 | * Write the end of the header to the output stream
253 | * @param out The output stream
254 | * @throws IOException If an IO problem occurs.
255 | */
256 | protected void sendEndOfHeader(OutputStream out) throws IOException {
257 | out.write(CRLF_BYTES);
258 | out.write(CRLF_BYTES);
259 | }
260 |
261 | /**
262 | * Write the data to the specified output stream
263 | * @param out The output stream
264 | * @throws IOException If an IO problem occurs.
265 | */
266 | protected abstract void sendData(OutputStream out) throws IOException;
267 |
268 | /**
269 | * Return the length of the main content
270 | *
271 | * @return long The length.
272 | * @throws IOException If an IO problem occurs
273 | */
274 | protected abstract long lengthOfData() throws IOException;
275 |
276 | /**
277 | * Write the end data to the output stream.
278 | * @param out The output stream
279 | * @throws IOException If an IO problem occurs.
280 | */
281 | protected void sendEnd(OutputStream out) throws IOException {
282 | out.write(CRLF_BYTES);
283 | }
284 |
285 | /**
286 | * Write all the data to the output stream.
287 | * If you override this method make sure to override
288 | * #length() as well
289 | *
290 | * @param out The output stream
291 | * @throws IOException If an IO problem occurs.
292 | */
293 | public void send(OutputStream out) throws IOException {
294 | sendStart(out);
295 | sendDispositionHeader(out);
296 | sendContentTypeHeader(out);
297 | sendTransferEncodingHeader(out);
298 | sendEndOfHeader(out);
299 | sendData(out);
300 | sendEnd(out);
301 | }
302 |
303 |
304 | /**
305 | * Return the full length of all the data.
306 | * If you override this method make sure to override
307 | * #send(OutputStream) as well
308 | *
309 | * @return long The length.
310 | * @throws IOException If an IO problem occurs
311 | */
312 | public long length() throws IOException {
313 | if (lengthOfData() < 0) {
314 | return -1;
315 | }
316 | ByteArrayOutputStream overhead = new ByteArrayOutputStream();
317 | sendStart(overhead);
318 | sendDispositionHeader(overhead);
319 | sendContentTypeHeader(overhead);
320 | sendTransferEncodingHeader(overhead);
321 | sendEndOfHeader(overhead);
322 | sendEnd(overhead);
323 | return overhead.size() + lengthOfData();
324 | }
325 |
326 | /**
327 | * Return a string representation of this object.
328 | * @return A string representation of this object.
329 | * @see java.lang.Object#toString()
330 | */
331 | @Override
332 | public String toString() {
333 | return this.getName();
334 | }
335 |
336 | /**
337 | * Write all parts and the last boundary to the specified output stream.
338 | *
339 | * @param out The stream to write to.
340 | * @param parts The parts to write.
341 | *
342 | * @throws IOException If an I/O error occurs while writing the parts.
343 | */
344 | public static void sendParts(OutputStream out, final Part[] parts)
345 | throws IOException {
346 | sendParts(out, parts, DEFAULT_BOUNDARY_BYTES);
347 | }
348 |
349 | /**
350 | * Write all parts and the last boundary to the specified output stream.
351 | *
352 | * @param out The stream to write to.
353 | * @param parts The parts to write.
354 | * @param partBoundary The ASCII bytes to use as the part boundary.
355 | *
356 | * @throws IOException If an I/O error occurs while writing the parts.
357 | *
358 | * @since 3.0
359 | */
360 | public static void sendParts(OutputStream out, Part[] parts, byte[] partBoundary)
361 | throws IOException {
362 |
363 | if (parts == null) {
364 | throw new IllegalArgumentException("Parts may not be null");
365 | }
366 | if (partBoundary == null || partBoundary.length == 0) {
367 | throw new IllegalArgumentException("partBoundary may not be empty");
368 | }
369 | for (int i = 0; i < parts.length; i++) {
370 | // set the part boundary before the part is sent
371 | parts[i].setPartBoundary(partBoundary);
372 | parts[i].send(out);
373 | }
374 | out.write(EXTRA_BYTES);
375 | out.write(partBoundary);
376 | out.write(EXTRA_BYTES);
377 | out.write(CRLF_BYTES);
378 | }
379 |
380 | /**
381 | * Return the total sum of all parts and that of the last boundary
382 | *
383 | * @param parts The parts.
384 | * @return The total length
385 | *
386 | * @throws IOException If an I/O error occurs while writing the parts.
387 | */
388 | public static long getLengthOfParts(Part[] parts)
389 | throws IOException {
390 | return getLengthOfParts(parts, DEFAULT_BOUNDARY_BYTES);
391 | }
392 |
393 | /**
394 | * Gets the length of the multipart message including the given parts.
395 | *
396 | * @param parts The parts.
397 | * @param partBoundary The ASCII bytes to use as the part boundary.
398 | * @return The total length
399 | *
400 | * @throws IOException If an I/O error occurs while writing the parts.
401 | *
402 | * @since 3.0
403 | */
404 | public static long getLengthOfParts(Part[] parts, byte[] partBoundary) throws IOException {
405 | if (parts == null) {
406 | throw new IllegalArgumentException("Parts may not be null");
407 | }
408 | long total = 0;
409 | for (int i = 0; i < parts.length; i++) {
410 | // set the part boundary before we calculate the part's length
411 | parts[i].setPartBoundary(partBoundary);
412 | long l = parts[i].length();
413 | if (l < 0) {
414 | return -1;
415 | }
416 | total += l;
417 | }
418 | total += EXTRA_BYTES.length;
419 | total += partBoundary.length;
420 | total += EXTRA_BYTES.length;
421 | total += CRLF_BYTES.length;
422 | return total;
423 | }
424 | }
425 |
--------------------------------------------------------------------------------
/Example/src/com/android/http/multipart/PartBase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/PartBase.java,v 1.5 2004/04/18 23:51:37 jsdever Exp $
3 | * $Revision: 480424 $
4 | * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
5 | *
6 | * ====================================================================
7 | *
8 | * Licensed to the Apache Software Foundation (ASF) under one or more
9 | * contributor license agreements. See the NOTICE file distributed with
10 | * this work for additional information regarding copyright ownership.
11 | * The ASF licenses this file to You under the Apache License, Version 2.0
12 | * (the "License"); you may not use this file except in compliance with
13 | * the License. You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | * ====================================================================
23 | *
24 | * This software consists of voluntary contributions made by many
25 | * individuals on behalf of the Apache Software Foundation. For more
26 | * information on the Apache Software Foundation, please see
27 | * .
28 | *
29 | */
30 |
31 | package com.android.http.multipart;
32 |
33 |
34 | /**
35 | * Provides setters and getters for the basic Part properties.
36 | *
37 | * @author Michael Becke
38 | */
39 | public abstract class PartBase extends Part {
40 |
41 | /** Name of the file part. */
42 | private String name;
43 |
44 | /** Content type of the file part. */
45 | private String contentType;
46 |
47 | /** Content encoding of the file part. */
48 | private String charSet;
49 |
50 | /** The transfer encoding. */
51 | private String transferEncoding;
52 |
53 | /**
54 | * Constructor.
55 | *
56 | * @param name The name of the part
57 | * @param contentType The content type, or null
58 | * @param charSet The character encoding, or null
59 | * @param transferEncoding The transfer encoding, or null
60 | */
61 | public PartBase(String name, String contentType, String charSet, String transferEncoding) {
62 |
63 | if (name == null) {
64 | throw new IllegalArgumentException("Name must not be null");
65 | }
66 | this.name = name;
67 | this.contentType = contentType;
68 | this.charSet = charSet;
69 | this.transferEncoding = transferEncoding;
70 | }
71 |
72 | /**
73 | * Returns the name.
74 | * @return The name.
75 | * @see Part#getName()
76 | */
77 | @Override
78 | public String getName() {
79 | return this.name;
80 | }
81 |
82 | /**
83 | * Returns the content type of this part.
84 | * @return String The name.
85 | */
86 | @Override
87 | public String getContentType() {
88 | return this.contentType;
89 | }
90 |
91 | /**
92 | * Return the character encoding of this part.
93 | * @return String The name.
94 | */
95 | @Override
96 | public String getCharSet() {
97 | return this.charSet;
98 | }
99 |
100 | /**
101 | * Returns the transfer encoding of this part.
102 | * @return String The name.
103 | */
104 | @Override
105 | public String getTransferEncoding() {
106 | return transferEncoding;
107 | }
108 |
109 | /**
110 | * Sets the character encoding.
111 | *
112 | * @param charSet the character encoding, or null to exclude the character
113 | * encoding header
114 | */
115 | public void setCharSet(String charSet) {
116 | this.charSet = charSet;
117 | }
118 |
119 | /**
120 | * Sets the content type.
121 | *
122 | * @param contentType the content type, or null to exclude the content type header
123 | */
124 | public void setContentType(String contentType) {
125 | this.contentType = contentType;
126 | }
127 |
128 | /**
129 | * Sets the part name.
130 | *
131 | * @param name
132 | */
133 | public void setName(String name) {
134 | if (name == null) {
135 | throw new IllegalArgumentException("Name must not be null");
136 | }
137 | this.name = name;
138 | }
139 |
140 | /**
141 | * Sets the transfer encoding.
142 | *
143 | * @param transferEncoding the transfer encoding, or null to exclude the
144 | * transfer encoding header
145 | */
146 | public void setTransferEncoding(String transferEncoding) {
147 | this.transferEncoding = transferEncoding;
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/Example/src/com/android/http/multipart/PartSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/PartSource.java,v 1.6 2004/04/18 23:51:37 jsdever Exp $
3 | * $Revision: 480424 $
4 | * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
5 | *
6 | * ====================================================================
7 | *
8 | * Licensed to the Apache Software Foundation (ASF) under one or more
9 | * contributor license agreements. See the NOTICE file distributed with
10 | * this work for additional information regarding copyright ownership.
11 | * The ASF licenses this file to You under the Apache License, Version 2.0
12 | * (the "License"); you may not use this file except in compliance with
13 | * the License. You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | * ====================================================================
23 | *
24 | * This software consists of voluntary contributions made by many
25 | * individuals on behalf of the Apache Software Foundation. For more
26 | * information on the Apache Software Foundation, please see
27 | * .
28 | *
29 | */
30 |
31 | package com.android.http.multipart;
32 |
33 | import java.io.IOException;
34 | import java.io.InputStream;
35 |
36 | /**
37 | * An interface for providing access to data when posting MultiPart messages.
38 | *
39 | * @see FilePart
40 | *
41 | * @author Michael Becke
42 | *
43 | * @since 2.0
44 | */
45 | public interface PartSource {
46 |
47 | /**
48 | * Gets the number of bytes contained in this source.
49 | *
50 | * @return a value >= 0
51 | */
52 | long getLength();
53 |
54 | /**
55 | * Gets the name of the file this source represents.
56 | *
57 | * @return the fileName used for posting a MultiPart file part
58 | */
59 | String getFileName();
60 |
61 | /**
62 | * Gets a new InputStream for reading this source. This method can be
63 | * called more than once and should therefore return a new stream every
64 | * time.
65 | *
66 | * @return a new InputStream
67 | *
68 | * @throws IOException if an error occurs when creating the InputStream
69 | */
70 | InputStream createInputStream() throws IOException;
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/Example/src/com/android/http/multipart/StringPart.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/StringPart.java,v 1.11 2004/04/18 23:51:37 jsdever Exp $
3 | * $Revision: 480424 $
4 | * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
5 | *
6 | * ====================================================================
7 | *
8 | * Licensed to the Apache Software Foundation (ASF) under one or more
9 | * contributor license agreements. See the NOTICE file distributed with
10 | * this work for additional information regarding copyright ownership.
11 | * The ASF licenses this file to You under the Apache License, Version 2.0
12 | * (the "License"); you may not use this file except in compliance with
13 | * the License. You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | * ====================================================================
23 | *
24 | * This software consists of voluntary contributions made by many
25 | * individuals on behalf of the Apache Software Foundation. For more
26 | * information on the Apache Software Foundation, please see
27 | * .
28 | *
29 | */
30 |
31 | package com.android.http.multipart;
32 |
33 | import java.io.OutputStream;
34 | import java.io.IOException;
35 |
36 | import org.apache.http.util.EncodingUtils;
37 |
38 | /**
39 | * Simple string parameter for a multipart post
40 | *
41 | * @author Matthew Albright
42 | * @author Jeff Dever
43 | * @author Mike Bowler
44 | * @author Oleg Kalnichevski
45 | *
46 | * @since 2.0
47 | */
48 | public class StringPart extends PartBase {
49 | /** Default content encoding of string parameters. */
50 | public static final String DEFAULT_CONTENT_TYPE = "text/plain";
51 |
52 | /** Default charset of string parameters*/
53 | public static final String DEFAULT_CHARSET = "US-ASCII";
54 |
55 | /** Default transfer encoding of string parameters*/
56 | public static final String DEFAULT_TRANSFER_ENCODING = "8bit";
57 |
58 | /** Contents of this StringPart. */
59 | private byte[] content;
60 |
61 | /** The String value of this part. */
62 | private String value;
63 |
64 | /**
65 | * Constructor.
66 | *
67 | * @param name The name of the part
68 | * @param value the string to post
69 | * @param charset the charset to be used to encode the string, if null
70 | * the {@link #DEFAULT_CHARSET default} is used
71 | */
72 | public StringPart(String name, String value, String charset) {
73 |
74 | super(
75 | name,
76 | DEFAULT_CONTENT_TYPE,
77 | charset == null ? DEFAULT_CHARSET : charset,
78 | DEFAULT_TRANSFER_ENCODING
79 | );
80 | if (value == null) {
81 | throw new IllegalArgumentException("Value may not be null");
82 | }
83 | if (value.indexOf(0) != -1) {
84 | // See RFC 2048, 2.8. "8bit Data"
85 | throw new IllegalArgumentException("NULs may not be present in string parts");
86 | }
87 | this.value = value;
88 | }
89 |
90 | /**
91 | * Constructor.
92 | *
93 | * @param name The name of the part
94 | * @param value the string to post
95 | */
96 | public StringPart(String name, String value) {
97 | this(name, value, null);
98 | }
99 |
100 | /**
101 | * Gets the content in bytes. Bytes are lazily created to allow the charset to be changed
102 | * after the part is created.
103 | *
104 | * @return the content in bytes
105 | */
106 | private byte[] getContent() {
107 | if (content == null) {
108 | content = EncodingUtils.getBytes(value, getCharSet());
109 | }
110 | return content;
111 | }
112 |
113 | /**
114 | * Writes the data to the given OutputStream.
115 | * @param out the OutputStream to write to
116 | * @throws IOException if there is a write error
117 | */
118 | @Override
119 | protected void sendData(OutputStream out) throws IOException {
120 | out.write(getContent());
121 | }
122 |
123 | /**
124 | * Return the length of the data.
125 | * @return The length of the data.
126 | * @see Part#lengthOfData()
127 | */
128 | @Override
129 | protected long lengthOfData() {
130 | return getContent().length;
131 | }
132 |
133 | /* (non-Javadoc)
134 | * @see org.apache.commons.httpclient.methods.multipart.BasePart#setCharSet(java.lang.String)
135 | */
136 | @Override
137 | public void setCharSet(String charSet) {
138 | super.setCharSet(charSet);
139 | this.content = null;
140 | }
141 |
142 | }
143 |
--------------------------------------------------------------------------------
/Example/src/com/catchnotes/api/CatchAccount.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2011 Catch.com, Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | package com.catchnotes.api;
18 |
19 | /**
20 | * Represents a Catch account.
21 | *
22 | * Provides information such as user name, email address, account creation date, etc.
23 | */
24 | public class CatchAccount {
25 | public long id;
26 | public String email;
27 | public String username;
28 | public long accountCreatedOn;
29 | public String auth_token;
30 | public long periodLimit;
31 | public long periodUsage;
32 | public long periodStart;
33 | public long periodEnd;
34 | public long subscriptionEnd;
35 | public int accountLevel;
36 | public String accountDescription;
37 |
38 | public CatchAccount() {
39 | id = -1;
40 | email = "";
41 | username = "";
42 | accountCreatedOn = -1;
43 | auth_token = "";
44 | periodLimit = -1;
45 | periodUsage = -1;
46 | periodStart = -1;
47 | periodEnd = -1;
48 | subscriptionEnd = -1;
49 | accountLevel = -1;
50 | accountDescription = "";
51 | }
52 |
53 | public CatchAccount(long id, String email, String username, long accountCreatedOn, String auth_token, int accountLevel, String accountDescription, long monthlyLimit, long usage, long usageStart, long usageEnd, long subscriptionEnd) {
54 | this.id = id;
55 | this.email = email;
56 | this.username = username;
57 | this.accountCreatedOn = accountCreatedOn;
58 | this.auth_token = auth_token;
59 | this.periodLimit = monthlyLimit;
60 | this.periodUsage = usage;
61 | this.periodStart = usageStart;
62 | this.periodEnd = usageEnd;
63 | this.subscriptionEnd = subscriptionEnd;
64 | this.accountLevel = accountLevel;
65 | this.accountDescription = accountDescription;
66 | }
67 |
68 | @Override
69 | public String toString() {
70 | return
71 | "email=\"" + email + "\" " +
72 | "id=" + id + ' ' +
73 | "username=\"" + username + "\" " +
74 | "accountCreatedOn=" + accountCreatedOn + ' ' +
75 | "accountLevel=" + accountLevel + ' ' +
76 | "accountDescription=\"" + accountDescription + "\" " +
77 | "periodLimit=" + periodLimit + ' ' +
78 | "periodUsage=" + periodUsage + ' ' +
79 | "periodStart=" + periodStart + ' ' +
80 | "periodEnd=" + periodEnd + ' ' +
81 | "subscriptionEnd=" + subscriptionEnd + ' ' +
82 | "auth_token=" + auth_token;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/Example/src/com/catchnotes/api/CatchMedia.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2011 Catch.com, Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | package com.catchnotes.api;
18 |
19 | import java.io.File;
20 |
21 | /**
22 | * Represents a media item.
23 | */
24 | public class CatchMedia {
25 | public String id;
26 | public String note_id;
27 | public long created_at;
28 | public String content_type;
29 | public String src;
30 | public long size;
31 | public String filename;
32 | public boolean voice_hint;
33 | public File data;
34 |
35 | public CatchMedia() {
36 | id = "";
37 | note_id = "";
38 | created_at = 0;
39 | content_type = "";
40 | src = "";
41 | size = 0;
42 | data = null;
43 | filename = "";
44 | voice_hint = false;
45 | }
46 |
47 | public String toString() {
48 | return "apiId=" + id + " nodeId=" + note_id + " created_at=" + created_at +
49 | " type=" + content_type + " src=" + src + " size=" + size +
50 | " filename=" + filename + " voice_hint=" + voice_hint + " data=" +
51 | ((data == null) ? "null" : data.getPath());
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Example/src/com/catchnotes/api/CatchNote.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2011 Catch.com, Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | package com.catchnotes.api;
18 |
19 | import java.util.HashMap;
20 | import java.util.List;
21 | import java.util.Map;
22 |
23 | /**
24 | * Represents a note.
25 | */
26 | public class CatchNote {
27 | public static final String NOT_SET = "NOT_SET";
28 | public static final int NOT_SET_INT = -1;
29 | public static final String NODE_ID_NEVER_SYNCED = "-1";
30 | public static final String MODE_PRIVATE = "";
31 | public static final String MODE_SET_PRIVATE = "private";
32 | public static final String MODE_SHARED = "shared";
33 | public static final String MODE_PUBLIC = "public";
34 | public static final String DEFAULT_OWNER = "Me";
35 | public static final int PENDING_OPERATION_NONE = 0;
36 | public static final int PENDING_OPERATION_SYNC = 1;
37 | public static final int PENDING_OPERATION_DELETE = 2;
38 | private static final String STARRED_KEY = "starred";
39 |
40 | public String id;
41 | public long parentId;
42 | public String parentNodeId;
43 | public String source;
44 | public String sourceUrl;
45 | public CharSequence owner;
46 | public long ownerId;
47 | public long creationTime;
48 | public long modificationTime;
49 | public long reminderTime;
50 | public CharSequence text;
51 | public CharSequence summary;
52 | public long depth;
53 | public long children;
54 | public CharSequence mode;
55 | public CharSequence browserUrl;
56 |
57 | public double latitude;
58 | public double longitude;
59 | public double altitude;
60 | public double speed;
61 | public double bearing;
62 | public double accuracyPosition;
63 | public double accuracyAltitude;
64 | public long serverModifiedAt;
65 |
66 | public List tags;
67 | public List mediaList;
68 | public Map annotations;
69 | public int apiPendingOp;
70 |
71 | public CatchNote() {
72 | id = NODE_ID_NEVER_SYNCED;
73 | parentId = NOT_SET_INT;
74 | parentNodeId = NODE_ID_NEVER_SYNCED;
75 | source = NOT_SET;
76 | sourceUrl = NOT_SET;
77 | owner = NOT_SET;
78 | ownerId = NOT_SET_INT;
79 | creationTime = NOT_SET_INT;
80 | modificationTime = NOT_SET_INT;
81 | reminderTime = NOT_SET_INT;
82 | text = NOT_SET;
83 | summary = NOT_SET;
84 | depth = NOT_SET_INT;
85 | children = NOT_SET_INT;
86 | mode = MODE_PRIVATE;
87 | browserUrl = NOT_SET;
88 |
89 | latitude = 0;
90 | longitude = 0;
91 | altitude = 0;
92 | speed = 0;
93 | bearing = 0;
94 | accuracyPosition = 0;
95 | accuracyAltitude = 0;
96 | serverModifiedAt = 0;
97 | apiPendingOp = PENDING_OPERATION_NONE;
98 |
99 | tags = null;
100 | mediaList = null;
101 | annotations = null;
102 | }
103 |
104 | /**
105 | * Return tags contained within note.
106 | *
107 | * @return Tags in note separated by spaces.
108 | */
109 | public CharSequence getTags() {
110 | if (tags == null) {
111 | return "";
112 | }
113 |
114 | StringBuffer sb = new StringBuffer();
115 |
116 | for (CharSequence tag : tags) {
117 | sb.append(tag + " ");
118 | }
119 |
120 | return sb.toString().trim();
121 | }
122 |
123 | /**
124 | * Copy a given note.
125 | *
126 | * @param note The note to copy.
127 | */
128 | public void copy(CatchNote note) {
129 | if (note != null) {
130 | this.id = note.id;
131 | this.parentId = note.parentId;
132 | this.owner = note.owner;
133 | this.ownerId = note.ownerId;
134 | this.creationTime = note.creationTime;
135 | this.modificationTime = note.modificationTime;
136 | this.reminderTime = note.reminderTime;
137 | this.text = note.text;
138 | this.summary = note.summary;
139 | this.depth = note.depth;
140 | this.children = note.children;
141 | this.mode = note.mode;
142 | this.browserUrl = note.browserUrl;
143 | this.source = note.source;
144 | this.sourceUrl = note.sourceUrl;
145 |
146 | this.latitude = note.latitude;
147 | this.longitude = note.longitude;
148 | this.altitude = note.altitude;
149 | this.speed = note.speed;
150 | this.bearing = note.bearing;
151 | this.accuracyPosition = note.accuracyPosition;
152 | this.accuracyAltitude = note.accuracyAltitude;
153 | this.serverModifiedAt = note.serverModifiedAt;
154 | this.apiPendingOp = note.apiPendingOp;
155 |
156 | this.tags = note.tags;
157 | this.mediaList = note.mediaList;
158 | this.annotations = note.annotations;
159 | }
160 | }
161 |
162 | /**
163 | * Turn note into a string of key : values.
164 | */
165 | @Override
166 | public String toString() {
167 | return
168 | "id:" + id +
169 | " parent_id:" + parentId +
170 | " parentNodeId:" + parentNodeId +
171 | " owner:" + owner +
172 | " ownerId:" + ownerId +
173 | " creationTime:" + creationTime +
174 | " modificationTime:" + modificationTime +
175 | " reminderTime:" + reminderTime +
176 | " text:" + text +
177 | " summary:" + summary +
178 | " depth:" + depth +
179 | " children:" + children +
180 | " mode: " + mode +
181 | " browserUrl: " + browserUrl +
182 | " source: " + source +
183 | " sourceUrl: " + sourceUrl +
184 | " latitude:" + latitude +
185 | " longitude:" + longitude +
186 | " altitude:" + altitude +
187 | " speed:" + speed +
188 | " bearing:" + bearing +
189 | " accuracyPosition:" + accuracyPosition +
190 | " accuracyAltitude:" + accuracyAltitude +
191 | " serverModifiedAt:" + serverModifiedAt +
192 | " tags:" + getTags() +
193 | " mediaList:" + mediaList +
194 | " annotations: " + annotations;
195 | }
196 |
197 | public CatchNote(Builder builder) {
198 | this.id = builder.id;
199 | this.parentId = builder.parentId;
200 | this.parentNodeId = builder.parentNodeId;
201 | this.owner = builder.owner;
202 | this.ownerId = builder.ownerId;
203 | this.creationTime = builder.creationTime;
204 | this.modificationTime = builder.modificationTime;
205 | this.reminderTime = builder.reminderTime;
206 | this.text = builder.text;
207 | this.summary = builder.summary;
208 | this.depth = builder.depth;
209 | this.children = builder.children;
210 | this.mode = builder.mode;
211 | this.browserUrl = builder.publicUrl;
212 | this.source = builder.source;
213 | this.sourceUrl = builder.sourceUrl;
214 |
215 | this.latitude = builder.latitude;
216 | this.longitude = builder.longitude;
217 | this.altitude = builder.altitude;
218 | this.speed = builder.speed;
219 | this.bearing = builder.bearing;
220 | this.accuracyPosition = builder.accuracyPosition;
221 | this.accuracyAltitude = builder.accuracyAltitude;
222 | this.serverModifiedAt = builder.serverModifiedAt;
223 | this.apiPendingOp = builder.apiPendingOp;
224 |
225 | this.tags = builder.tags;
226 | this.mediaList = builder.mediaList;
227 | this.annotations = builder.annotations;
228 | }
229 |
230 | public static class Builder {
231 | private String id;
232 | private long parentId;
233 | private String parentNodeId;
234 | private String source;
235 | private String sourceUrl;
236 | private CharSequence owner;
237 | private long ownerId;
238 | private long creationTime;
239 | private long modificationTime;
240 | private long reminderTime;
241 | private CharSequence text;
242 | private CharSequence summary;
243 | private long depth;
244 | private long children;
245 | private CharSequence mode;
246 | private CharSequence publicUrl;
247 |
248 | private double latitude;
249 | private double longitude;
250 | private double altitude;
251 | private double speed;
252 | private double bearing;
253 | private double accuracyPosition;
254 | private double accuracyAltitude;
255 | private long serverModifiedAt;
256 |
257 | private List tags;
258 | private List mediaList;
259 | private int apiPendingOp;
260 | private Map annotations;
261 |
262 | public Builder id(String id) {
263 | this.id = id;
264 | return this;
265 | }
266 |
267 | public Builder parentId(long parentId) {
268 | this.parentId = parentId;
269 | return this;
270 | }
271 |
272 | public Builder parentNodeId(String parentNodeId) {
273 | this.parentNodeId = parentNodeId;
274 | return this;
275 | }
276 |
277 | public Builder source(String source) {
278 | this.source = source;
279 | return this;
280 | }
281 |
282 | public Builder sourceUrl(String sourceUrl) {
283 | this.sourceUrl = sourceUrl;
284 | return this;
285 | }
286 |
287 | public Builder owner(CharSequence owner) {
288 | this.owner = owner;
289 | return this;
290 | }
291 |
292 | public Builder ownerId(long ownerId) {
293 | this.ownerId = ownerId;
294 | return this;
295 | }
296 |
297 | public Builder creationTime(long creationTime) {
298 | this.creationTime = creationTime;
299 | return this;
300 | }
301 |
302 | public Builder modificationTime(long modificationTime) {
303 | this.modificationTime = modificationTime;
304 | return this;
305 | }
306 |
307 | public Builder reminderTime(long reminderTime) {
308 | this.reminderTime = reminderTime;
309 | return this;
310 | }
311 |
312 | public Builder text(CharSequence text) {
313 | this.text = text;
314 | return this;
315 | }
316 |
317 | public Builder summary(CharSequence summary) {
318 | this.summary = summary;
319 | return this;
320 | }
321 |
322 | public Builder depth(long depth) {
323 | this.depth = depth;
324 | return this;
325 | }
326 |
327 | public Builder children(long children) {
328 | this.children = children;
329 | return this;
330 | }
331 |
332 | public Builder mode(CharSequence mode) {
333 | this.mode = mode;
334 | return this;
335 | }
336 |
337 | public Builder publicUrl(CharSequence publicUrl) {
338 | this.publicUrl = publicUrl;
339 | return this;
340 | }
341 |
342 | public Builder latitude(double latitude) {
343 | this.latitude = latitude;
344 | return this;
345 | }
346 |
347 | public Builder longitude(double longitude) {
348 | this.longitude = longitude;
349 | return this;
350 | }
351 |
352 | public Builder altitude(double altitude) {
353 | this.altitude = altitude;
354 | return this;
355 | }
356 |
357 | public Builder speed(double speed) {
358 | this.speed = speed;
359 | return this;
360 | }
361 |
362 | public Builder bearing(double bearing) {
363 | this.bearing = bearing;
364 | return this;
365 | }
366 |
367 | public Builder accuracyPosition(double accuracyPosition) {
368 | this.accuracyPosition = accuracyPosition;
369 | return this;
370 | }
371 |
372 | public Builder accuracyAltitude(double accuracyAltitude) {
373 | this.accuracyAltitude = accuracyAltitude;
374 | return this;
375 | }
376 |
377 | public Builder serverModifiedAt(long serverModifiedAt) {
378 | this.serverModifiedAt = serverModifiedAt;
379 | return this;
380 | }
381 |
382 | public Builder labels(List tags) {
383 | this.tags = tags;
384 | return this;
385 | }
386 |
387 | public Builder mediaList(List mediaList) {
388 | this.mediaList = mediaList;
389 | return this;
390 | }
391 |
392 | public Builder apiPendingOp(int apiPendingOp) {
393 | this.apiPendingOp = apiPendingOp;
394 | return this;
395 | }
396 |
397 | public Builder annotations(Map annotations) {
398 | this.annotations = annotations;
399 | return this;
400 | }
401 |
402 | public Builder annotationStarred(int annotationStarred) {
403 | if (annotationStarred == NOT_SET_INT) {
404 | return this;
405 | }
406 | if (this.annotations == null) {
407 | annotations = new HashMap();
408 | annotations.put(STARRED_KEY, Boolean.toString(annotationStarred == 1));
409 | }
410 | return this;
411 | }
412 |
413 | public CatchNote build() {
414 | return new CatchNote(this);
415 | }
416 | }
417 | }
418 |
--------------------------------------------------------------------------------
/Example/src/com/catchnotes/api/CatchNoteRef.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2011 Catch.com, Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | package com.catchnotes.api;
18 |
19 | /**
20 | * References a note by ID and server modification timestamp.
21 | */
22 | public class CatchNoteRef {
23 | public String nodeId;
24 | public String serverModified;
25 |
26 | public CatchNoteRef() {
27 | }
28 |
29 | public CatchNoteRef(String nodeId, String serverModified) {
30 | this.nodeId = nodeId;
31 | this.serverModified = serverModified;
32 | }
33 |
34 | @Override
35 | public String toString() {
36 | return "[ nodeId=" + nodeId + " serverModified=" + serverModified + " ]";
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Example/src/com/catchnotes/api/CatchNotesXmlParser.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2011 Catch.com, Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | package com.catchnotes.api;
18 |
19 | import java.io.IOException;
20 | import java.text.ParseException;
21 | import java.text.SimpleDateFormat;
22 | import java.util.ArrayList;
23 | import java.util.Date;
24 | import java.util.HashMap;
25 | import java.util.List;
26 | import java.util.TimeZone;
27 |
28 | import org.apache.http.HttpResponse;
29 | import org.xmlpull.v1.XmlPullParser;
30 | import org.xmlpull.v1.XmlPullParserException;
31 | import org.xmlpull.v1.XmlPullParserFactory;
32 |
33 | import android.os.Build;
34 | import android.text.format.Time;
35 | import android.util.Log;
36 | import android.util.TimeFormatException;
37 |
38 | public class CatchNotesXmlParser {
39 | public static final long ERROR_RESPONSE_NULL = -1;
40 | public static final long ERROR_PARAMETERS_NULL = -2;
41 |
42 | private static final String XML_TAG_NOTES = "notes";
43 | private static final String XML_TAG_NOTE = "note";
44 | private static final String XML_TAG_CREATED = "created_at";
45 | private static final String XML_TAG_MODIFIED = "modified_at";
46 | private static final String XML_TAG_REMINDER = "reminder_at";
47 | private static final String XML_TAG_SERVER_MODIFIED = "server_modified_at";
48 | private static final String XML_TAG_ID = "id";
49 | private static final String XML_TAG_SOURCE = "source";
50 | private static final String XML_TAG_SOURCE_URL = "source_url";
51 | private static final String XML_TAG_TEXT = "text";
52 | private static final String XML_TAG_SUMMARY = "summary";
53 | private static final String XML_TAG_USER = "user";
54 | private static final String XML_TAG_USER_NAME = "user_name";
55 | private static final String XML_TAG_COMMENTS = "comments";
56 | private static final String XML_TAG_COMMENT = "comment";
57 | private static final String XML_TAG_MODE = "mode";
58 | private static final String XML_TAG_BROWSER_URL = "browser_url";
59 | private static final String XML_TAG_TAGS = "tags";
60 | private static final String XML_TAG_TAG = "tag";
61 | private static final String XML_TAG_MEDIA_LIST = "media_list";
62 | private static final String XML_TAG_MEDIA = "media";
63 | private static final String XML_TAG_CONTENT_TYPE = "type";
64 | private static final String XML_TAG_SRC = "src";
65 | private static final String XML_TAG_SIZE = "size";
66 | private static final String XML_TAG_FILENAME = "filename";
67 | private static final String XML_TAG_VOICE_HINT = "voicenote_hint";
68 | private static final String XML_TAG_LOCATION = "location";
69 | private static final String XML_TAG_LATITUDE = "latitude";
70 | private static final String XML_TAG_LONGITUDE = "longitude";
71 | private static final String XML_TAG_ALTITUDE = "altitude";
72 | private static final String XML_TAG_SPEED = "speed";
73 | private static final String XML_TAG_BEARING = "bearing";
74 | private static final String XML_TAG_ACCURACY_POSITION = "accuracy_position";
75 | private static final String XML_TAG_ACCURACY_ALTITUDE = "accuracy_altitude";
76 |
77 | // Enable this for extra API call tracing output in the logcat.
78 | private static final boolean PARSE_TRACING_OUTPUT_ENABLED = false;
79 | private static final String LOGCAT_NAME = "CatchParser";
80 | public static final String CATCH_NAMESPACE_PREFIX = "catch";
81 |
82 | private Time timestamper;
83 | private SimpleDateFormat rfc3339;
84 |
85 | public CatchNotesXmlParser() {
86 | try {
87 | if (Integer.parseInt(Build.VERSION.SDK) >= Build.VERSION_CODES.ECLAIR_0_1) {
88 | // We can use Time & TimeFormatException on Android 2.0.1
89 | // (API level 6) or greater. It crashes the VM otherwise.
90 | timestamper = new Time();
91 | }
92 | } catch (Exception e) { }
93 | }
94 |
95 | public void parseSyncV2XML(HttpResponse response, List noteRefs)
96 | throws XmlPullParserException, IOException, IllegalArgumentException {
97 | if (response == null || noteRefs == null) {
98 | throw new IllegalArgumentException();
99 | }
100 |
101 | XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
102 | XmlPullParser parser = factory.newPullParser();
103 | parser.setInput(response.getEntity().getContent(), null);
104 |
105 | int eventType = parser.getEventType();
106 |
107 | String startTag;
108 | String endTag;
109 | String nextText = "";
110 |
111 | while (eventType != XmlPullParser.END_DOCUMENT) {
112 | if (eventType == XmlPullParser.START_DOCUMENT) {
113 | parse_trace("Beginning XML pullparse.");
114 | } else if (eventType == XmlPullParser.START_TAG) {
115 | startTag = parser.getName();
116 |
117 | if (XML_TAG_NOTES.equals(startTag)) {
118 | parse_trace("Parsing noteRefs.");
119 | } else if (XML_TAG_NOTE.equals(startTag)) {
120 | parse_trace("Parsing a note.");
121 | CatchNoteRef noteRef = new CatchNoteRef();
122 |
123 | while (eventType != XmlPullParser.END_DOCUMENT) {
124 | if (eventType == XmlPullParser.START_TAG) {
125 | startTag = parser.getName();
126 |
127 | // one-liners:
128 | if (XML_TAG_ID.equals(startTag)) {
129 | nextText = parser.nextText();
130 | noteRef.nodeId = nextText;
131 | parse_trace("Note ID is " + noteRef.nodeId);
132 | } else if (XML_TAG_SERVER_MODIFIED.equals(startTag)) {
133 | nextText = parser.nextText();
134 | noteRef.serverModified = nextText;
135 | parse_trace("Server modification time is " + noteRef.serverModified);
136 | }
137 | } else if (eventType == XmlPullParser.END_TAG) {
138 | endTag = parser.getName();
139 |
140 | if (XML_TAG_NOTE.equals(endTag)) {
141 | parse_trace("Parsing noteRef complete.");
142 | break;
143 | }
144 | }
145 |
146 | eventType = parser.next();
147 | }
148 |
149 | noteRefs.add(noteRef);
150 | } else {
151 | parse_trace("(parseSyncV2XML) unknown XML tag: <" + startTag + ">");
152 | }
153 | } else if (eventType == XmlPullParser.END_TAG) {
154 | endTag = parser.getName();
155 |
156 | if (XML_TAG_NOTES.equals(endTag)) {
157 | parse_trace("Parsed " + noteRefs.size() + " noteRefs.");
158 | }
159 | }
160 |
161 | eventType = parser.next();
162 | }
163 | }
164 |
165 | public void parseNotesXml(HttpResponse response,
166 | ArrayList notes, long parentId)
167 | throws XmlPullParserException, IOException, IllegalArgumentException {
168 | if (response == null || notes == null) {
169 | throw new IllegalArgumentException();
170 | }
171 |
172 | XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
173 | factory.setNamespaceAware(true);
174 | XmlPullParser parser = factory.newPullParser();
175 | parser.setInput(response.getEntity().getContent(), null);
176 |
177 | int eventType = parser.getEventType();
178 |
179 | while (eventType != XmlPullParser.END_DOCUMENT) {
180 | if (eventType == XmlPullParser.START_DOCUMENT) {
181 | parse_trace("Beginning XML pullparse.");
182 | } else if (eventType == XmlPullParser.START_TAG) {
183 | String startTag = parser.getName();
184 |
185 | if (XML_TAG_NOTES.equals(startTag)) {
186 | parse_trace("Parsing notes.");
187 | } else if (XML_TAG_NOTE.equals(startTag)) {
188 | parse_trace("Parsing a note.");
189 | parseNote(parser, notes, parentId);
190 | } else {
191 | parse_trace("(parseNotesXml) unknown XML tag: <" + startTag + ">");
192 | }
193 | } else if (eventType == XmlPullParser.END_TAG) {
194 | String endTag = parser.getName();
195 |
196 | if (XML_TAG_NOTES.equals(endTag)) {
197 | parse_trace("Parsed " + notes.size() + " notes.");
198 | }
199 | }
200 |
201 | eventType = parser.next();
202 | }
203 | }
204 |
205 | private void parseNote(XmlPullParser parser,
206 | ArrayList returnVal, long parentId)
207 | throws XmlPullParserException, IOException {
208 | // Create a blank note object
209 | CatchNote note = new CatchNote();
210 | returnVal.add(note);
211 | note.parentId = parentId;
212 | int eventType = parser.next();
213 |
214 | while (eventType != XmlPullParser.END_DOCUMENT) {
215 | if (eventType == XmlPullParser.START_TAG) {
216 | String startTag = parser.getName();
217 | String nextText = "";
218 |
219 | if (parser.getNamespace().equals(XmlPullParser.NO_NAMESPACE)) { // default properties
220 | // one-liners:
221 | if (XML_TAG_ID.equals(startTag)) {
222 | nextText = parser.nextText();
223 | note.id = nextText;
224 | parse_trace("Note ID is " + note.id);
225 | } else if (XML_TAG_SOURCE.equals(startTag)) {
226 | nextText = parser.nextText();
227 | note.source = nextText;
228 | parse_trace("Note source is " + note.source);
229 | } else if (XML_TAG_SOURCE_URL.equals(startTag)) {
230 | nextText = parser.nextText();
231 | note.sourceUrl = nextText;
232 | parse_trace("Note source URL is " + note.sourceUrl);
233 | } else if (XML_TAG_CREATED.equals(startTag)) {
234 | nextText = parser.nextText();
235 | note.creationTime = parse3339(nextText);
236 | parse_trace("Creation time is " + nextText + " (" +
237 | note.creationTime + ')');
238 | } else if (XML_TAG_MODIFIED.equals(startTag)) {
239 | nextText = parser.nextText();
240 | note.modificationTime = parse3339(nextText);
241 | parse_trace("Modification time is " + nextText +
242 | " (" + note.modificationTime + ')');
243 | } else if (XML_TAG_REMINDER.equals(startTag)) {
244 | nextText = parser.nextText();
245 | note.reminderTime = parse3339(nextText);
246 | parse_trace("Reminder time is " + nextText + " (" +
247 | note.reminderTime + ')');
248 | } else if (XML_TAG_SERVER_MODIFIED.equals(startTag)) {
249 | nextText = parser.nextText();
250 | note.serverModifiedAt= parse3339(nextText);
251 | parse_trace("ServerModifiedAt time is " + nextText + " (" +
252 | note.serverModifiedAt + ')');
253 | } else if (XML_TAG_TEXT.equals(startTag)) {
254 | nextText = parser.nextText();
255 | note.text = nextText;
256 | parse_trace("Note text is \"" + note.text + '"');
257 | } else if (XML_TAG_SUMMARY.equals(startTag)) {
258 | nextText = parser.nextText();
259 | note.summary = nextText;
260 | parse_trace("Note summary is \"" + note.summary + '"');
261 | } else if (XML_TAG_COMMENTS.equals(startTag)) {
262 | note.children = 0;
263 |
264 | while (eventType != XmlPullParser.END_DOCUMENT) {
265 | if (eventType == XmlPullParser.START_TAG) {
266 | startTag = parser.getName();
267 |
268 | if (XML_TAG_COMMENT.equals(startTag)) {
269 | note.children++;
270 | parse_trace("found comment");
271 | }
272 | } else if (eventType == XmlPullParser.END_TAG) {
273 | String endTag = parser.getName();
274 |
275 | if (XML_TAG_COMMENTS.equals(endTag)) {
276 | parse_trace("Parsing comments complete.");
277 | break;
278 | }
279 | }
280 |
281 | eventType = parser.next();
282 | }
283 |
284 | parse_trace("Comment count is " + note.children);
285 | } else if (XML_TAG_MODE.equals(startTag)) {
286 | nextText = parser.nextText();
287 | note.mode = nextText;
288 | parse_trace("Mode is " + note.mode);
289 | } else if (XML_TAG_BROWSER_URL.equals(startTag)) {
290 | nextText = parser.nextText();
291 | note.browserUrl = nextText;
292 | parse_trace("Browser URL is " + note.browserUrl);
293 | }
294 | // new blocks:
295 | else if (XML_TAG_USER.equals(startTag)) {
296 | parse_trace("Parsing note owner data.");
297 | parseNoteOwner(parser, note);
298 | } else if (XML_TAG_TAGS.equals(startTag)) {
299 | parse_trace("Parsing note tags.");
300 | parseTags(parser, note);
301 | } else if (XML_TAG_LOCATION.equals(startTag)) {
302 | parse_trace("Parsing geotag.");
303 | parseLocation(parser, note);
304 | } else if (XML_TAG_MEDIA_LIST.equals(startTag)) {
305 | parse_trace("Parsing media list.");
306 | parseMediaList(parser, note);
307 | } else {
308 | parse_trace("(parseNote) unknown XML tag: <" + startTag + ">");
309 | }
310 | } else if (parser.getPrefix().equals(CATCH_NAMESPACE_PREFIX)) { // XXXaes. use full path once we fix server side uris
311 | parse_trace("Parsing annotation.");
312 | if (note.annotations == null) {
313 | note.annotations = new HashMap();
314 | }
315 | note.annotations.put(startTag, parser.nextText());
316 | }
317 | } else if (eventType == XmlPullParser.END_TAG) {
318 | String endTag = parser.getName();
319 |
320 | if (XML_TAG_NOTE.equals(endTag)) {
321 | parse_trace("Parsing note complete.");
322 | break;
323 | }
324 | }
325 |
326 | eventType = parser.next();
327 | }
328 | }
329 |
330 | private void parseTags(XmlPullParser parser, CatchNote note)
331 | throws XmlPullParserException, IOException {
332 | ArrayList tags = new ArrayList();
333 | int eventType = parser.next();
334 |
335 | while (eventType != XmlPullParser.END_DOCUMENT) {
336 | if (eventType == XmlPullParser.START_TAG) {
337 | String startTag = parser.getName();
338 |
339 | if (XML_TAG_TAG.equals(startTag)) {
340 | String tag = parser.nextText();
341 | tags.add(tag);
342 | parse_trace("Added tag \"" + tag + '"');
343 | } else {
344 | parse_trace("(parseTags) unknown XML tag: <" + startTag + ">");
345 | }
346 | } else if (eventType == XmlPullParser.END_TAG) {
347 | String endTag = parser.getName();
348 |
349 | if (XML_TAG_TAGS.equals(endTag)) {
350 | note.tags = tags;
351 | parse_trace("Note had " + note.tags.size()
352 | + " tag(s).");
353 | break;
354 | }
355 | }
356 |
357 | eventType = parser.next();
358 | }
359 | }
360 |
361 | private void parseMediaList(XmlPullParser parser, CatchNote note)
362 | throws XmlPullParserException, IOException {
363 | int eventType = parser.next();
364 |
365 | while (eventType != XmlPullParser.END_DOCUMENT) {
366 | if (eventType == XmlPullParser.START_TAG) {
367 | String startTag = parser.getName();
368 |
369 | if (XML_TAG_MEDIA.equals(startTag)) {
370 | parse_trace("Parsing a media item.");
371 | parseMedia(parser, note);
372 | } else {
373 | parse_trace("(parseMediaList) unknown XML tag: <" + startTag + ">");
374 | }
375 | } else if (eventType == XmlPullParser.END_TAG) {
376 | String endTag = parser.getName();
377 |
378 | if (XML_TAG_MEDIA_LIST.equals(endTag)) {
379 | parse_trace("Parsing media list complete.");
380 | break;
381 | }
382 | }
383 |
384 | eventType = parser.next();
385 | }
386 | }
387 |
388 | private void parseMedia(XmlPullParser parser, CatchNote note)
389 | throws XmlPullParserException, IOException {
390 | CatchMedia media = new CatchMedia();
391 | media.note_id = note.id;
392 | int eventType = parser.next();
393 |
394 | while (eventType != XmlPullParser.END_DOCUMENT) {
395 | if (eventType == XmlPullParser.START_TAG) {
396 | String startTag = parser.getName();
397 | String nextText = "";
398 |
399 | if (XML_TAG_SRC.equals(startTag)) {
400 | nextText = parser.nextText();
401 | media.src = nextText;
402 | parse_trace("Source = " + media.src);
403 | } else if (XML_TAG_ID.equals(startTag)) {
404 | nextText = parser.nextText();
405 | media.id = nextText;
406 | parse_trace("API ID = " + media.id);
407 | } else if (XML_TAG_CREATED.equals(startTag)) {
408 | nextText = parser.nextText();
409 | media.created_at = parse3339(nextText);
410 | parse_trace("Creation time = " + nextText + " (" + media.created_at + ')');
411 | } else if (XML_TAG_CONTENT_TYPE.equals(startTag)) {
412 | nextText = parser.nextText();
413 | media.content_type = nextText;
414 | parse_trace("Type = " + media.content_type);
415 | } else if (XML_TAG_SIZE.equals(startTag)) {
416 | try {
417 | nextText = parser.nextText();
418 | long size = Long.parseLong(nextText);
419 | media.size = size;
420 | } catch (NumberFormatException nfe) {
421 | Log.e(LOGCAT_NAME, "unable to parse value for media size: \"" + nextText + '"');
422 | media.size = 0;
423 | }
424 |
425 | parse_trace("Size = " + media.size);
426 | } else if (XML_TAG_VOICE_HINT.equals(startTag)) {
427 | nextText = parser.nextText();
428 | media.voice_hint = Boolean.parseBoolean(nextText);
429 | parse_trace("voice hint = " + media.voice_hint);
430 | } else if (XML_TAG_FILENAME.equals(startTag)) {
431 | nextText = parser.nextText();
432 | media.filename = nextText;
433 | parse_trace("Filename = " + media.filename);
434 | } else {
435 | parse_trace("(parseMedia) unknown XML tag: <" + startTag + ">");
436 | }
437 | } else if (eventType == XmlPullParser.END_TAG) {
438 | String endTag = parser.getName();
439 |
440 | if (XML_TAG_MEDIA.equals(endTag)) {
441 | if (note.mediaList == null) {
442 | note.mediaList = new ArrayList();
443 | }
444 |
445 | note.mediaList.add(media);
446 | parse_trace("Parsing media item complete.");
447 | break;
448 | }
449 | }
450 |
451 | eventType = parser.next();
452 | }
453 | }
454 |
455 | private void parseNoteOwner(XmlPullParser parser, CatchNote note)
456 | throws XmlPullParserException, IOException {
457 | int eventType = parser.next();
458 |
459 | while (eventType != XmlPullParser.END_DOCUMENT) {
460 | if (eventType == XmlPullParser.START_TAG) {
461 | String startTag = parser.getName();
462 | String nextText = "";
463 |
464 | if (XML_TAG_ID.equals(startTag)) {
465 | try {
466 | nextText = parser.nextText();
467 | long ownerId = Long.parseLong(nextText);
468 | note.ownerId = ownerId;
469 | } catch (NumberFormatException nfe) {
470 | Log.e(LOGCAT_NAME, "unable to parse value for note owner ID: \"" + nextText + '"');
471 | note.ownerId = 0;
472 | }
473 |
474 | parse_trace("Owner ID = " + note.ownerId);
475 | } else if (XML_TAG_USER_NAME.equals(startTag)) {
476 | String owner = parser.nextText();
477 | note.owner = owner;
478 | parse_trace("Owner name = " + note.owner);
479 | } else {
480 | parse_trace("(parseNoteOwner) unknown XML tag: <" + startTag + ">");
481 | }
482 | } else if (eventType == XmlPullParser.END_TAG) {
483 | String endTag = parser.getName();
484 |
485 | if (XML_TAG_USER.equals(endTag)) {
486 | parse_trace("Parsing owner data complete.");
487 | break;
488 | }
489 | }
490 |
491 | eventType = parser.next();
492 | }
493 | }
494 |
495 | private void parseLocation(XmlPullParser parser, CatchNote note)
496 | throws XmlPullParserException, IOException {
497 | int eventType = parser.next();
498 |
499 | while (eventType != XmlPullParser.END_DOCUMENT) {
500 | if (eventType == XmlPullParser.START_TAG) {
501 | String startTag = parser.getName();
502 | String nextText = "";
503 |
504 | if (XML_TAG_LATITUDE.equals(startTag)) {
505 | try {
506 | nextText = parser.nextText();
507 | double latitude = Double.parseDouble(nextText);
508 | note.latitude = latitude;
509 | } catch (NumberFormatException nfe) {
510 | Log.e(LOGCAT_NAME, "unable to parse value for latitude: \"" + nextText + '"');
511 | note.latitude = 0.0;
512 | }
513 |
514 | parse_trace("Latitude = " + note.latitude);
515 | } else if (XML_TAG_LONGITUDE.equals(startTag)) {
516 | try {
517 | nextText = parser.nextText();
518 | double longitude = Double.parseDouble(nextText);
519 | note.longitude = longitude;
520 | } catch (NumberFormatException nfe) {
521 | Log.e(LOGCAT_NAME, "unable to parse value for longitude: \"" + nextText + '"');
522 | note.longitude = 0.0;
523 | }
524 |
525 | parse_trace("Longitude = " + note.longitude);
526 | } else if (XML_TAG_ALTITUDE.equals(startTag)) {
527 | try {
528 | nextText = parser.nextText();
529 | double altitude = Double.parseDouble(nextText);
530 | note.altitude = altitude;
531 | } catch (NumberFormatException nfe) {
532 | Log.e(LOGCAT_NAME, "unable to parse value for altitude: \"" + nextText + '"');
533 | note.altitude = 0.0;
534 | }
535 |
536 | parse_trace("Altitude = " + note.altitude);
537 | } else if (XML_TAG_SPEED.equals(startTag)) {
538 | try {
539 | nextText = parser.nextText();
540 | double speed = Double.parseDouble(nextText);
541 | note.speed = speed;
542 | } catch (NumberFormatException nfe) {
543 | Log.e(LOGCAT_NAME, "unable to parse value for speed: \"" + nextText + '"');
544 | note.speed = 0.0;
545 | }
546 |
547 | parse_trace("Speed = " + note.speed);
548 | } else if (XML_TAG_BEARING.equals(startTag)) {
549 | try {
550 | nextText = parser.nextText();
551 | double bearing = Double.parseDouble(nextText);
552 | note.bearing = bearing;
553 | } catch (NumberFormatException nfe) {
554 | Log.e(LOGCAT_NAME, "unable to parse value for bearing: \"" + nextText + '"');
555 | note.bearing = 0.0;
556 | }
557 |
558 | parse_trace("Bearing = " + note.bearing);
559 | } else if (XML_TAG_ACCURACY_POSITION.equals(startTag)) {
560 | try {
561 | nextText = parser.nextText();
562 | double accuracyPosition = Double.parseDouble(nextText);
563 | note.accuracyPosition = accuracyPosition;
564 | } catch (NumberFormatException nfe) {
565 | Log.e(LOGCAT_NAME, "unable to parse value for accuracyPosition: \"" + nextText + '"');
566 | note.accuracyPosition = 0.0;
567 | }
568 |
569 | parse_trace("Positional accuracy = "
570 | + note.accuracyPosition);
571 | } else if (XML_TAG_ACCURACY_ALTITUDE.equals(startTag)) {
572 | try {
573 | nextText = parser.nextText();
574 | double accuracyAltitude = Double.parseDouble(nextText);
575 | note.accuracyAltitude = accuracyAltitude;
576 | } catch (NumberFormatException nfe) {
577 | Log.e(LOGCAT_NAME, "unable to parse value for accuracyAltitude: \"" + nextText + '"');
578 | note.accuracyAltitude = 0.0;
579 | }
580 |
581 | parse_trace("Altitude accuracy = "
582 | + note.accuracyAltitude);
583 | } else {
584 | parse_trace("(parseLocation) unknown XML tag: <" + startTag + ">");
585 | }
586 | } else if (eventType == XmlPullParser.END_TAG) {
587 | String endTag = parser.getName();
588 |
589 | if (XML_TAG_LOCATION.equals(endTag)) {
590 | parse_trace("Parsing geotag complete.");
591 | break;
592 | }
593 | }
594 |
595 | eventType = parser.next();
596 | }
597 | }
598 |
599 | private void parse_trace(String msg) {
600 | if (PARSE_TRACING_OUTPUT_ENABLED) {
601 | Log.d(LOGCAT_NAME, msg);
602 | }
603 | }
604 |
605 | private synchronized long parse3339(String time) {
606 | if (time == null || time.length() == 0) {
607 | return 0;
608 | }
609 |
610 | if (timestamper != null) {
611 | try {
612 | timestamper.parse3339(time);
613 | } catch (TimeFormatException e) {
614 | Log.e(LOGCAT_NAME, "got TimeFormatException parsing timestamp: \"" + time + '"', e);
615 | return 0;
616 | }
617 |
618 | return timestamper.normalize(false);
619 | } else {
620 | Date timestamp = null;
621 |
622 | if (rfc3339 == null) {
623 | rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
624 | rfc3339.setTimeZone(TimeZone.getTimeZone("GMT+0"));
625 | rfc3339.setLenient(true);
626 | }
627 |
628 | try {
629 | timestamp = rfc3339.parse(time);
630 | } catch (ParseException e) {
631 | Log.e(LOGCAT_NAME, "got ParseException parsing timestamp: \"" + time + '"', e);
632 | return 0;
633 | }
634 |
635 | return timestamp.getTime();
636 | }
637 | }
638 | }
639 |
--------------------------------------------------------------------------------
/Example/src/com/catchnotes/api/VersionedCatchHttpClient.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2011 Catch.com, Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | package com.catchnotes.api;
18 |
19 | import java.io.IOException;
20 | import java.io.UnsupportedEncodingException;
21 | import java.net.URI;
22 | import java.net.URLEncoder;
23 |
24 | import org.apache.http.HttpHost;
25 | import org.apache.http.HttpRequest;
26 | import org.apache.http.HttpResponse;
27 | import org.apache.http.HttpVersion;
28 | import org.apache.http.client.ClientProtocolException;
29 | import org.apache.http.client.HttpClient;
30 | import org.apache.http.client.ResponseHandler;
31 | import org.apache.http.client.methods.HttpRequestBase;
32 | import org.apache.http.client.methods.HttpUriRequest;
33 | import org.apache.http.client.params.HttpClientParams;
34 | import org.apache.http.conn.ClientConnectionManager;
35 | import org.apache.http.impl.client.DefaultHttpClient;
36 | import org.apache.http.params.BasicHttpParams;
37 | import org.apache.http.params.HttpConnectionParams;
38 | import org.apache.http.params.HttpParams;
39 | import org.apache.http.params.HttpProtocolParams;
40 | import org.apache.http.protocol.HTTP;
41 | import org.apache.http.protocol.HttpContext;
42 |
43 | import android.content.Context;
44 | import android.net.http.AndroidHttpClient;
45 | import android.os.Build;
46 |
47 | public abstract class VersionedCatchHttpClient implements HttpClient {
48 | protected String mEncodedAccessToken;
49 | protected HttpClient mHttpClient;
50 |
51 | public static VersionedCatchHttpClient newInstance(String userAgent, Context context) {
52 | VersionedCatchHttpClient client;
53 |
54 | if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
55 | client = new PreFroyoCatchHttpClient(userAgent);
56 | } else {
57 | client = new CatchHttpClient(userAgent, context);
58 | }
59 |
60 | return client;
61 | }
62 |
63 | private static class PreFroyoCatchHttpClient extends VersionedCatchHttpClient {
64 | public PreFroyoCatchHttpClient(String userAgent) {
65 | HttpParams params = new BasicHttpParams();
66 | HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
67 | HttpProtocolParams.setUserAgent(params, userAgent);
68 | HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
69 |
70 | // Use some properties set in the default impl of AndroidHttpdClient
71 |
72 | // Turn off stale checking. Our connections break all the time anyway,
73 | // and it's not worth it to pay the penalty of checking every time.
74 | HttpConnectionParams.setStaleCheckingEnabled(params, false);
75 |
76 | // Default connection and socket timeout of 20 seconds.
77 | HttpConnectionParams.setConnectionTimeout(params, 20000);
78 | HttpConnectionParams.setSoTimeout(params, 20000);
79 | HttpConnectionParams.setSocketBufferSize(params, 8192);
80 |
81 | mHttpClient = new DefaultHttpClient(params);
82 | }
83 | }
84 |
85 | private static class CatchHttpClient extends VersionedCatchHttpClient {
86 | public CatchHttpClient(String userAgent, Context context) {
87 | mHttpClient = AndroidHttpClient.newInstance(userAgent, context);
88 | HttpParams httpParams = mHttpClient.getParams();
89 | HttpClientParams.setRedirecting(httpParams, true);
90 | HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
91 | HttpProtocolParams.setContentCharset(httpParams, HTTP.UTF_8);
92 | }
93 |
94 | public void close() {
95 | ((AndroidHttpClient) mHttpClient).close();
96 | }
97 | }
98 |
99 | public void close() {
100 | }
101 |
102 | public void setAccessToken(String accessToken) {
103 | try {
104 | mEncodedAccessToken = "access_token=" + URLEncoder.encode(accessToken, HTTP.UTF_8);
105 | } catch (UnsupportedEncodingException e) {
106 | throw new AssertionError(e);
107 | }
108 | }
109 |
110 | private void addAccessTokenToHttpUriRequest(HttpUriRequest httpUriRequest) {
111 | if (mEncodedAccessToken != null) {
112 | String query = httpUriRequest.getURI().getQuery();
113 |
114 | if (query == null || query.length() == 0) {
115 | ((HttpRequestBase) httpUriRequest).setURI(URI.create(httpUriRequest.getURI() + "?" + mEncodedAccessToken));
116 | } else {
117 | ((HttpRequestBase) httpUriRequest).setURI(URI.create(httpUriRequest.getURI() + "&" + mEncodedAccessToken));
118 | }
119 | }
120 | }
121 |
122 | public HttpParams getParams() {
123 | return mHttpClient.getParams();
124 | }
125 |
126 | public ClientConnectionManager getConnectionManager() {
127 | return mHttpClient.getConnectionManager();
128 | }
129 |
130 | public HttpResponse execute(HttpUriRequest httpUriRequest) throws IOException, ClientProtocolException {
131 | addAccessTokenToHttpUriRequest(httpUriRequest);
132 | return mHttpClient.execute(httpUriRequest);
133 | }
134 |
135 | public HttpResponse execute(HttpUriRequest httpUriRequest, HttpContext httpContext) throws IOException, ClientProtocolException {
136 | addAccessTokenToHttpUriRequest(httpUriRequest);
137 | return mHttpClient.execute(httpUriRequest, httpContext);
138 | }
139 |
140 | public HttpResponse execute(HttpHost httpHost, HttpRequest httpRequest) throws IOException, ClientProtocolException {
141 | addAccessTokenToHttpUriRequest((HttpUriRequest) httpRequest);
142 | return mHttpClient.execute(httpHost, httpRequest);
143 | }
144 |
145 | public HttpResponse execute(HttpHost httpHost, HttpRequest httpRequest, HttpContext httpContext) throws IOException, ClientProtocolException {
146 | addAccessTokenToHttpUriRequest((HttpUriRequest) httpRequest);
147 | return mHttpClient.execute(httpHost, httpRequest, httpContext);
148 | }
149 |
150 | public T execute(HttpUriRequest httpUriRequest, ResponseHandler extends T> responseHandler) throws IOException, ClientProtocolException {
151 | addAccessTokenToHttpUriRequest(httpUriRequest);
152 | return mHttpClient.execute(httpUriRequest, responseHandler);
153 | }
154 |
155 | public T execute(HttpUriRequest httpUriRequest, ResponseHandler extends T> responseHandler, HttpContext httpContext) throws IOException, ClientProtocolException {
156 | addAccessTokenToHttpUriRequest(httpUriRequest);
157 | return mHttpClient.execute(httpUriRequest, responseHandler, httpContext);
158 | }
159 |
160 | public T execute(HttpHost httpHost, HttpRequest httpRequest, ResponseHandler extends T> responseHandler) throws IOException, ClientProtocolException {
161 | addAccessTokenToHttpUriRequest((HttpUriRequest) httpRequest);
162 | return mHttpClient.execute(httpHost, httpRequest, responseHandler);
163 | }
164 |
165 | public T execute(HttpHost httpHost, HttpRequest httpRequest, ResponseHandler extends T> responseHandler, HttpContext httpContext) throws IOException, ClientProtocolException {
166 | addAccessTokenToHttpUriRequest((HttpUriRequest) httpRequest);
167 | return mHttpClient.execute(httpHost, httpRequest, responseHandler, httpContext);
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/Example/src/com/example/CatchApiDemo/Dashboard.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2011 Catch.com, Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | package com.example.CatchApiDemo;
18 |
19 | import java.util.ArrayList;
20 |
21 | import android.app.Activity;
22 | import android.app.AlertDialog;
23 | import android.app.Dialog;
24 | import android.content.Context;
25 | import android.content.DialogInterface;
26 | import android.os.AsyncTask;
27 | import android.os.Bundle;
28 | import android.text.format.DateUtils;
29 | import android.util.Log;
30 | import android.view.LayoutInflater;
31 | import android.view.View;
32 | import android.view.View.OnClickListener;
33 | import android.widget.Button;
34 | import android.widget.EditText;
35 | import android.widget.Toast;
36 |
37 | import com.catchnotes.api.CatchAPI;
38 | import com.catchnotes.api.CatchAccount;
39 | import com.catchnotes.api.CatchNote;
40 |
41 | public class Dashboard extends Activity {
42 |
43 | public static final String APP_NAME = "CatchApiDemo";
44 | protected static final int DIALOG_SIGN_IN = 0;
45 | protected static final int DIALOG_COMPOSE_NOTE = 1;
46 |
47 | /////////////////////////////////////////////////////////
48 | // You get a token when you sign in.
49 | // You'll need it each time you create a CatchAPI object.
50 | /////////////////////////////////////////////////////////
51 | protected String mAccessToken;
52 |
53 |
54 | @Override
55 | public void onCreate(Bundle savedInstanceState) {
56 | super.onCreate(savedInstanceState);
57 | setContentView(R.layout.main);
58 |
59 | // Sign in button
60 | final Button signInButton = (Button) findViewById(R.id.sign_in_button);
61 | signInButton.setOnClickListener(new OnClickListener() {
62 | public void onClick(View v) {
63 | showDialog(DIALOG_SIGN_IN);
64 | }
65 | });
66 |
67 | // Fetch Notes button
68 | final Button fetchButton = (Button) findViewById(R.id.fetch_button);
69 | fetchButton.setOnClickListener(new OnClickListener() {
70 | public void onClick(View v) {
71 | if (mAccessToken == null) {
72 | Toast.makeText(Dashboard.this, "Not signed in!", Toast.LENGTH_SHORT).show();
73 | } else {
74 | // start Fetch Notes task
75 | new FetchNotesTask(getApplicationContext()).execute();
76 | }
77 | }
78 | });
79 |
80 | // New Note button
81 | final Button createButton = (Button) findViewById(R.id.create_button);
82 | createButton.setOnClickListener(new OnClickListener() {
83 | public void onClick(View v) {
84 | if (mAccessToken == null) {
85 | Toast.makeText(Dashboard.this, "Not signed in!", Toast.LENGTH_SHORT).show();
86 | } else {
87 | showDialog(DIALOG_COMPOSE_NOTE);
88 | }
89 | }
90 | });
91 | }
92 |
93 |
94 | @Override
95 | protected Dialog onCreateDialog(int id) {
96 | Dialog dialog;
97 | AlertDialog.Builder builder;
98 |
99 | switch (id) {
100 | case DIALOG_SIGN_IN:
101 | {
102 | final View inflated = LayoutInflater.from(this).inflate(R.layout.sign_in, null);
103 | builder = new AlertDialog.Builder(this);
104 | builder.setMessage(R.string.sign_in_dialog_title)
105 | .setCancelable(true)
106 | .setView(inflated)
107 | .setPositiveButton(getString(R.string.sign_in), new DialogInterface.OnClickListener() {
108 | public void onClick(DialogInterface dialog, int id) {
109 | EditText userEdit = (EditText) inflated.findViewById(R.id.username_edittext);
110 | EditText passEdit = (EditText) inflated.findViewById(R.id.password_edittext);
111 | // start Sign In task
112 | new SignInTask(getApplicationContext())
113 | .execute(userEdit.getText().toString(), passEdit.getText().toString());
114 | }
115 | })
116 | .setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
117 | public void onClick(DialogInterface dialog, int id) {
118 | dialog.cancel();
119 | }
120 | });
121 | dialog = builder.create();
122 | break;
123 | }
124 |
125 | case DIALOG_COMPOSE_NOTE:
126 | {
127 | final View inflated = LayoutInflater.from(this).inflate(R.layout.new_note, null);
128 | builder = new AlertDialog.Builder(this);
129 | builder.setMessage(R.string.new_note_dialog_title)
130 | .setCancelable(true)
131 | .setView(inflated)
132 | .setPositiveButton(getString(R.string.add_note), new DialogInterface.OnClickListener() {
133 | public void onClick(DialogInterface dialog, int id) {
134 | EditText composer = (EditText) inflated.findViewById(R.id.compose_edittext);
135 | // start Create Note task
136 | new CreateNoteTask(getApplicationContext()).execute(composer.getText().toString());
137 | }
138 | })
139 | .setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
140 | public void onClick(DialogInterface dialog, int id) {
141 | dialog.cancel();
142 | }
143 | });
144 | dialog = builder.create();
145 | break;
146 | }
147 |
148 | default:
149 | dialog = null;
150 | break;
151 | }
152 |
153 | return dialog;
154 | }
155 |
156 |
157 | ////////////////////////////////////////////
158 | // Example sign-in task. Sets mAccessToken.
159 | ////////////////////////////////////////////
160 | private class SignInTask extends AsyncTask {
161 |
162 | private Context mContext;
163 | private CatchAccount mAccount;
164 |
165 | public SignInTask(Context context) {
166 | mContext = context;
167 | mAccount = new CatchAccount();
168 | }
169 |
170 | @Override
171 | protected String doInBackground(String... params) {
172 | String username = params[0];
173 | String password = params[1];
174 |
175 | // Create a CatchAPI object.
176 | CatchAPI api = new CatchAPI(APP_NAME, mContext);
177 |
178 | // Sign in.
179 | // The third parameter (CatchAccount) will be populated with account
180 | // information, including the access token that you can use to avoid
181 | // signing in each time you need to create a new CatchAPI object.
182 | int result = api.signIn(username, password, mAccount);
183 | if (result == CatchAPI.RESULT_OK) {
184 | Log.d(APP_NAME, "Signed in.");
185 | Log.d(APP_NAME, "Account ID: "+mAccount.id);
186 | Log.d(APP_NAME, "Account Name: "+mAccount.username);
187 | Log.d(APP_NAME, "Account Email: "+mAccount.email);
188 | return mAccount.auth_token;
189 |
190 | } else {
191 | Log.d(APP_NAME, "Couldn't sign in. Error code: "+result);
192 | return null;
193 | }
194 | }
195 |
196 | @Override
197 | protected void onPostExecute(String accessToken) {
198 | Dashboard.this.mAccessToken = accessToken;
199 | if (accessToken == null) {
200 | Toast.makeText(Dashboard.this, "Sign-in Failed!", Toast.LENGTH_SHORT).show();
201 | } else {
202 | Toast.makeText(Dashboard.this, "User "+mAccount.username+" signed in.",
203 | Toast.LENGTH_SHORT).show();
204 | }
205 | }
206 |
207 | }
208 |
209 |
210 | //////////////////////////////
211 | // Example note fetching task.
212 | //////////////////////////////
213 | private class FetchNotesTask extends AsyncTask {
214 |
215 | private Context mContext;
216 | private int mResult;
217 |
218 | public FetchNotesTask(Context context) {
219 | mContext = context;
220 | }
221 |
222 | protected String formatDate(long timestamp) {
223 | return DateUtils.formatDateTime(mContext, timestamp,
224 | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE |
225 | DateUtils.FORMAT_SHOW_TIME);
226 | }
227 |
228 | @Override
229 | protected Void doInBackground(Void... params) {
230 |
231 | // Create a CatchAPI object. Use the access token that we got from
232 | // a previous sign-in.
233 | CatchAPI api = new CatchAPI(APP_NAME, mContext);
234 | api.setAccessToken(Dashboard.this.mAccessToken);
235 |
236 | // Call getNotes to fill a list with CatchNote objects.
237 | ArrayList notes = new ArrayList();
238 | mResult = api.getNotes(notes);
239 | if (mResult == CatchAPI.RESULT_OK) {
240 | Log.d(APP_NAME, "Displaying "+notes.size()+" notes...");
241 | for (CatchNote note : notes) {
242 | // Print note info.
243 | Log.d(APP_NAME, "----"+
244 | " Note ID: "+note.id+
245 | " Created: "+formatDate(note.creationTime)+
246 | " Modified: "+formatDate(note.modificationTime)+
247 | " ----");
248 | // Print note summary. (Full text is note.text)
249 | Log.d(APP_NAME, note.summary.toString());
250 | }
251 | Log.d(APP_NAME, "Displayed "+notes.size()+" notes.");
252 |
253 | } else {
254 | Log.d(APP_NAME, "Couldn't fetch notes. Error code: "+mResult);
255 | return null;
256 | }
257 |
258 | return null;
259 | }
260 |
261 | @Override
262 | protected void onPostExecute(Void unused) {
263 | if (mResult == CatchAPI.RESULT_OK) {
264 | Toast.makeText(Dashboard.this, "Notes Fetched", Toast.LENGTH_SHORT).show();
265 | } else {
266 | Toast.makeText(Dashboard.this, "Note Fetch Failed!",
267 | Toast.LENGTH_SHORT).show();
268 | }
269 | }
270 | }
271 |
272 |
273 | //////////////////////////////
274 | // Example note creation task.
275 | //////////////////////////////
276 | private class CreateNoteTask extends AsyncTask {
277 |
278 | private Context mContext;
279 |
280 | public CreateNoteTask(Context context) {
281 | mContext = context;
282 | }
283 |
284 | @Override
285 | protected String doInBackground(String... params) {
286 | String text = params[0];
287 |
288 | // Create CatchAPI and set the access token.
289 | CatchAPI api = new CatchAPI(APP_NAME, mContext);
290 | api.setAccessToken(Dashboard.this.mAccessToken);
291 |
292 | // Create a new note.
293 | CatchNote note = new CatchNote();
294 |
295 | // set the creation and modification timestamps.
296 | long timestamp = System.currentTimeMillis();
297 | note.creationTime = timestamp;
298 | note.modificationTime = timestamp;
299 |
300 | // set the note text.
301 | note.text = text;
302 |
303 | // Call addNote to add the note to the account. The note object
304 | // will be updated with extra information, such as the note ID.
305 | int result = api.addNote(note);
306 | if (result == CatchAPI.RESULT_OK) {
307 | Log.d(APP_NAME, "Created note ID: "+note.id);
308 | return note.id;
309 |
310 | } else {
311 | Log.d(APP_NAME, "Couldn't add note. Error code: "+result);
312 | return null;
313 | }
314 | }
315 |
316 | @Override
317 | protected void onPostExecute(String noteId) {
318 | if (noteId != null) {
319 | Toast.makeText(Dashboard.this, "Note Added", Toast.LENGTH_SHORT).show();
320 | } else {
321 | Toast.makeText(Dashboard.this, "Note Creation Failed!",
322 | Toast.LENGTH_SHORT).show();
323 | }
324 | }
325 |
326 | }
327 |
328 | }
329 |
330 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | # CatchAPI
2 | CatchAPI is a Java library for Android. It makes it easy to use the [Catch.com REST API](https://catch.com/developer/v2/). Here's a quick preview...
3 |
4 | ```java
5 | CatchAPI api = new CatchAPI("MyCoolApp", context);
6 |
7 | // sign in
8 | api.signIn("username", "pass1234", null);
9 |
10 | // add a new note
11 | CatchNote note = new CatchNote();
12 |
13 | long timestamp = System.currentTimeMillis();
14 | note.creationTime = timestamp;
15 | note.modificationTime = timestamp;
16 |
17 | note.text = "Hello World!";
18 |
19 | api.addNote(note);
20 | ```
21 |
22 | Check out the [library documentation](http://catch.github.com/android-api/Documentation/) for more. The [CatchAPI class](http://catch.github.com/android-api/Documentation/com/catchnotes/api/CatchAPI.html) is the primary interface, so you might want to start there.
23 |
24 | Also, take a look at the Example app to see an example of the library in use. The interesting stuff is in [Dashboard.java](https://github.com/catch/android-api/blob/master/Example/src/com/example/CatchApiDemo/Dashboard.java), mostly near the bottom of the file.
25 |
26 |
--------------------------------------------------------------------------------
/android-lib/libs/commons-codec-1.4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/catch/android-api/9fab8967757a64078fffa811ebb939364e5b3617/android-lib/libs/commons-codec-1.4.jar
--------------------------------------------------------------------------------
/android-lib/src/com/android/http/multipart/ByteArrayPartSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/ByteArrayPartSource.java,v 1.7 2004/04/18 23:51:37 jsdever Exp $
3 | * $Revision: 480424 $
4 | * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
5 | *
6 | * ====================================================================
7 | *
8 | * Licensed to the Apache Software Foundation (ASF) under one or more
9 | * contributor license agreements. See the NOTICE file distributed with
10 | * this work for additional information regarding copyright ownership.
11 | * The ASF licenses this file to You under the Apache License, Version 2.0
12 | * (the "License"); you may not use this file except in compliance with
13 | * the License. You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | * ====================================================================
23 | *
24 | * This software consists of voluntary contributions made by many
25 | * individuals on behalf of the Apache Software Foundation. For more
26 | * information on the Apache Software Foundation, please see
27 | * .
28 | *
29 | */
30 |
31 | package com.android.http.multipart;
32 |
33 | import java.io.ByteArrayInputStream;
34 | import java.io.InputStream;
35 |
36 | /**
37 | * A PartSource that reads from a byte array. This class should be used when
38 | * the data to post is already loaded into memory.
39 | *
40 | * @author Michael Becke
41 | *
42 | * @since 2.0
43 | */
44 | public class ByteArrayPartSource implements PartSource {
45 |
46 | /** Name of the source file. */
47 | private String fileName;
48 |
49 | /** Byte array of the source file. */
50 | private byte[] bytes;
51 |
52 | /**
53 | * Constructor for ByteArrayPartSource.
54 | *
55 | * @param fileName the name of the file these bytes represent
56 | * @param bytes the content of this part
57 | */
58 | public ByteArrayPartSource(String fileName, byte[] bytes) {
59 |
60 | this.fileName = fileName;
61 | this.bytes = bytes;
62 |
63 | }
64 |
65 | /**
66 | * @see PartSource#getLength()
67 | */
68 | public long getLength() {
69 | return bytes.length;
70 | }
71 |
72 | /**
73 | * @see PartSource#getFileName()
74 | */
75 | public String getFileName() {
76 | return fileName;
77 | }
78 |
79 | /**
80 | * @see PartSource#createInputStream()
81 | */
82 | public InputStream createInputStream() {
83 | return new ByteArrayInputStream(bytes);
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/android-lib/src/com/android/http/multipart/FilePart.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java,v 1.19 2004/04/18 23:51:37 jsdever Exp $
3 | * $Revision: 480424 $
4 | * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
5 | *
6 | * ====================================================================
7 | *
8 | * Licensed to the Apache Software Foundation (ASF) under one or more
9 | * contributor license agreements. See the NOTICE file distributed with
10 | * this work for additional information regarding copyright ownership.
11 | * The ASF licenses this file to You under the Apache License, Version 2.0
12 | * (the "License"); you may not use this file except in compliance with
13 | * the License. You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | * ====================================================================
23 | *
24 | * This software consists of voluntary contributions made by many
25 | * individuals on behalf of the Apache Software Foundation. For more
26 | * information on the Apache Software Foundation, please see
27 | * .
28 | *
29 | */
30 |
31 | package com.android.http.multipart;
32 |
33 | import java.io.File;
34 | import java.io.FileNotFoundException;
35 | import java.io.IOException;
36 | import java.io.InputStream;
37 | import java.io.OutputStream;
38 | import org.apache.http.util.EncodingUtils;
39 |
40 | /**
41 | * This class implements a part of a Multipart post object that
42 | * consists of a file.
43 | *
44 | * @author Matthew Albright
45 | * @author Jeff Dever
46 | * @author Adrian Sutton
47 | * @author Michael Becke
48 | * @author Mark Diggory
49 | * @author Mike Bowler
50 | * @author Oleg Kalnichevski
51 | *
52 | * @since 2.0
53 | *
54 | */
55 | public class FilePart extends PartBase {
56 |
57 | /** Default content encoding of file attachments. */
58 | public static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
59 |
60 | /** Default charset of file attachments. */
61 | public static final String DEFAULT_CHARSET = "ISO-8859-1";
62 |
63 | /** Default transfer encoding of file attachments. */
64 | public static final String DEFAULT_TRANSFER_ENCODING = "binary";
65 |
66 | /** Attachment's file name */
67 | protected static final String FILE_NAME = "; filename=";
68 |
69 | /** Attachment's file name as a byte array */
70 | private static final byte[] FILE_NAME_BYTES =
71 | EncodingUtils.getAsciiBytes(FILE_NAME);
72 |
73 | /** Source of the file part. */
74 | private PartSource source;
75 |
76 | /**
77 | * FilePart Constructor.
78 | *
79 | * @param name the name for this part
80 | * @param partSource the source for this part
81 | * @param contentType the content type for this part, if null the
82 | * {@link #DEFAULT_CONTENT_TYPE default} is used
83 | * @param charset the charset encoding for this part, if null the
84 | * {@link #DEFAULT_CHARSET default} is used
85 | */
86 | public FilePart(String name, PartSource partSource, String contentType, String charset) {
87 |
88 | super(
89 | name,
90 | contentType == null ? DEFAULT_CONTENT_TYPE : contentType,
91 | charset == null ? "ISO-8859-1" : charset,
92 | DEFAULT_TRANSFER_ENCODING
93 | );
94 |
95 | if (partSource == null) {
96 | throw new IllegalArgumentException("Source may not be null");
97 | }
98 | this.source = partSource;
99 | }
100 |
101 | /**
102 | * FilePart Constructor.
103 | *
104 | * @param name the name for this part
105 | * @param partSource the source for this part
106 | */
107 | public FilePart(String name, PartSource partSource) {
108 | this(name, partSource, null, null);
109 | }
110 |
111 | /**
112 | * FilePart Constructor.
113 | *
114 | * @param name the name of the file part
115 | * @param file the file to post
116 | *
117 | * @throws FileNotFoundException if the file is not a normal
118 | * file or if it is not readable.
119 | */
120 | public FilePart(String name, File file)
121 | throws FileNotFoundException {
122 | this(name, new FilePartSource(file), null, null);
123 | }
124 |
125 | /**
126 | * FilePart Constructor.
127 | *
128 | * @param name the name of the file part
129 | * @param file the file to post
130 | * @param contentType the content type for this part, if null the
131 | * {@link #DEFAULT_CONTENT_TYPE default} is used
132 | * @param charset the charset encoding for this part, if null the
133 | * {@link #DEFAULT_CHARSET default} is used
134 | *
135 | * @throws FileNotFoundException if the file is not a normal
136 | * file or if it is not readable.
137 | */
138 | public FilePart(String name, File file, String contentType, String charset)
139 | throws FileNotFoundException {
140 | this(name, new FilePartSource(file), contentType, charset);
141 | }
142 |
143 | /**
144 | * FilePart Constructor.
145 | *
146 | * @param name the name of the file part
147 | * @param fileName the file name
148 | * @param file the file to post
149 | *
150 | * @throws FileNotFoundException if the file is not a normal
151 | * file or if it is not readable.
152 | */
153 | public FilePart(String name, String fileName, File file)
154 | throws FileNotFoundException {
155 | this(name, new FilePartSource(fileName, file), null, null);
156 | }
157 |
158 | /**
159 | * FilePart Constructor.
160 | *
161 | * @param name the name of the file part
162 | * @param fileName the file name
163 | * @param file the file to post
164 | * @param contentType the content type for this part, if null the
165 | * {@link #DEFAULT_CONTENT_TYPE default} is used
166 | * @param charset the charset encoding for this part, if null the
167 | * {@link #DEFAULT_CHARSET default} is used
168 | *
169 | * @throws FileNotFoundException if the file is not a normal
170 | * file or if it is not readable.
171 | */
172 | public FilePart(String name, String fileName, File file, String contentType, String charset)
173 | throws FileNotFoundException {
174 | this(name, new FilePartSource(fileName, file), contentType, charset);
175 | }
176 |
177 | /**
178 | * Write the disposition header to the output stream
179 | * @param out The output stream
180 | * @throws IOException If an IO problem occurs
181 | * @see Part#sendDispositionHeader(OutputStream)
182 | */
183 | @Override
184 | protected void sendDispositionHeader(OutputStream out)
185 | throws IOException {
186 | super.sendDispositionHeader(out);
187 | String filename = this.source.getFileName();
188 | if (filename != null) {
189 | out.write(FILE_NAME_BYTES);
190 | out.write(QUOTE_BYTES);
191 | out.write(EncodingUtils.getAsciiBytes(filename));
192 | out.write(QUOTE_BYTES);
193 | }
194 | }
195 |
196 | /**
197 | * Write the data in "source" to the specified stream.
198 | * @param out The output stream.
199 | * @throws IOException if an IO problem occurs.
200 | * @see Part#sendData(OutputStream)
201 | */
202 | @Override
203 | protected void sendData(OutputStream out) throws IOException {
204 | if (lengthOfData() == 0) {
205 |
206 | // this file contains no data, so there is nothing to send.
207 | // we don't want to create a zero length buffer as this will
208 | // cause an infinite loop when reading.
209 | return;
210 | }
211 |
212 | byte[] tmp = new byte[4096];
213 | InputStream instream = source.createInputStream();
214 | try {
215 | int len;
216 | while ((len = instream.read(tmp)) >= 0) {
217 | out.write(tmp, 0, len);
218 | }
219 | } finally {
220 | // we're done with the stream, close it
221 | instream.close();
222 | }
223 | }
224 |
225 | /**
226 | * Returns the source of the file part.
227 | *
228 | * @return The source.
229 | */
230 | protected PartSource getSource() {
231 | return this.source;
232 | }
233 |
234 | /**
235 | * Return the length of the data.
236 | * @return The length.
237 | * @see Part#lengthOfData()
238 | */
239 | @Override
240 | protected long lengthOfData() {
241 | return source.getLength();
242 | }
243 |
244 | }
245 |
--------------------------------------------------------------------------------
/android-lib/src/com/android/http/multipart/FilePartSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePartSource.java,v 1.10 2004/04/18 23:51:37 jsdever Exp $
3 | * $Revision: 480424 $
4 | * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
5 | *
6 | * ====================================================================
7 | *
8 | * Licensed to the Apache Software Foundation (ASF) under one or more
9 | * contributor license agreements. See the NOTICE file distributed with
10 | * this work for additional information regarding copyright ownership.
11 | * The ASF licenses this file to You under the Apache License, Version 2.0
12 | * (the "License"); you may not use this file except in compliance with
13 | * the License. You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | * ====================================================================
23 | *
24 | * This software consists of voluntary contributions made by many
25 | * individuals on behalf of the Apache Software Foundation. For more
26 | * information on the Apache Software Foundation, please see
27 | * .
28 | *
29 | */
30 |
31 | package com.android.http.multipart;
32 |
33 | import java.io.ByteArrayInputStream;
34 | import java.io.File;
35 | import java.io.FileInputStream;
36 | import java.io.FileNotFoundException;
37 | import java.io.IOException;
38 | import java.io.InputStream;
39 |
40 | /**
41 | * A PartSource that reads from a File.
42 | *
43 | * @author Michael Becke
44 | * @author Mark Diggory
45 | * @author Mike Bowler
46 | *
47 | * @since 2.0
48 | */
49 | public class FilePartSource implements PartSource {
50 |
51 | /** File part file. */
52 | private File file = null;
53 |
54 | /** File part file name. */
55 | private String fileName = null;
56 |
57 | /**
58 | * Constructor for FilePartSource.
59 | *
60 | * @param file the FilePart source File.
61 | *
62 | * @throws FileNotFoundException if the file does not exist or
63 | * cannot be read
64 | */
65 | public FilePartSource(File file) throws FileNotFoundException {
66 | this.file = file;
67 | if (file != null) {
68 | if (!file.isFile()) {
69 | throw new FileNotFoundException("File is not a normal file.");
70 | }
71 | if (!file.canRead()) {
72 | throw new FileNotFoundException("File is not readable.");
73 | }
74 | this.fileName = file.getName();
75 | }
76 | }
77 |
78 | /**
79 | * Constructor for FilePartSource.
80 | *
81 | * @param fileName the file name of the FilePart
82 | * @param file the source File for the FilePart
83 | *
84 | * @throws FileNotFoundException if the file does not exist or
85 | * cannot be read
86 | */
87 | public FilePartSource(String fileName, File file)
88 | throws FileNotFoundException {
89 | this(file);
90 | if (fileName != null) {
91 | this.fileName = fileName;
92 | }
93 | }
94 |
95 | /**
96 | * Return the length of the file
97 | * @return the length of the file.
98 | * @see PartSource#getLength()
99 | */
100 | public long getLength() {
101 | if (this.file != null) {
102 | return this.file.length();
103 | } else {
104 | return 0;
105 | }
106 | }
107 |
108 | /**
109 | * Return the current filename
110 | * @return the filename.
111 | * @see PartSource#getFileName()
112 | */
113 | public String getFileName() {
114 | return (fileName == null) ? "noname" : fileName;
115 | }
116 |
117 | /**
118 | * Return a new {@link FileInputStream} for the current filename.
119 | * @return the new input stream.
120 | * @throws IOException If an IO problem occurs.
121 | * @see PartSource#createInputStream()
122 | */
123 | public InputStream createInputStream() throws IOException {
124 | if (this.file != null) {
125 | return new FileInputStream(this.file);
126 | } else {
127 | return new ByteArrayInputStream(new byte[] {});
128 | }
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/android-lib/src/com/android/http/multipart/MultipartEntity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/MultipartRequestEntity.java,v 1.1 2004/10/06 03:39:59 mbecke Exp $
3 | * $Revision: 502647 $
4 | * $Date: 2007-02-02 17:22:54 +0100 (Fri, 02 Feb 2007) $
5 | *
6 | * ====================================================================
7 | *
8 | * Licensed to the Apache Software Foundation (ASF) under one or more
9 | * contributor license agreements. See the NOTICE file distributed with
10 | * this work for additional information regarding copyright ownership.
11 | * The ASF licenses this file to You under the Apache License, Version 2.0
12 | * (the "License"); you may not use this file except in compliance with
13 | * the License. You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | * ====================================================================
23 | *
24 | * This software consists of voluntary contributions made by many
25 | * individuals on behalf of the Apache Software Foundation. For more
26 | * information on the Apache Software Foundation, please see
27 | * .
28 | *
29 | */
30 |
31 | package com.android.http.multipart;
32 |
33 | import java.io.ByteArrayInputStream;
34 | import java.io.ByteArrayOutputStream;
35 | import java.io.IOException;
36 | import java.io.InputStream;
37 | import java.io.OutputStream;
38 | import java.util.Random;
39 |
40 | import org.apache.http.Header;
41 | import org.apache.http.entity.AbstractHttpEntity;
42 | import org.apache.http.message.BasicHeader;
43 | import org.apache.http.params.HttpParams;
44 | import org.apache.http.protocol.HTTP;
45 | import org.apache.http.util.EncodingUtils;
46 |
47 | /**
48 | * Implements a request entity suitable for an HTTP multipart POST method.
49 | *
50 | * The HTTP multipart POST method is defined in section 3.3 of
51 | * RFC1867:
52 | *
53 | * The media-type multipart/form-data follows the rules of all multipart
54 | * MIME data streams as outlined in RFC 1521. The multipart/form-data contains
55 | * a series of parts. Each part is expected to contain a content-disposition
56 | * header where the value is "form-data" and a name attribute specifies
57 | * the field name within the form, e.g., 'content-disposition: form-data;
58 | * name="xxxxx"', where xxxxx is the field name corresponding to that field.
59 | * Field names originally in non-ASCII character sets may be encoded using
60 | * the method outlined in RFC 1522.
61 | *
62 | *
63 | *
This entity is designed to be used in conjunction with the
64 | * {@link org.apache.http.HttpRequest} to provide
65 | * multipart posts. Example usage:
66 | *
67 | * File f = new File("/path/fileToUpload.txt");
68 | * HttpRequest request = new HttpRequest("http://host/some_path");
69 | * Part[] parts = {
70 | * new StringPart("param_name", "value"),
71 | * new FilePart(f.getName(), f)
72 | * };
73 | * filePost.setEntity(
74 | * new MultipartRequestEntity(parts, filePost.getParams())
75 | * );
76 | * HttpClient client = new HttpClient();
77 | * int status = client.executeMethod(filePost);
78 | *
79 | *
80 | * @since 3.0
81 | */
82 | public class MultipartEntity extends AbstractHttpEntity {
83 | /** The Content-Type for multipart/form-data. */
84 | private static final String MULTIPART_FORM_CONTENT_TYPE = "multipart/form-data";
85 |
86 | /**
87 | * Sets the value to use as the multipart boundary.
88 | *
89 | * This parameter expects a value if type {@link String}.
90 | *
91 | */
92 | public static final String MULTIPART_BOUNDARY = "http.method.multipart.boundary";
93 |
94 | /**
95 | * The pool of ASCII chars to be used for generating a multipart boundary.
96 | */
97 | private static byte[] MULTIPART_CHARS = EncodingUtils.getAsciiBytes(
98 | "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
99 |
100 | /**
101 | * Generates a random multipart boundary string.
102 | */
103 | private static byte[] generateMultipartBoundary() {
104 | Random rand = new Random();
105 | byte[] bytes = new byte[rand.nextInt(11) + 30]; // a random size from 30 to 40
106 | for (int i = 0; i < bytes.length; i++) {
107 | bytes[i] = MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)];
108 | }
109 | return bytes;
110 | }
111 |
112 | /** The MIME parts as set by the constructor */
113 | protected Part[] parts;
114 |
115 | private byte[] multipartBoundary;
116 |
117 | private HttpParams params;
118 |
119 | private boolean contentConsumed = false;
120 |
121 | /**
122 | * Creates a new multipart entity containing the given parts.
123 | * @param parts The parts to include.
124 | * @param params The params of the HttpMethod using this entity.
125 | */
126 | public MultipartEntity(Part[] parts, HttpParams params) {
127 | if (parts == null) {
128 | throw new IllegalArgumentException("parts cannot be null");
129 | }
130 | if (params == null) {
131 | throw new IllegalArgumentException("params cannot be null");
132 | }
133 | this.parts = parts;
134 | this.params = params;
135 | }
136 |
137 | public MultipartEntity(Part[] parts) {
138 | setContentType(MULTIPART_FORM_CONTENT_TYPE);
139 | if (parts == null) {
140 | throw new IllegalArgumentException("parts cannot be null");
141 | }
142 | this.parts = parts;
143 | this.params = null;
144 | }
145 |
146 | /**
147 | * Returns the MIME boundary string that is used to demarcate boundaries of
148 | * this part. The first call to this method will implicitly create a new
149 | * boundary string. To create a boundary string first the
150 | * HttpMethodParams.MULTIPART_BOUNDARY parameter is considered. Otherwise
151 | * a random one is generated.
152 | *
153 | * @return The boundary string of this entity in ASCII encoding.
154 | */
155 | protected byte[] getMultipartBoundary() {
156 | if (multipartBoundary == null) {
157 | String temp = null;
158 | if (params != null) {
159 | temp = (String) params.getParameter(MULTIPART_BOUNDARY);
160 | }
161 | if (temp != null) {
162 | multipartBoundary = EncodingUtils.getAsciiBytes(temp);
163 | } else {
164 | multipartBoundary = generateMultipartBoundary();
165 | }
166 | }
167 | return multipartBoundary;
168 | }
169 |
170 | /**
171 | * Returns true if all parts are repeatable, false otherwise.
172 | */
173 | public boolean isRepeatable() {
174 | for (int i = 0; i < parts.length; i++) {
175 | if (!parts[i].isRepeatable()) {
176 | return false;
177 | }
178 | }
179 | return true;
180 | }
181 |
182 | /* (non-Javadoc)
183 | */
184 | public void writeTo(OutputStream out) throws IOException {
185 | Part.sendParts(out, parts, getMultipartBoundary());
186 | }
187 | /* (non-Javadoc)
188 | * @see org.apache.commons.http.AbstractHttpEntity.#getContentType()
189 | */
190 | @Override
191 | public Header getContentType() {
192 | StringBuffer buffer = new StringBuffer(MULTIPART_FORM_CONTENT_TYPE);
193 | buffer.append("; boundary=");
194 | buffer.append(EncodingUtils.getAsciiString(getMultipartBoundary()));
195 | return new BasicHeader(HTTP.CONTENT_TYPE, buffer.toString());
196 |
197 | }
198 |
199 | /* (non-Javadoc)
200 | */
201 | public long getContentLength() {
202 | try {
203 | return Part.getLengthOfParts(parts, getMultipartBoundary());
204 | } catch (Exception e) {
205 | return 0;
206 | }
207 | }
208 |
209 | public InputStream getContent() throws IOException, IllegalStateException {
210 | if(!isRepeatable() && this.contentConsumed ) {
211 | throw new IllegalStateException("Content has been consumed");
212 | }
213 | this.contentConsumed = true;
214 |
215 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
216 | Part.sendParts(baos, this.parts, this.multipartBoundary);
217 | ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
218 | return bais;
219 | }
220 |
221 | public boolean isStreaming() {
222 | return false;
223 | }
224 | }
225 |
--------------------------------------------------------------------------------
/android-lib/src/com/android/http/multipart/Part.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/Part.java,v 1.16 2005/01/14 21:16:40 olegk Exp $
3 | * $Revision: 480424 $
4 | * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
5 | *
6 | * ====================================================================
7 | *
8 | * Licensed to the Apache Software Foundation (ASF) under one or more
9 | * contributor license agreements. See the NOTICE file distributed with
10 | * this work for additional information regarding copyright ownership.
11 | * The ASF licenses this file to You under the Apache License, Version 2.0
12 | * (the "License"); you may not use this file except in compliance with
13 | * the License. You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | * ====================================================================
23 | *
24 | * This software consists of voluntary contributions made by many
25 | * individuals on behalf of the Apache Software Foundation. For more
26 | * information on the Apache Software Foundation, please see
27 | * .
28 | *
29 | */
30 |
31 | package com.android.http.multipart;
32 |
33 | import java.io.ByteArrayOutputStream;
34 | import java.io.IOException;
35 | import java.io.OutputStream;
36 |
37 | import org.apache.http.util.EncodingUtils;
38 |
39 | /**
40 | * Abstract class for one Part of a multipart post object.
41 | *
42 | * @author Matthew Albright
43 | * @author Jeff Dever
44 | * @author Adrian Sutton
45 | * @author Mike Bowler
46 | * @author Oleg Kalnichevski
47 | *
48 | * @since 2.0
49 | */
50 | public abstract class Part {
51 | /**
52 | * The boundary
53 | * @deprecated use {@link org.apache.http.client.methods.multipart#MULTIPART_BOUNDARY}
54 | */
55 | protected static final String BOUNDARY = "----------------314159265358979323846";
56 |
57 | /**
58 | * The boundary as a byte array.
59 | * @deprecated
60 | */
61 | protected static final byte[] BOUNDARY_BYTES = EncodingUtils.getAsciiBytes(BOUNDARY);
62 |
63 | /**
64 | * The default boundary to be used if {@link #setPartBoundary(byte[])} has not
65 | * been called.
66 | */
67 | private static final byte[] DEFAULT_BOUNDARY_BYTES = BOUNDARY_BYTES;
68 |
69 | /** Carriage return/linefeed */
70 | protected static final String CRLF = "\r\n";
71 |
72 | /** Carriage return/linefeed as a byte array */
73 | protected static final byte[] CRLF_BYTES = EncodingUtils.getAsciiBytes(CRLF);
74 |
75 | /** Content dispostion characters */
76 | protected static final String QUOTE = "\"";
77 |
78 | /** Content dispostion as a byte array */
79 | protected static final byte[] QUOTE_BYTES =
80 | EncodingUtils.getAsciiBytes(QUOTE);
81 |
82 | /** Extra characters */
83 | protected static final String EXTRA = "--";
84 |
85 | /** Extra characters as a byte array */
86 | protected static final byte[] EXTRA_BYTES =
87 | EncodingUtils.getAsciiBytes(EXTRA);
88 |
89 | /** Content dispostion characters */
90 | protected static final String CONTENT_DISPOSITION = "Content-Disposition: form-data; name=";
91 |
92 | /** Content dispostion as a byte array */
93 | protected static final byte[] CONTENT_DISPOSITION_BYTES =
94 | EncodingUtils.getAsciiBytes(CONTENT_DISPOSITION);
95 |
96 | /** Content type header */
97 | protected static final String CONTENT_TYPE = "Content-Type: ";
98 |
99 | /** Content type header as a byte array */
100 | protected static final byte[] CONTENT_TYPE_BYTES =
101 | EncodingUtils.getAsciiBytes(CONTENT_TYPE);
102 |
103 | /** Content charset */
104 | protected static final String CHARSET = "; charset=";
105 |
106 | /** Content charset as a byte array */
107 | protected static final byte[] CHARSET_BYTES =
108 | EncodingUtils.getAsciiBytes(CHARSET);
109 |
110 | /** Content type header */
111 | protected static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding: ";
112 |
113 | /** Content type header as a byte array */
114 | protected static final byte[] CONTENT_TRANSFER_ENCODING_BYTES =
115 | EncodingUtils.getAsciiBytes(CONTENT_TRANSFER_ENCODING);
116 |
117 | /**
118 | * Return the boundary string.
119 | * @return the boundary string
120 | * @deprecated uses a constant string. Rather use {@link #getPartBoundary}
121 | */
122 | public static String getBoundary() {
123 | return BOUNDARY;
124 | }
125 |
126 | /**
127 | * The ASCII bytes to use as the multipart boundary.
128 | */
129 | private byte[] boundaryBytes;
130 |
131 | /**
132 | * Return the name of this part.
133 | * @return The name.
134 | */
135 | public abstract String getName();
136 |
137 | /**
138 | * Returns the content type of this part.
139 | * @return the content type, or null to exclude the content type header
140 | */
141 | public abstract String getContentType();
142 |
143 | /**
144 | * Return the character encoding of this part.
145 | * @return the character encoding, or null to exclude the character
146 | * encoding header
147 | */
148 | public abstract String getCharSet();
149 |
150 | /**
151 | * Return the transfer encoding of this part.
152 | * @return the transfer encoding, or null to exclude the transfer encoding header
153 | */
154 | public abstract String getTransferEncoding();
155 |
156 | /**
157 | * Gets the part boundary to be used.
158 | * @return the part boundary as an array of bytes.
159 | *
160 | * @since 3.0
161 | */
162 | protected byte[] getPartBoundary() {
163 | if (boundaryBytes == null) {
164 | // custom boundary bytes have not been set, use the default.
165 | return DEFAULT_BOUNDARY_BYTES;
166 | } else {
167 | return boundaryBytes;
168 | }
169 | }
170 |
171 | /**
172 | * Sets the part boundary. Only meant to be used by
173 | * {@link Part#sendParts(OutputStream, Part[], byte[])}
174 | * and {@link Part#getLengthOfParts(Part[], byte[])}
175 | * @param boundaryBytes An array of ASCII bytes.
176 | * @since 3.0
177 | */
178 | void setPartBoundary(byte[] boundaryBytes) {
179 | this.boundaryBytes = boundaryBytes;
180 | }
181 |
182 | /**
183 | * Tests if this part can be sent more than once.
184 | * @return true if {@link #sendData(OutputStream)} can be successfully called
185 | * more than once.
186 | * @since 3.0
187 | */
188 | public boolean isRepeatable() {
189 | return true;
190 | }
191 |
192 | /**
193 | * Write the start to the specified output stream
194 | * @param out The output stream
195 | * @throws IOException If an IO problem occurs.
196 | */
197 | protected void sendStart(OutputStream out) throws IOException {
198 | out.write(EXTRA_BYTES);
199 | out.write(getPartBoundary());
200 | out.write(CRLF_BYTES);
201 | }
202 |
203 | /**
204 | * Write the content disposition header to the specified output stream
205 | *
206 | * @param out The output stream
207 | * @throws IOException If an IO problem occurs.
208 | */
209 | protected void sendDispositionHeader(OutputStream out) throws IOException {
210 | out.write(CONTENT_DISPOSITION_BYTES);
211 | out.write(QUOTE_BYTES);
212 | out.write(EncodingUtils.getAsciiBytes(getName()));
213 | out.write(QUOTE_BYTES);
214 | }
215 |
216 | /**
217 | * Write the content type header to the specified output stream
218 | * @param out The output stream
219 | * @throws IOException If an IO problem occurs.
220 | */
221 | protected void sendContentTypeHeader(OutputStream out) throws IOException {
222 | String contentType = getContentType();
223 | if (contentType != null) {
224 | out.write(CRLF_BYTES);
225 | out.write(CONTENT_TYPE_BYTES);
226 | out.write(EncodingUtils.getAsciiBytes(contentType));
227 | String charSet = getCharSet();
228 | if (charSet != null) {
229 | out.write(CHARSET_BYTES);
230 | out.write(EncodingUtils.getAsciiBytes(charSet));
231 | }
232 | }
233 | }
234 |
235 | /**
236 | * Write the content transfer encoding header to the specified
237 | * output stream
238 | *
239 | * @param out The output stream
240 | * @throws IOException If an IO problem occurs.
241 | */
242 | protected void sendTransferEncodingHeader(OutputStream out) throws IOException {
243 | String transferEncoding = getTransferEncoding();
244 | if (transferEncoding != null) {
245 | out.write(CRLF_BYTES);
246 | out.write(CONTENT_TRANSFER_ENCODING_BYTES);
247 | out.write(EncodingUtils.getAsciiBytes(transferEncoding));
248 | }
249 | }
250 |
251 | /**
252 | * Write the end of the header to the output stream
253 | * @param out The output stream
254 | * @throws IOException If an IO problem occurs.
255 | */
256 | protected void sendEndOfHeader(OutputStream out) throws IOException {
257 | out.write(CRLF_BYTES);
258 | out.write(CRLF_BYTES);
259 | }
260 |
261 | /**
262 | * Write the data to the specified output stream
263 | * @param out The output stream
264 | * @throws IOException If an IO problem occurs.
265 | */
266 | protected abstract void sendData(OutputStream out) throws IOException;
267 |
268 | /**
269 | * Return the length of the main content
270 | *
271 | * @return long The length.
272 | * @throws IOException If an IO problem occurs
273 | */
274 | protected abstract long lengthOfData() throws IOException;
275 |
276 | /**
277 | * Write the end data to the output stream.
278 | * @param out The output stream
279 | * @throws IOException If an IO problem occurs.
280 | */
281 | protected void sendEnd(OutputStream out) throws IOException {
282 | out.write(CRLF_BYTES);
283 | }
284 |
285 | /**
286 | * Write all the data to the output stream.
287 | * If you override this method make sure to override
288 | * #length() as well
289 | *
290 | * @param out The output stream
291 | * @throws IOException If an IO problem occurs.
292 | */
293 | public void send(OutputStream out) throws IOException {
294 | sendStart(out);
295 | sendDispositionHeader(out);
296 | sendContentTypeHeader(out);
297 | sendTransferEncodingHeader(out);
298 | sendEndOfHeader(out);
299 | sendData(out);
300 | sendEnd(out);
301 | }
302 |
303 |
304 | /**
305 | * Return the full length of all the data.
306 | * If you override this method make sure to override
307 | * #send(OutputStream) as well
308 | *
309 | * @return long The length.
310 | * @throws IOException If an IO problem occurs
311 | */
312 | public long length() throws IOException {
313 | if (lengthOfData() < 0) {
314 | return -1;
315 | }
316 | ByteArrayOutputStream overhead = new ByteArrayOutputStream();
317 | sendStart(overhead);
318 | sendDispositionHeader(overhead);
319 | sendContentTypeHeader(overhead);
320 | sendTransferEncodingHeader(overhead);
321 | sendEndOfHeader(overhead);
322 | sendEnd(overhead);
323 | return overhead.size() + lengthOfData();
324 | }
325 |
326 | /**
327 | * Return a string representation of this object.
328 | * @return A string representation of this object.
329 | * @see java.lang.Object#toString()
330 | */
331 | @Override
332 | public String toString() {
333 | return this.getName();
334 | }
335 |
336 | /**
337 | * Write all parts and the last boundary to the specified output stream.
338 | *
339 | * @param out The stream to write to.
340 | * @param parts The parts to write.
341 | *
342 | * @throws IOException If an I/O error occurs while writing the parts.
343 | */
344 | public static void sendParts(OutputStream out, final Part[] parts)
345 | throws IOException {
346 | sendParts(out, parts, DEFAULT_BOUNDARY_BYTES);
347 | }
348 |
349 | /**
350 | * Write all parts and the last boundary to the specified output stream.
351 | *
352 | * @param out The stream to write to.
353 | * @param parts The parts to write.
354 | * @param partBoundary The ASCII bytes to use as the part boundary.
355 | *
356 | * @throws IOException If an I/O error occurs while writing the parts.
357 | *
358 | * @since 3.0
359 | */
360 | public static void sendParts(OutputStream out, Part[] parts, byte[] partBoundary)
361 | throws IOException {
362 |
363 | if (parts == null) {
364 | throw new IllegalArgumentException("Parts may not be null");
365 | }
366 | if (partBoundary == null || partBoundary.length == 0) {
367 | throw new IllegalArgumentException("partBoundary may not be empty");
368 | }
369 | for (int i = 0; i < parts.length; i++) {
370 | // set the part boundary before the part is sent
371 | parts[i].setPartBoundary(partBoundary);
372 | parts[i].send(out);
373 | }
374 | out.write(EXTRA_BYTES);
375 | out.write(partBoundary);
376 | out.write(EXTRA_BYTES);
377 | out.write(CRLF_BYTES);
378 | }
379 |
380 | /**
381 | * Return the total sum of all parts and that of the last boundary
382 | *
383 | * @param parts The parts.
384 | * @return The total length
385 | *
386 | * @throws IOException If an I/O error occurs while writing the parts.
387 | */
388 | public static long getLengthOfParts(Part[] parts)
389 | throws IOException {
390 | return getLengthOfParts(parts, DEFAULT_BOUNDARY_BYTES);
391 | }
392 |
393 | /**
394 | * Gets the length of the multipart message including the given parts.
395 | *
396 | * @param parts The parts.
397 | * @param partBoundary The ASCII bytes to use as the part boundary.
398 | * @return The total length
399 | *
400 | * @throws IOException If an I/O error occurs while writing the parts.
401 | *
402 | * @since 3.0
403 | */
404 | public static long getLengthOfParts(Part[] parts, byte[] partBoundary) throws IOException {
405 | if (parts == null) {
406 | throw new IllegalArgumentException("Parts may not be null");
407 | }
408 | long total = 0;
409 | for (int i = 0; i < parts.length; i++) {
410 | // set the part boundary before we calculate the part's length
411 | parts[i].setPartBoundary(partBoundary);
412 | long l = parts[i].length();
413 | if (l < 0) {
414 | return -1;
415 | }
416 | total += l;
417 | }
418 | total += EXTRA_BYTES.length;
419 | total += partBoundary.length;
420 | total += EXTRA_BYTES.length;
421 | total += CRLF_BYTES.length;
422 | return total;
423 | }
424 | }
425 |
--------------------------------------------------------------------------------
/android-lib/src/com/android/http/multipart/PartBase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/PartBase.java,v 1.5 2004/04/18 23:51:37 jsdever Exp $
3 | * $Revision: 480424 $
4 | * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
5 | *
6 | * ====================================================================
7 | *
8 | * Licensed to the Apache Software Foundation (ASF) under one or more
9 | * contributor license agreements. See the NOTICE file distributed with
10 | * this work for additional information regarding copyright ownership.
11 | * The ASF licenses this file to You under the Apache License, Version 2.0
12 | * (the "License"); you may not use this file except in compliance with
13 | * the License. You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | * ====================================================================
23 | *
24 | * This software consists of voluntary contributions made by many
25 | * individuals on behalf of the Apache Software Foundation. For more
26 | * information on the Apache Software Foundation, please see
27 | * .
28 | *
29 | */
30 |
31 | package com.android.http.multipart;
32 |
33 |
34 | /**
35 | * Provides setters and getters for the basic Part properties.
36 | *
37 | * @author Michael Becke
38 | */
39 | public abstract class PartBase extends Part {
40 |
41 | /** Name of the file part. */
42 | private String name;
43 |
44 | /** Content type of the file part. */
45 | private String contentType;
46 |
47 | /** Content encoding of the file part. */
48 | private String charSet;
49 |
50 | /** The transfer encoding. */
51 | private String transferEncoding;
52 |
53 | /**
54 | * Constructor.
55 | *
56 | * @param name The name of the part
57 | * @param contentType The content type, or null
58 | * @param charSet The character encoding, or null
59 | * @param transferEncoding The transfer encoding, or null
60 | */
61 | public PartBase(String name, String contentType, String charSet, String transferEncoding) {
62 |
63 | if (name == null) {
64 | throw new IllegalArgumentException("Name must not be null");
65 | }
66 | this.name = name;
67 | this.contentType = contentType;
68 | this.charSet = charSet;
69 | this.transferEncoding = transferEncoding;
70 | }
71 |
72 | /**
73 | * Returns the name.
74 | * @return The name.
75 | * @see Part#getName()
76 | */
77 | @Override
78 | public String getName() {
79 | return this.name;
80 | }
81 |
82 | /**
83 | * Returns the content type of this part.
84 | * @return String The name.
85 | */
86 | @Override
87 | public String getContentType() {
88 | return this.contentType;
89 | }
90 |
91 | /**
92 | * Return the character encoding of this part.
93 | * @return String The name.
94 | */
95 | @Override
96 | public String getCharSet() {
97 | return this.charSet;
98 | }
99 |
100 | /**
101 | * Returns the transfer encoding of this part.
102 | * @return String The name.
103 | */
104 | @Override
105 | public String getTransferEncoding() {
106 | return transferEncoding;
107 | }
108 |
109 | /**
110 | * Sets the character encoding.
111 | *
112 | * @param charSet the character encoding, or null to exclude the character
113 | * encoding header
114 | */
115 | public void setCharSet(String charSet) {
116 | this.charSet = charSet;
117 | }
118 |
119 | /**
120 | * Sets the content type.
121 | *
122 | * @param contentType the content type, or null to exclude the content type header
123 | */
124 | public void setContentType(String contentType) {
125 | this.contentType = contentType;
126 | }
127 |
128 | /**
129 | * Sets the part name.
130 | *
131 | * @param name
132 | */
133 | public void setName(String name) {
134 | if (name == null) {
135 | throw new IllegalArgumentException("Name must not be null");
136 | }
137 | this.name = name;
138 | }
139 |
140 | /**
141 | * Sets the transfer encoding.
142 | *
143 | * @param transferEncoding the transfer encoding, or null to exclude the
144 | * transfer encoding header
145 | */
146 | public void setTransferEncoding(String transferEncoding) {
147 | this.transferEncoding = transferEncoding;
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/android-lib/src/com/android/http/multipart/PartSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/PartSource.java,v 1.6 2004/04/18 23:51:37 jsdever Exp $
3 | * $Revision: 480424 $
4 | * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
5 | *
6 | * ====================================================================
7 | *
8 | * Licensed to the Apache Software Foundation (ASF) under one or more
9 | * contributor license agreements. See the NOTICE file distributed with
10 | * this work for additional information regarding copyright ownership.
11 | * The ASF licenses this file to You under the Apache License, Version 2.0
12 | * (the "License"); you may not use this file except in compliance with
13 | * the License. You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | * ====================================================================
23 | *
24 | * This software consists of voluntary contributions made by many
25 | * individuals on behalf of the Apache Software Foundation. For more
26 | * information on the Apache Software Foundation, please see
27 | * .
28 | *
29 | */
30 |
31 | package com.android.http.multipart;
32 |
33 | import java.io.IOException;
34 | import java.io.InputStream;
35 |
36 | /**
37 | * An interface for providing access to data when posting MultiPart messages.
38 | *
39 | * @see FilePart
40 | *
41 | * @author Michael Becke
42 | *
43 | * @since 2.0
44 | */
45 | public interface PartSource {
46 |
47 | /**
48 | * Gets the number of bytes contained in this source.
49 | *
50 | * @return a value >= 0
51 | */
52 | long getLength();
53 |
54 | /**
55 | * Gets the name of the file this source represents.
56 | *
57 | * @return the fileName used for posting a MultiPart file part
58 | */
59 | String getFileName();
60 |
61 | /**
62 | * Gets a new InputStream for reading this source. This method can be
63 | * called more than once and should therefore return a new stream every
64 | * time.
65 | *
66 | * @return a new InputStream
67 | *
68 | * @throws IOException if an error occurs when creating the InputStream
69 | */
70 | InputStream createInputStream() throws IOException;
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/android-lib/src/com/android/http/multipart/StringPart.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/StringPart.java,v 1.11 2004/04/18 23:51:37 jsdever Exp $
3 | * $Revision: 480424 $
4 | * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
5 | *
6 | * ====================================================================
7 | *
8 | * Licensed to the Apache Software Foundation (ASF) under one or more
9 | * contributor license agreements. See the NOTICE file distributed with
10 | * this work for additional information regarding copyright ownership.
11 | * The ASF licenses this file to You under the Apache License, Version 2.0
12 | * (the "License"); you may not use this file except in compliance with
13 | * the License. You may obtain a copy of the License at
14 | *
15 | * http://www.apache.org/licenses/LICENSE-2.0
16 | *
17 | * Unless required by applicable law or agreed to in writing, software
18 | * distributed under the License is distributed on an "AS IS" BASIS,
19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | * See the License for the specific language governing permissions and
21 | * limitations under the License.
22 | * ====================================================================
23 | *
24 | * This software consists of voluntary contributions made by many
25 | * individuals on behalf of the Apache Software Foundation. For more
26 | * information on the Apache Software Foundation, please see
27 | * .
28 | *
29 | */
30 |
31 | package com.android.http.multipart;
32 |
33 | import java.io.OutputStream;
34 | import java.io.IOException;
35 |
36 | import org.apache.http.util.EncodingUtils;
37 |
38 | /**
39 | * Simple string parameter for a multipart post
40 | *
41 | * @author Matthew Albright
42 | * @author Jeff Dever
43 | * @author Mike Bowler
44 | * @author Oleg Kalnichevski
45 | *
46 | * @since 2.0
47 | */
48 | public class StringPart extends PartBase {
49 | /** Default content encoding of string parameters. */
50 | public static final String DEFAULT_CONTENT_TYPE = "text/plain";
51 |
52 | /** Default charset of string parameters*/
53 | public static final String DEFAULT_CHARSET = "US-ASCII";
54 |
55 | /** Default transfer encoding of string parameters*/
56 | public static final String DEFAULT_TRANSFER_ENCODING = "8bit";
57 |
58 | /** Contents of this StringPart. */
59 | private byte[] content;
60 |
61 | /** The String value of this part. */
62 | private String value;
63 |
64 | /**
65 | * Constructor.
66 | *
67 | * @param name The name of the part
68 | * @param value the string to post
69 | * @param charset the charset to be used to encode the string, if null
70 | * the {@link #DEFAULT_CHARSET default} is used
71 | */
72 | public StringPart(String name, String value, String charset) {
73 |
74 | super(
75 | name,
76 | DEFAULT_CONTENT_TYPE,
77 | charset == null ? DEFAULT_CHARSET : charset,
78 | DEFAULT_TRANSFER_ENCODING
79 | );
80 | if (value == null) {
81 | throw new IllegalArgumentException("Value may not be null");
82 | }
83 | if (value.indexOf(0) != -1) {
84 | // See RFC 2048, 2.8. "8bit Data"
85 | throw new IllegalArgumentException("NULs may not be present in string parts");
86 | }
87 | this.value = value;
88 | }
89 |
90 | /**
91 | * Constructor.
92 | *
93 | * @param name The name of the part
94 | * @param value the string to post
95 | */
96 | public StringPart(String name, String value) {
97 | this(name, value, null);
98 | }
99 |
100 | /**
101 | * Gets the content in bytes. Bytes are lazily created to allow the charset to be changed
102 | * after the part is created.
103 | *
104 | * @return the content in bytes
105 | */
106 | private byte[] getContent() {
107 | if (content == null) {
108 | content = EncodingUtils.getBytes(value, getCharSet());
109 | }
110 | return content;
111 | }
112 |
113 | /**
114 | * Writes the data to the given OutputStream.
115 | * @param out the OutputStream to write to
116 | * @throws IOException if there is a write error
117 | */
118 | @Override
119 | protected void sendData(OutputStream out) throws IOException {
120 | out.write(getContent());
121 | }
122 |
123 | /**
124 | * Return the length of the data.
125 | * @return The length of the data.
126 | * @see Part#lengthOfData()
127 | */
128 | @Override
129 | protected long lengthOfData() {
130 | return getContent().length;
131 | }
132 |
133 | /* (non-Javadoc)
134 | * @see org.apache.commons.httpclient.methods.multipart.BasePart#setCharSet(java.lang.String)
135 | */
136 | @Override
137 | public void setCharSet(String charSet) {
138 | super.setCharSet(charSet);
139 | this.content = null;
140 | }
141 |
142 | }
143 |
--------------------------------------------------------------------------------
/android-lib/src/com/catchnotes/api/CatchAccount.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2011 Catch.com, Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | package com.catchnotes.api;
18 |
19 | /**
20 | * Represents a Catch account.
21 | *
22 | * Provides information such as user name, email address, account creation date, etc.
23 | */
24 | public class CatchAccount {
25 | public long id;
26 | public String email;
27 | public String username;
28 | public long accountCreatedOn;
29 | public String auth_token;
30 | public long periodLimit;
31 | public long periodUsage;
32 | public long periodStart;
33 | public long periodEnd;
34 | public long subscriptionEnd;
35 | public int accountLevel;
36 | public String accountDescription;
37 |
38 | public CatchAccount() {
39 | id = -1;
40 | email = "";
41 | username = "";
42 | accountCreatedOn = -1;
43 | auth_token = "";
44 | periodLimit = -1;
45 | periodUsage = -1;
46 | periodStart = -1;
47 | periodEnd = -1;
48 | subscriptionEnd = -1;
49 | accountLevel = -1;
50 | accountDescription = "";
51 | }
52 |
53 | public CatchAccount(long id, String email, String username, long accountCreatedOn, String auth_token, int accountLevel, String accountDescription, long monthlyLimit, long usage, long usageStart, long usageEnd, long subscriptionEnd) {
54 | this.id = id;
55 | this.email = email;
56 | this.username = username;
57 | this.accountCreatedOn = accountCreatedOn;
58 | this.auth_token = auth_token;
59 | this.periodLimit = monthlyLimit;
60 | this.periodUsage = usage;
61 | this.periodStart = usageStart;
62 | this.periodEnd = usageEnd;
63 | this.subscriptionEnd = subscriptionEnd;
64 | this.accountLevel = accountLevel;
65 | this.accountDescription = accountDescription;
66 | }
67 |
68 | @Override
69 | public String toString() {
70 | return
71 | "email=\"" + email + "\" " +
72 | "id=" + id + ' ' +
73 | "username=\"" + username + "\" " +
74 | "accountCreatedOn=" + accountCreatedOn + ' ' +
75 | "accountLevel=" + accountLevel + ' ' +
76 | "accountDescription=\"" + accountDescription + "\" " +
77 | "periodLimit=" + periodLimit + ' ' +
78 | "periodUsage=" + periodUsage + ' ' +
79 | "periodStart=" + periodStart + ' ' +
80 | "periodEnd=" + periodEnd + ' ' +
81 | "subscriptionEnd=" + subscriptionEnd + ' ' +
82 | "auth_token=" + auth_token;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/android-lib/src/com/catchnotes/api/CatchMedia.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2011 Catch.com, Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | package com.catchnotes.api;
18 |
19 | import java.io.File;
20 |
21 | /**
22 | * Represents a media item.
23 | */
24 | public class CatchMedia {
25 | public String id;
26 | public String note_id;
27 | public long created_at;
28 | public String content_type;
29 | public String src;
30 | public long size;
31 | public String filename;
32 | public boolean voice_hint;
33 | public File data;
34 |
35 | public CatchMedia() {
36 | id = "";
37 | note_id = "";
38 | created_at = 0;
39 | content_type = "";
40 | src = "";
41 | size = 0;
42 | data = null;
43 | filename = "";
44 | voice_hint = false;
45 | }
46 |
47 | public String toString() {
48 | return "apiId=" + id + " nodeId=" + note_id + " created_at=" + created_at +
49 | " type=" + content_type + " src=" + src + " size=" + size +
50 | " filename=" + filename + " voice_hint=" + voice_hint + " data=" +
51 | ((data == null) ? "null" : data.getPath());
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/android-lib/src/com/catchnotes/api/CatchNote.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2011 Catch.com, Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | package com.catchnotes.api;
18 |
19 | import java.util.HashMap;
20 | import java.util.List;
21 | import java.util.Map;
22 |
23 | /**
24 | * Represents a note.
25 | */
26 | public class CatchNote {
27 | public static final String NOT_SET = "NOT_SET";
28 | public static final int NOT_SET_INT = -1;
29 | public static final String NODE_ID_NEVER_SYNCED = "-1";
30 | public static final String MODE_PRIVATE = "";
31 | public static final String MODE_SET_PRIVATE = "private";
32 | public static final String MODE_SHARED = "shared";
33 | public static final String MODE_PUBLIC = "public";
34 | public static final String DEFAULT_OWNER = "Me";
35 | public static final int PENDING_OPERATION_NONE = 0;
36 | public static final int PENDING_OPERATION_SYNC = 1;
37 | public static final int PENDING_OPERATION_DELETE = 2;
38 | private static final String STARRED_KEY = "starred";
39 |
40 | public String id;
41 | public long parentId;
42 | public String parentNodeId;
43 | public String source;
44 | public String sourceUrl;
45 | public CharSequence owner;
46 | public long ownerId;
47 | public long creationTime;
48 | public long modificationTime;
49 | public long reminderTime;
50 | public CharSequence text;
51 | public CharSequence summary;
52 | public long depth;
53 | public long children;
54 | public CharSequence mode;
55 | public CharSequence browserUrl;
56 |
57 | public double latitude;
58 | public double longitude;
59 | public double altitude;
60 | public double speed;
61 | public double bearing;
62 | public double accuracyPosition;
63 | public double accuracyAltitude;
64 | public long serverModifiedAt;
65 |
66 | public List tags;
67 | public List mediaList;
68 | public Map annotations;
69 | public int apiPendingOp;
70 |
71 | public CatchNote() {
72 | id = NODE_ID_NEVER_SYNCED;
73 | parentId = NOT_SET_INT;
74 | parentNodeId = NODE_ID_NEVER_SYNCED;
75 | source = NOT_SET;
76 | sourceUrl = NOT_SET;
77 | owner = NOT_SET;
78 | ownerId = NOT_SET_INT;
79 | creationTime = NOT_SET_INT;
80 | modificationTime = NOT_SET_INT;
81 | reminderTime = NOT_SET_INT;
82 | text = NOT_SET;
83 | summary = NOT_SET;
84 | depth = NOT_SET_INT;
85 | children = NOT_SET_INT;
86 | mode = MODE_PRIVATE;
87 | browserUrl = NOT_SET;
88 |
89 | latitude = 0;
90 | longitude = 0;
91 | altitude = 0;
92 | speed = 0;
93 | bearing = 0;
94 | accuracyPosition = 0;
95 | accuracyAltitude = 0;
96 | serverModifiedAt = 0;
97 | apiPendingOp = PENDING_OPERATION_NONE;
98 |
99 | tags = null;
100 | mediaList = null;
101 | annotations = null;
102 | }
103 |
104 | /**
105 | * Return tags contained within note.
106 | *
107 | * @return Tags in note separated by spaces.
108 | */
109 | public CharSequence getTags() {
110 | if (tags == null) {
111 | return "";
112 | }
113 |
114 | StringBuffer sb = new StringBuffer();
115 |
116 | for (CharSequence tag : tags) {
117 | sb.append(tag + " ");
118 | }
119 |
120 | return sb.toString().trim();
121 | }
122 |
123 | /**
124 | * Copy a given note.
125 | *
126 | * @param note The note to copy.
127 | */
128 | public void copy(CatchNote note) {
129 | if (note != null) {
130 | this.id = note.id;
131 | this.parentId = note.parentId;
132 | this.owner = note.owner;
133 | this.ownerId = note.ownerId;
134 | this.creationTime = note.creationTime;
135 | this.modificationTime = note.modificationTime;
136 | this.reminderTime = note.reminderTime;
137 | this.text = note.text;
138 | this.summary = note.summary;
139 | this.depth = note.depth;
140 | this.children = note.children;
141 | this.mode = note.mode;
142 | this.browserUrl = note.browserUrl;
143 | this.source = note.source;
144 | this.sourceUrl = note.sourceUrl;
145 |
146 | this.latitude = note.latitude;
147 | this.longitude = note.longitude;
148 | this.altitude = note.altitude;
149 | this.speed = note.speed;
150 | this.bearing = note.bearing;
151 | this.accuracyPosition = note.accuracyPosition;
152 | this.accuracyAltitude = note.accuracyAltitude;
153 | this.serverModifiedAt = note.serverModifiedAt;
154 | this.apiPendingOp = note.apiPendingOp;
155 |
156 | this.tags = note.tags;
157 | this.mediaList = note.mediaList;
158 | this.annotations = note.annotations;
159 | }
160 | }
161 |
162 | /**
163 | * Turn note into a string of key : values.
164 | */
165 | @Override
166 | public String toString() {
167 | return
168 | "id:" + id +
169 | " parent_id:" + parentId +
170 | " parentNodeId:" + parentNodeId +
171 | " owner:" + owner +
172 | " ownerId:" + ownerId +
173 | " creationTime:" + creationTime +
174 | " modificationTime:" + modificationTime +
175 | " reminderTime:" + reminderTime +
176 | " text:" + text +
177 | " summary:" + summary +
178 | " depth:" + depth +
179 | " children:" + children +
180 | " mode: " + mode +
181 | " browserUrl: " + browserUrl +
182 | " source: " + source +
183 | " sourceUrl: " + sourceUrl +
184 | " latitude:" + latitude +
185 | " longitude:" + longitude +
186 | " altitude:" + altitude +
187 | " speed:" + speed +
188 | " bearing:" + bearing +
189 | " accuracyPosition:" + accuracyPosition +
190 | " accuracyAltitude:" + accuracyAltitude +
191 | " serverModifiedAt:" + serverModifiedAt +
192 | " tags:" + getTags() +
193 | " mediaList:" + mediaList +
194 | " annotations: " + annotations;
195 | }
196 |
197 | public CatchNote(Builder builder) {
198 | this.id = builder.id;
199 | this.parentId = builder.parentId;
200 | this.parentNodeId = builder.parentNodeId;
201 | this.owner = builder.owner;
202 | this.ownerId = builder.ownerId;
203 | this.creationTime = builder.creationTime;
204 | this.modificationTime = builder.modificationTime;
205 | this.reminderTime = builder.reminderTime;
206 | this.text = builder.text;
207 | this.summary = builder.summary;
208 | this.depth = builder.depth;
209 | this.children = builder.children;
210 | this.mode = builder.mode;
211 | this.browserUrl = builder.publicUrl;
212 | this.source = builder.source;
213 | this.sourceUrl = builder.sourceUrl;
214 |
215 | this.latitude = builder.latitude;
216 | this.longitude = builder.longitude;
217 | this.altitude = builder.altitude;
218 | this.speed = builder.speed;
219 | this.bearing = builder.bearing;
220 | this.accuracyPosition = builder.accuracyPosition;
221 | this.accuracyAltitude = builder.accuracyAltitude;
222 | this.serverModifiedAt = builder.serverModifiedAt;
223 | this.apiPendingOp = builder.apiPendingOp;
224 |
225 | this.tags = builder.tags;
226 | this.mediaList = builder.mediaList;
227 | this.annotations = builder.annotations;
228 | }
229 |
230 | public static class Builder {
231 | private String id;
232 | private long parentId;
233 | private String parentNodeId;
234 | private String source;
235 | private String sourceUrl;
236 | private CharSequence owner;
237 | private long ownerId;
238 | private long creationTime;
239 | private long modificationTime;
240 | private long reminderTime;
241 | private CharSequence text;
242 | private CharSequence summary;
243 | private long depth;
244 | private long children;
245 | private CharSequence mode;
246 | private CharSequence publicUrl;
247 |
248 | private double latitude;
249 | private double longitude;
250 | private double altitude;
251 | private double speed;
252 | private double bearing;
253 | private double accuracyPosition;
254 | private double accuracyAltitude;
255 | private long serverModifiedAt;
256 |
257 | private List tags;
258 | private List mediaList;
259 | private int apiPendingOp;
260 | private Map annotations;
261 |
262 | public Builder id(String id) {
263 | this.id = id;
264 | return this;
265 | }
266 |
267 | public Builder parentId(long parentId) {
268 | this.parentId = parentId;
269 | return this;
270 | }
271 |
272 | public Builder parentNodeId(String parentNodeId) {
273 | this.parentNodeId = parentNodeId;
274 | return this;
275 | }
276 |
277 | public Builder source(String source) {
278 | this.source = source;
279 | return this;
280 | }
281 |
282 | public Builder sourceUrl(String sourceUrl) {
283 | this.sourceUrl = sourceUrl;
284 | return this;
285 | }
286 |
287 | public Builder owner(CharSequence owner) {
288 | this.owner = owner;
289 | return this;
290 | }
291 |
292 | public Builder ownerId(long ownerId) {
293 | this.ownerId = ownerId;
294 | return this;
295 | }
296 |
297 | public Builder creationTime(long creationTime) {
298 | this.creationTime = creationTime;
299 | return this;
300 | }
301 |
302 | public Builder modificationTime(long modificationTime) {
303 | this.modificationTime = modificationTime;
304 | return this;
305 | }
306 |
307 | public Builder reminderTime(long reminderTime) {
308 | this.reminderTime = reminderTime;
309 | return this;
310 | }
311 |
312 | public Builder text(CharSequence text) {
313 | this.text = text;
314 | return this;
315 | }
316 |
317 | public Builder summary(CharSequence summary) {
318 | this.summary = summary;
319 | return this;
320 | }
321 |
322 | public Builder depth(long depth) {
323 | this.depth = depth;
324 | return this;
325 | }
326 |
327 | public Builder children(long children) {
328 | this.children = children;
329 | return this;
330 | }
331 |
332 | public Builder mode(CharSequence mode) {
333 | this.mode = mode;
334 | return this;
335 | }
336 |
337 | public Builder publicUrl(CharSequence publicUrl) {
338 | this.publicUrl = publicUrl;
339 | return this;
340 | }
341 |
342 | public Builder latitude(double latitude) {
343 | this.latitude = latitude;
344 | return this;
345 | }
346 |
347 | public Builder longitude(double longitude) {
348 | this.longitude = longitude;
349 | return this;
350 | }
351 |
352 | public Builder altitude(double altitude) {
353 | this.altitude = altitude;
354 | return this;
355 | }
356 |
357 | public Builder speed(double speed) {
358 | this.speed = speed;
359 | return this;
360 | }
361 |
362 | public Builder bearing(double bearing) {
363 | this.bearing = bearing;
364 | return this;
365 | }
366 |
367 | public Builder accuracyPosition(double accuracyPosition) {
368 | this.accuracyPosition = accuracyPosition;
369 | return this;
370 | }
371 |
372 | public Builder accuracyAltitude(double accuracyAltitude) {
373 | this.accuracyAltitude = accuracyAltitude;
374 | return this;
375 | }
376 |
377 | public Builder serverModifiedAt(long serverModifiedAt) {
378 | this.serverModifiedAt = serverModifiedAt;
379 | return this;
380 | }
381 |
382 | public Builder labels(List tags) {
383 | this.tags = tags;
384 | return this;
385 | }
386 |
387 | public Builder mediaList(List mediaList) {
388 | this.mediaList = mediaList;
389 | return this;
390 | }
391 |
392 | public Builder apiPendingOp(int apiPendingOp) {
393 | this.apiPendingOp = apiPendingOp;
394 | return this;
395 | }
396 |
397 | public Builder annotations(Map annotations) {
398 | this.annotations = annotations;
399 | return this;
400 | }
401 |
402 | public Builder annotationStarred(int annotationStarred) {
403 | if (annotationStarred == NOT_SET_INT) {
404 | return this;
405 | }
406 | if (this.annotations == null) {
407 | annotations = new HashMap();
408 | annotations.put(STARRED_KEY, Boolean.toString(annotationStarred == 1));
409 | }
410 | return this;
411 | }
412 |
413 | public CatchNote build() {
414 | return new CatchNote(this);
415 | }
416 | }
417 | }
418 |
--------------------------------------------------------------------------------
/android-lib/src/com/catchnotes/api/CatchNoteRef.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2011 Catch.com, Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | package com.catchnotes.api;
18 |
19 | /**
20 | * References a note by ID and server modification timestamp.
21 | */
22 | public class CatchNoteRef {
23 | public String nodeId;
24 | public String serverModified;
25 |
26 | public CatchNoteRef() {
27 | }
28 |
29 | public CatchNoteRef(String nodeId, String serverModified) {
30 | this.nodeId = nodeId;
31 | this.serverModified = serverModified;
32 | }
33 |
34 | @Override
35 | public String toString() {
36 | return "[ nodeId=" + nodeId + " serverModified=" + serverModified + " ]";
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/android-lib/src/com/catchnotes/api/VersionedCatchHttpClient.java:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2011 Catch.com, Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | package com.catchnotes.api;
18 |
19 | import java.io.IOException;
20 | import java.io.UnsupportedEncodingException;
21 | import java.net.URI;
22 | import java.net.URLEncoder;
23 |
24 | import org.apache.http.HttpHost;
25 | import org.apache.http.HttpRequest;
26 | import org.apache.http.HttpResponse;
27 | import org.apache.http.HttpVersion;
28 | import org.apache.http.client.ClientProtocolException;
29 | import org.apache.http.client.HttpClient;
30 | import org.apache.http.client.ResponseHandler;
31 | import org.apache.http.client.methods.HttpRequestBase;
32 | import org.apache.http.client.methods.HttpUriRequest;
33 | import org.apache.http.client.params.HttpClientParams;
34 | import org.apache.http.conn.ClientConnectionManager;
35 | import org.apache.http.impl.client.DefaultHttpClient;
36 | import org.apache.http.params.BasicHttpParams;
37 | import org.apache.http.params.HttpConnectionParams;
38 | import org.apache.http.params.HttpParams;
39 | import org.apache.http.params.HttpProtocolParams;
40 | import org.apache.http.protocol.HTTP;
41 | import org.apache.http.protocol.HttpContext;
42 |
43 | import android.content.Context;
44 | import android.net.http.AndroidHttpClient;
45 | import android.os.Build;
46 |
47 | public abstract class VersionedCatchHttpClient implements HttpClient {
48 | protected String mEncodedAccessToken;
49 | protected HttpClient mHttpClient;
50 |
51 | public static VersionedCatchHttpClient newInstance(String userAgent, Context context) {
52 | VersionedCatchHttpClient client;
53 |
54 | if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
55 | client = new PreFroyoCatchHttpClient(userAgent);
56 | } else {
57 | client = new CatchHttpClient(userAgent, context);
58 | }
59 |
60 | return client;
61 | }
62 |
63 | private static class PreFroyoCatchHttpClient extends VersionedCatchHttpClient {
64 | public PreFroyoCatchHttpClient(String userAgent) {
65 | HttpParams params = new BasicHttpParams();
66 | HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
67 | HttpProtocolParams.setUserAgent(params, userAgent);
68 | HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
69 |
70 | // Use some properties set in the default impl of AndroidHttpdClient
71 |
72 | // Turn off stale checking. Our connections break all the time anyway,
73 | // and it's not worth it to pay the penalty of checking every time.
74 | HttpConnectionParams.setStaleCheckingEnabled(params, false);
75 |
76 | // Default connection and socket timeout of 20 seconds.
77 | HttpConnectionParams.setConnectionTimeout(params, 20000);
78 | HttpConnectionParams.setSoTimeout(params, 20000);
79 | HttpConnectionParams.setSocketBufferSize(params, 8192);
80 |
81 | mHttpClient = new DefaultHttpClient(params);
82 | }
83 | }
84 |
85 | private static class CatchHttpClient extends VersionedCatchHttpClient {
86 | public CatchHttpClient(String userAgent, Context context) {
87 | mHttpClient = AndroidHttpClient.newInstance(userAgent, context);
88 | HttpParams httpParams = mHttpClient.getParams();
89 | HttpClientParams.setRedirecting(httpParams, true);
90 | HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
91 | HttpProtocolParams.setContentCharset(httpParams, HTTP.UTF_8);
92 | }
93 |
94 | public void close() {
95 | ((AndroidHttpClient) mHttpClient).close();
96 | }
97 | }
98 |
99 | public void close() {
100 | }
101 |
102 | public void setAccessToken(String accessToken) {
103 | try {
104 | mEncodedAccessToken = "access_token=" + URLEncoder.encode(accessToken, HTTP.UTF_8);
105 | } catch (UnsupportedEncodingException e) {
106 | throw new AssertionError(e);
107 | }
108 | }
109 |
110 | private void addAccessTokenToHttpUriRequest(HttpUriRequest httpUriRequest) {
111 | if (mEncodedAccessToken != null) {
112 | String query = httpUriRequest.getURI().getQuery();
113 |
114 | if (query == null || query.length() == 0) {
115 | ((HttpRequestBase) httpUriRequest).setURI(URI.create(httpUriRequest.getURI() + "?" + mEncodedAccessToken));
116 | } else {
117 | ((HttpRequestBase) httpUriRequest).setURI(URI.create(httpUriRequest.getURI() + "&" + mEncodedAccessToken));
118 | }
119 | }
120 | }
121 |
122 | public HttpParams getParams() {
123 | return mHttpClient.getParams();
124 | }
125 |
126 | public ClientConnectionManager getConnectionManager() {
127 | return mHttpClient.getConnectionManager();
128 | }
129 |
130 | public HttpResponse execute(HttpUriRequest httpUriRequest) throws IOException, ClientProtocolException {
131 | addAccessTokenToHttpUriRequest(httpUriRequest);
132 | return mHttpClient.execute(httpUriRequest);
133 | }
134 |
135 | public HttpResponse execute(HttpUriRequest httpUriRequest, HttpContext httpContext) throws IOException, ClientProtocolException {
136 | addAccessTokenToHttpUriRequest(httpUriRequest);
137 | return mHttpClient.execute(httpUriRequest, httpContext);
138 | }
139 |
140 | public HttpResponse execute(HttpHost httpHost, HttpRequest httpRequest) throws IOException, ClientProtocolException {
141 | addAccessTokenToHttpUriRequest((HttpUriRequest) httpRequest);
142 | return mHttpClient.execute(httpHost, httpRequest);
143 | }
144 |
145 | public HttpResponse execute(HttpHost httpHost, HttpRequest httpRequest, HttpContext httpContext) throws IOException, ClientProtocolException {
146 | addAccessTokenToHttpUriRequest((HttpUriRequest) httpRequest);
147 | return mHttpClient.execute(httpHost, httpRequest, httpContext);
148 | }
149 |
150 | public T execute(HttpUriRequest httpUriRequest, ResponseHandler extends T> responseHandler) throws IOException, ClientProtocolException {
151 | addAccessTokenToHttpUriRequest(httpUriRequest);
152 | return mHttpClient.execute(httpUriRequest, responseHandler);
153 | }
154 |
155 | public T execute(HttpUriRequest httpUriRequest, ResponseHandler extends T> responseHandler, HttpContext httpContext) throws IOException, ClientProtocolException {
156 | addAccessTokenToHttpUriRequest(httpUriRequest);
157 | return mHttpClient.execute(httpUriRequest, responseHandler, httpContext);
158 | }
159 |
160 | public T execute(HttpHost httpHost, HttpRequest httpRequest, ResponseHandler extends T> responseHandler) throws IOException, ClientProtocolException {
161 | addAccessTokenToHttpUriRequest((HttpUriRequest) httpRequest);
162 | return mHttpClient.execute(httpHost, httpRequest, responseHandler);
163 | }
164 |
165 | public T execute(HttpHost httpHost, HttpRequest httpRequest, ResponseHandler extends T> responseHandler, HttpContext httpContext) throws IOException, ClientProtocolException {
166 | addAccessTokenToHttpUriRequest((HttpUriRequest) httpRequest);
167 | return mHttpClient.execute(httpHost, httpRequest, responseHandler, httpContext);
168 | }
169 | }
170 |
--------------------------------------------------------------------------------