Java tutorial
/* * Copyright (C) 2014. BaasBox * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and limitations under the License. */ package com.baasbox.android; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.util.Pair; import android.webkit.MimeTypeMap; import com.baasbox.android.impl.Util; import com.baasbox.android.json.JsonArray; import com.baasbox.android.json.JsonException; import com.baasbox.android.json.JsonObject; import com.baasbox.android.net.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.util.EntityUtils; import java.io.*; import java.net.URLConnection; import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; /** * Represents a BaasBox file. * <p> * A file is an entity that can be stored on the server. * Unlike documents files do not dictate a format for their content, but they can * have optionally json attached data. * </p> * <p/> * <p> * Files can be created, stored and retrieved from the server either synchronously or asynchronously, * through the provided methods. * </p> * <p> * A BaasFile does not represent the content of the file, but an handle to the actual content. * The actual content can be obtained through a streaming api. * </p> * * @author Andrea Tortorella * @since 0.7.3 */ public class BaasFile extends BaasObject implements Parcelable { // ------------------------------ FIELDS ------------------------------ private JsonWrapper attachedData; private JsonObject metaData; private String mimeType; private String name; private String creationDate; private String id; private String author; private long contentLength; private long version; private final AtomicBoolean isBound = new AtomicBoolean(); private AtomicReference<byte[]> data = new AtomicReference<byte[]>(); // --------------------------- CONSTRUCTORS --------------------------- public BaasFile() { this(new JsonObject(), false); } public BaasFile(JsonObject attachedData) { this(attachedData, false); } BaasFile(JsonObject data, boolean fromServer) { super(); if (fromServer) { this.attachedData = new JsonWrapper(data); this.metaData = new JsonObject(); update(data); } else { this.attachedData = new JsonWrapper(data); } } void update(JsonObject fromServer) { isBound.set(true); this.attachedData.merge(fromServer.getObject("attachedData")); if (this.metaData == null) this.metaData = new JsonObject(); this.metaData.merge(fromServer.getObject("metadata")); this.id = fromServer.getString("id"); this.creationDate = fromServer.getString("_creation_date"); this.author = fromServer.getString("_author"); this.name = fromServer.getString("fileName"); this.contentLength = fromServer.getLong("contentLength"); this.version = fromServer.getLong("@version"); attachedData.setDirty(false); } @Override public void writeToParcel(Parcel dest, int flags) { Util.writeOptString(dest, name); Util.writeOptString(dest, id); Util.writeOptString(dest, creationDate); Util.writeOptString(dest, author); Util.writeOptString(dest, mimeType); dest.writeParcelable(attachedData, flags); dest.writeParcelable(metaData, flags); dest.writeLong(contentLength); dest.writeLong(version); Util.writeBoolean(dest, isBound.get()); Util.writeOptBytes(dest, data.get()); } private BaasFile(Parcel source) { name = Util.readOptString(source); id = Util.readOptString(source); creationDate = Util.readOptString(source); author = Util.readOptString(source); mimeType = Util.readOptString(source); attachedData = source.readParcelable(BaasFile.class.getClassLoader()); metaData = source.readParcelable(BaasFile.class.getClassLoader()); contentLength = source.readLong(); version = source.readLong(); isBound.set(Util.readBoolean(source)); data.set(Util.readOptBytes(source)); } public static final Creator<BaasFile> CREATOR = new Creator<BaasFile>() { @Override public BaasFile createFromParcel(Parcel source) { return new BaasFile(source); } @Override public BaasFile[] newArray(int size) { return new BaasFile[size]; } }; @Override public int describeContents() { return 0; } @Override public boolean isDirty() { return attachedData.isDirty(); } // -------------------------- STATIC METHODS -------------------------- public static RequestToken fetchAll(BaasHandler<List<BaasFile>> handler) { return fetchAll(null, RequestOptions.DEFAULT, handler); } public static RequestToken fetchAll(BaasQuery.Criteria filter, BaasHandler<List<BaasFile>> handler) { return fetchAll(filter, RequestOptions.DEFAULT, handler); } public static RequestToken fetchAll(BaasQuery.Criteria filter, int flags, BaasHandler<List<BaasFile>> handler) { BaasBox box = BaasBox.getDefaultChecked(); Files files = new Files(box, filter, flags, handler); return box.submitAsync(files); } public static BaasResult<List<BaasFile>> fetchAllSync() { return fetchAllSync(null); } public static BaasResult<List<BaasFile>> fetchAllSync(BaasQuery.Criteria filter) { BaasBox box = BaasBox.getDefaultChecked(); Files files = new Files(box, filter, RequestOptions.DEFAULT, null); return box.submitSync(files); } public static RequestToken fetch(String id, BaasHandler<BaasFile> handler) { return fetch(id, RequestOptions.DEFAULT, handler); } public static RequestToken fetch(String id, int flags, BaasHandler<BaasFile> handler) { BaasBox box = BaasBox.getDefaultChecked(); if (id == null) throw new IllegalArgumentException("id cannot be null"); BaasFile file = new BaasFile(); file.id = id; Details details = new Details(box, file, flags, handler); return box.submitAsync(details); } public static BaasResult<BaasFile> fetchSync(String id) { BaasBox box = BaasBox.getDefaultChecked(); if (id == null) throw new IllegalArgumentException("id cannot be null"); BaasFile file = new BaasFile(); file.id = id; Details details = new Details(box, file, RequestOptions.DEFAULT, null); return box.submitSync(details); } public static BaasResult<Void> deleteSync(String id) { BaasBox box = BaasBox.getDefaultChecked(); if (id == null) throw new IllegalArgumentException("id cannot be null"); Delete delete = new Delete(box, id, RequestOptions.DEFAULT, null); return box.submitSync(delete); } public static RequestToken delete(String id, BaasHandler<Void> handler) { return delete(id, RequestOptions.DEFAULT, handler); } public static RequestToken delete(String id, int flags, BaasHandler<Void> handler) { BaasBox box = BaasBox.getDefaultChecked(); if (id == null) throw new IllegalArgumentException("id cannot be null"); Delete delete = new Delete(box, id, flags, handler); return box.submitAsync(delete); } public static RequestToken fetchStream(String id, BaasHandler<BaasFile> handler) { BaasFile f = new BaasFile(); f.id = id; return f.doStream(-1, null, RequestOptions.DEFAULT, handler); } private RequestToken doStream(int size, String spec, int flags, BaasHandler<BaasFile> handler) { return doStream(this.id, spec, size, flags, new FileStreamer(this), handler); } private static <R> RequestToken doStream(String id, String sizeSpec, int sizeIdx, int flags, DataStreamHandler<R> contentHandler, BaasHandler<R> handler) { BaasBox box = BaasBox.getDefaultChecked(); if (contentHandler == null) throw new IllegalArgumentException("data handler cannot be null"); if (id == null) throw new IllegalArgumentException("id cannot be null"); AsyncStream<R> stream = new FileStream<R>(box, id, sizeSpec, sizeIdx, flags, contentHandler, handler); return box.submitAsync(stream); } public static BaasResult<BaasStream> streamImageSync(String id, int sizeId) { return doStreamSync(id, null, sizeId); } public Uri getStreamUri() { if (id == null) throw new IllegalArgumentException("file is not bound"); BaasBox cli = BaasBox.getDefaultChecked(); String endpoint = cli.requestFactory.getEndpoint("file/{}", id); return cli.requestFactory.getAuthenticatedUri(endpoint); } public static BaasResult<BaasStream> streamImageSync(String id, String spec) { return doStreamSync(id, spec, -1); } private static BaasResult<BaasStream> doStreamSync(String id, String spec, int sizeId) { BaasBox box = BaasBox.getDefaultChecked(); if (id == null) throw new IllegalArgumentException("id cannot be null"); StreamRequest synReq = new StreamRequest(box, "file", id, spec, sizeId); return box.submitSync(synReq); } public static <R> RequestToken stream(String id, DataStreamHandler<R> data, BaasHandler<R> handler) { return doStream(id, null, -1, RequestOptions.DEFAULT, data, handler); } public static <R> RequestToken streamImage(String id, int size, DataStreamHandler<R> data, BaasHandler<R> handler) { return doStream(id, null, size, RequestOptions.DEFAULT, data, handler); } public static <R> RequestToken stream(String id, int flags, DataStreamHandler<R> contentHandler, BaasHandler<R> handler) { return doStream(id, null, -1, flags, contentHandler, handler); } public static <R> RequestToken streamImage(String id, int size, int flags, DataStreamHandler<R> data, BaasHandler<R> handler) { return doStream(id, null, size, flags, data, handler); } // --------------------- GETTER / SETTER METHODS --------------------- public JsonObject getAttachedData() { return attachedData; } @Override public final boolean isFile() { return true; } @Override public final boolean isDocument() { return false; } /** * Retrieves the metadata associated with this file * coomputed by the server. * * @return an object containing metadata about this file or null if no metadata is found */ public JsonObject getMetadata() { return metaData; } @Override public String getAuthor() { return author; } public long getContentLength() { return this.contentLength; } @Override public String getCreationDate() { return creationDate; } @Override public String getId() { return id; } @Override public long getVersion() { return version; } public String getContentType() { return mimeType; } public byte[] getData() { return data.get(); } // -------------------------- OTHER METHODS -------------------------- public RequestToken delete(BaasHandler<Void> handler) { return delete(RequestOptions.DEFAULT, handler); } public RequestToken delete(int flags, BaasHandler<Void> handler) { BaasBox box = BaasBox.getDefaultChecked(); if (id == null) throw new IllegalStateException("this file is not bound to an entity on the server"); Delete delete = new Delete(box, this, flags, handler); return box.submitAsync(delete); } public BaasResult<Void> deleteSync() { BaasBox box = BaasBox.getDefaultChecked(); if (id == null) throw new IllegalStateException("this file is not bounded to an entity on the server"); Delete delete = new Delete(box, this, RequestOptions.DEFAULT, null); return box.submitSync(delete); } @Override public RequestToken grant(Grant grant, String username, int flags, BaasHandler<Void> handler) { BaasBox box = BaasBox.getDefaultChecked(); Access access = new Access(box, true, false, id, username, grant, flags, handler); return box.submitAsync(access); } @Override public RequestToken grantAll(Grant grant, String role, int flags, BaasHandler<Void> handler) { BaasBox box = BaasBox.getDefaultChecked(); Access access = new Access(box, true, true, id, role, grant, flags, handler); return box.submitAsync(access); } @Override public BaasResult<Void> grantAllSync(Grant grant, String role) { BaasBox box = BaasBox.getDefaultChecked(); Access access = new Access(box, true, true, id, role, grant, RequestOptions.DEFAULT, null); return box.submitSync(access); } @Override public BaasResult<Void> grantSync(Grant grant, String user) { BaasBox box = BaasBox.getDefaultChecked(); Access access = new Access(box, true, false, id, user, grant, RequestOptions.DEFAULT, null); return box.submitSync(access); } public RequestToken refresh(BaasHandler<BaasFile> handler) { return refresh(RequestOptions.DEFAULT, handler); } public RequestToken refresh(int flags, BaasHandler<BaasFile> handler) { BaasBox box = BaasBox.getDefaultChecked(); if (id == null) throw new IllegalStateException("this file is not bound to an entity on the server"); Details details = new Details(box, this, flags, handler); return box.submitAsync(details); } public BaasResult<BaasFile> refreshSync() { BaasBox box = BaasBox.getDefaultChecked(); if (id == null) throw new IllegalStateException("this file is not bound to an entity on the server"); Details details = new Details(box, this, RequestOptions.DEFAULT, null); return box.submitSync(details); } @Override public RequestToken revoke(Grant grant, String username, int flags, BaasHandler<Void> handler) { BaasBox box = BaasBox.getDefaultChecked(); Access access = new Access(box, false, false, id, username, grant, RequestOptions.DEFAULT, handler); return box.submitAsync(access); } @Override public RequestToken revokeAll(Grant grant, String role, int flags, BaasHandler<Void> handler) { BaasBox box = BaasBox.getDefaultChecked(); Access access = new Access(box, false, true, id, role, grant, RequestOptions.DEFAULT, handler); return box.submitAsync(access); } @Override public BaasResult<Void> revokeAllSync(Grant grant, String role) { BaasBox box = BaasBox.getDefaultChecked(); Access access = new Access(box, false, true, id, role, grant, RequestOptions.DEFAULT, null); return box.submitSync(access); } @Override public BaasResult<Void> revokeSync(Grant grant, String user) { BaasBox box = BaasBox.getDefaultChecked(); Access access = new Access(box, false, false, id, user, grant, RequestOptions.DEFAULT, null); return box.submitSync(access); } public RequestToken extractedContent(int flags, BaasHandler<String> handler) { BaasBox box = BaasBox.getDefault(); if (id == null) throw new IllegalArgumentException("id cannot be null"); ContentRequest req = new ContentRequest(box, id, flags, handler); return box.submitAsync(req); } private static class ContentRequest extends NetworkTask<String> { private final String file; protected ContentRequest(BaasBox box, String file, int flags, BaasHandler<String> handler) { super(box, flags, handler); this.file = file; } @Override protected String onOk(int status, HttpResponse response, BaasBox box) throws BaasException { try { return EntityUtils.toString(response.getEntity()); } catch (IOException e) { throw new BaasIOException("unable to parse content"); } } @Override protected HttpRequest request(BaasBox box) { String ep = box.requestFactory.getEndpoint("file/content/{}", file); return box.requestFactory.get(ep); } } public RequestToken extractedContent(BaasHandler<String> handler) { return extractedContent(RequestOptions.DEFAULT, handler); } public BaasResult<String> extractedContentSync() { BaasBox box = BaasBox.getDefaultChecked(); if (id == null) throw new IllegalArgumentException("id cannot be null"); ContentRequest req = new ContentRequest(box, id, RequestOptions.DEFAULT, null); return box.submitSync(req); } public RequestToken stream(BaasHandler<BaasFile> handler) { return doStream(-1, null, RequestOptions.DEFAULT, handler); } public RequestToken download(String path, BaasHandler<Pair<BaasFile, String>> handler) { return doStream(id, null, -1, RequestOptions.DEFAULT, new SaveToDisk(this, path), handler); } private static class SaveToDisk implements DataStreamHandler<Pair<BaasFile, String>> { final String fileName; final BaasFile file; FileOutputStream out; private SaveToDisk(BaasFile file, String fileName) { this.fileName = fileName; this.file = file; } @Override public void startData(String id, long contentLength, String contentType) throws Exception { out = new FileOutputStream(fileName); } @Override public void onData(byte[] data, int read) throws Exception { out.write(data, 0, read); } @Override public Pair<BaasFile, String> endData(String id, long contentLength, String contentType) throws Exception { return new Pair<BaasFile, String>(file, fileName); } @Override public void finishStream(String id) { if (out != null) { try { out.close(); } catch (IOException e) { // swallow } } } } public RequestToken streamImage(int sizeIdx, BaasHandler<BaasFile> handler) { return doStream(sizeIdx, null, RequestOptions.DEFAULT, handler); } public RequestToken streamImage(String sizeSpec, BaasHandler<BaasFile> handler) { return doStream(-1, sizeSpec, RequestOptions.DEFAULT, handler); } public <R> RequestToken stream(DataStreamHandler<R> contentHandler, BaasHandler<R> handler) { return stream(RequestOptions.DEFAULT, contentHandler, handler); } public <R> RequestToken stream(int flags, DataStreamHandler<R> contentHandler, BaasHandler<R> handler) { if (id == null) throw new IllegalStateException("this file is not bound to any remote entity"); return stream(id, flags, contentHandler, handler); } public <R> RequestToken stream(int sizeId, int flags, DataStreamHandler<R> contentHandler, BaasHandler<R> handler) { if (id == null) throw new IllegalStateException("this file is not bound to any remote entity"); return doStream(id, null, sizeId, flags, contentHandler, handler); } public BaasResult<BaasStream> streamSync() { if (id == null) throw new IllegalStateException("this is not bound to a remote entity"); return doStreamSync(id, null, -1); } public BaasResult<BaasStream> streamImageSync(String spec) { if (id == null) throw new IllegalStateException("this is not bound to a remote entity"); return doStreamSync(id, spec, -1); } public BaasResult<BaasStream> streamImaeSync(int sizeId) { if (id == null) throw new IllegalStateException("this is not bound to a remote entity"); return doStreamSync(id, null, sizeId); } public RequestToken upload(InputStream stream, BaasHandler<BaasFile> handler) { BaasBox box = BaasBox.getDefaultChecked(); Upload upload = uploadRequest(box, stream, RequestOptions.DEFAULT, handler, new JsonObject()); return box.submitAsync(upload); } private Upload uploadRequest(BaasBox box, InputStream stream, int flags, BaasHandler<BaasFile> handler, JsonObject acl) { RequestFactory factory = box.requestFactory; if (!isBound.compareAndSet(false, true)) { throw new IllegalArgumentException("you cannot upload new content for this file"); } if (stream == null) throw new IllegalArgumentException("doStream cannot be null"); boolean tryGuessExtension = false; if (this.mimeType == null) { try { this.mimeType = URLConnection.guessContentTypeFromStream(stream); tryGuessExtension = true; } catch (IOException e) { this.mimeType = "application/octet-doStream"; } } if (this.name == null) { this.name = UUID.randomUUID().toString(); if (tryGuessExtension) { String ext = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType); if (ext != null) { this.name = name + "." + ext; } } } String endpoint = factory.getEndpoint("file"); HttpRequest req = factory.uploadFile(endpoint, true, stream, name, mimeType, acl, attachedData); return new Upload(box, this, req, flags, handler); } public RequestToken upload(File file, BaasHandler<BaasFile> handler) { return upload(file, RequestOptions.DEFAULT, handler); } public RequestToken upload(byte[] bytes, BaasHandler<BaasFile> handler) { if (bytes == null) throw new IllegalArgumentException("bytes cannot be null"); ByteArrayInputStream in = new ByteArrayInputStream(bytes); return upload(in, RequestOptions.DEFAULT, handler); } public RequestToken upload(InputStream stream, int flags, BaasHandler<BaasFile> handler) { BaasBox box = BaasBox.getDefaultChecked(); RequestFactory factory = box.requestFactory; Upload req = uploadRequest(box, stream, flags, handler, new JsonObject()); return box.submitAsync(req); } public RequestToken upload(BaasACL acl, InputStream stream, BaasHandler<BaasFile> handler) { BaasBox box = BaasBox.getDefaultChecked(); Upload upload = uploadRequest(box, stream, RequestOptions.DEFAULT, handler, acl.toJson()); return box.submitAsync(upload); } public RequestToken upload(File file, int flags, BaasHandler<BaasFile> handler) { if (file == null) throw new IllegalArgumentException("file cannot be null"); try { FileInputStream fin = new FileInputStream(file); return upload(fin, flags, handler); } catch (FileNotFoundException e) { throw new IllegalArgumentException("file does not exists", e); } } public RequestToken upload(BaasACL acl, File file, BaasHandler<BaasFile> handler) { return upload(acl, file, RequestOptions.DEFAULT, handler); } public RequestToken upload(byte[] bytes, int flags, BaasHandler<BaasFile> handler) { return upload(BaasACL.builder().build(), bytes, flags, handler); } public RequestToken upload(BaasACL acl, byte[] bytes, BaasHandler<BaasFile> handler) { if (bytes == null) throw new IllegalArgumentException("bytes cannot be null"); ByteArrayInputStream in = new ByteArrayInputStream(bytes); return upload(acl, in, RequestOptions.DEFAULT, handler); } public RequestToken upload(BaasACL acl, InputStream stream, int flags, BaasHandler<BaasFile> handler) { BaasBox box = BaasBox.getDefaultChecked(); RequestFactory factory = box.requestFactory; Upload req = uploadRequest(box, stream, flags, handler, acl.toJson()); return box.submitAsync(req); } public RequestToken upload(BaasACL acl, File file, int flags, BaasHandler<BaasFile> handler) { if (file == null) throw new IllegalArgumentException("file cannot be null"); try { FileInputStream fin = new FileInputStream(file); return upload(acl, fin, flags, handler); } catch (FileNotFoundException e) { throw new IllegalArgumentException("file does not exists", e); } } public RequestToken upload(BaasACL acl, byte[] bytes, int flags, BaasHandler<BaasFile> handler) { if (bytes == null) throw new IllegalArgumentException("bytes cannot be null"); ByteArrayInputStream in = new ByteArrayInputStream(bytes); return upload(acl, in, flags, handler); } public BaasResult<BaasFile> uploadSync(InputStream stream) { return uploadSync(null, stream); } public BaasResult<BaasFile> uploadSync(BaasACL acl, InputStream stream) { BaasBox box = BaasBox.getDefaultChecked(); if (stream == null) throw new IllegalArgumentException("stream cannot be null"); Upload req = uploadRequest(box, stream, RequestOptions.DEFAULT, null, acl == null ? new JsonObject() : acl.toJson()); return box.submitSync(req); } public BaasResult<BaasFile> uploadSync(byte[] bytes) { return uploadSync(null, bytes); } public BaasResult<BaasFile> uploadSync(BaasACL acl, byte[] bytes) { BaasBox box = BaasBox.getDefaultChecked(); if (bytes == null) throw new IllegalArgumentException("bytes cannot be null"); ByteArrayInputStream in = new ByteArrayInputStream(bytes); Upload req = uploadRequest(box, in, RequestOptions.DEFAULT, null, acl == null ? new JsonObject() : acl.toJson()); return box.submitSync(req); } public BaasResult<BaasFile> uploadSync(File file) { return uploadSync(null, file); } public BaasResult<BaasFile> uploadSync(BaasACL acl, File file) { BaasBox box = BaasBox.getDefaultChecked(); if (file == null) throw new IllegalArgumentException("file cannot be null"); try { FileInputStream in = new FileInputStream(file); Upload req = uploadRequest(box, in, RequestOptions.DEFAULT, null, acl == null ? new JsonObject() : acl.toJson()); return box.submitSync(req); } catch (FileNotFoundException e) { throw new IllegalArgumentException("file does not exists", e); } } // -------------------------- INNER CLASSES -------------------------- private static final class Access extends BaasObject.Access { protected Access(BaasBox box, boolean add, boolean isRole, String id, String to, Grant grant, int flags, BaasHandler<Void> handler) { super(box, add, isRole, null, id, to, grant, flags, handler); } @Override protected String userGrant(RequestFactory factory, Grant grant, String collection, String id, String to) { return factory.getEndpoint("file/{}/{}/user/{}", id, grant.action, to); } @Override protected String roleGrant(RequestFactory factory, Grant grant, String collection, String id, String to) { return factory.getEndpoint("file/{}/{}/role/{}", id, grant.action, to); } } private static class FileStreamer extends StreamBody<BaasFile> { BaasFile file; FileStreamer(BaasFile file) { this.file = file; } @Override protected BaasFile convert(byte[] body, String id, String contentType, long contentLength) { file.data.set(body); file.mimeType = contentType; file.contentLength = contentLength; return file; } } private static class FileStream<R> extends AsyncStream<R> { private final String id; private HttpRequest request; protected FileStream(BaasBox box, String id, String sizeSpec, int sizeId, int flags, DataStreamHandler<R> dataStream, BaasHandler<R> handler) { super(box, flags, dataStream, handler); this.id = id; RequestFactory.Param param = null; if (sizeSpec != null) { param = new RequestFactory.Param("resize", sizeSpec); } else if (sizeId >= 0) { param = new RequestFactory.Param("sizeId", Integer.toString(sizeId)); } String endpoint = box.requestFactory.getEndpoint("file/{}", id); if (param != null) { request = box.requestFactory.get(endpoint, param); } else { request = box.requestFactory.get(endpoint); } } @Override protected String streamId() { return id; } @Override protected HttpRequest request(BaasBox box) { return request; } } private static final class Details extends NetworkTask<BaasFile> { private final BaasFile file; protected Details(BaasBox box, BaasFile file, int flags, BaasHandler<BaasFile> handler) { super(box, flags, handler); this.file = file; } @Override protected BaasFile onOk(int status, HttpResponse response, BaasBox box) throws BaasException { JsonObject jsonData = parseJson(response, box).getObject("data"); file.update(jsonData); return file; } @Override protected HttpRequest request(BaasBox box) { return box.requestFactory.get(box.requestFactory.getEndpoint("file/details/{}", file.id)); } } private static final class Delete extends NetworkTask<Void> { private final BaasFile file; private final String id; protected Delete(BaasBox box, BaasFile file, int flags, BaasHandler<Void> handler) { super(box, flags, handler); this.file = file; this.id = file.id; } protected Delete(BaasBox box, String id, int flags, BaasHandler<Void> handler) { super(box, flags, handler); this.id = id; this.file = null; } @Override protected Void onOk(int status, HttpResponse response, BaasBox box) throws BaasException { if (file != null) file.id = null; return null; } @Override protected Void onSkipRequest() throws BaasException { throw new BaasException("file is not bounded to an entity on the server"); } @Override protected HttpRequest request(BaasBox box) { if (id == null) { return null; } else { String endpoint = box.requestFactory.getEndpoint("file/{}", id); return box.requestFactory.delete(endpoint); } } } private static final class Files extends NetworkTask<List<BaasFile>> { private RequestFactory.Param[] params; protected Files(BaasBox box, BaasQuery.Criteria filter, int flags, BaasHandler<List<BaasFile>> handler) { super(box, flags, handler); if (filter == null) { params = null; } else { params = filter.toParams(); } } @Override protected List<BaasFile> onOk(int status, HttpResponse response, BaasBox box) throws BaasException { try { JsonArray details = parseJson(response, box).getArray("data"); List<BaasFile> files = new ArrayList<BaasFile>(); for (Object o : details) { JsonObject obj = (JsonObject) o; BaasFile f = new BaasFile(obj, true); files.add(f); } return files; } catch (JsonException e) { throw new BaasException(e); } } @Override protected HttpRequest request(BaasBox box) { String endpoint = box.requestFactory.getEndpoint("file/details"); if (params == null) { return box.requestFactory.get(endpoint); } else { return box.requestFactory.get(endpoint, params); } } } private static final class Upload extends NetworkTask<BaasFile> { private final BaasFile file; private final HttpRequest request; protected Upload(BaasBox box, BaasFile file, HttpRequest request, int flags, BaasHandler<BaasFile> handler) { super(box, flags, handler); this.file = file; this.request = request; } @Override protected BaasFile onOk(int status, HttpResponse response, BaasBox box) throws BaasException { JsonObject o = parseJson(response, box).getObject("data"); file.update(o); return file; } @Override protected HttpRequest request(BaasBox box) { return request; } } }