/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.waveprotocol.wave.client.doodad.attachment;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.waveprotocol.box.attachment.jso.AttachmentsResponseJsoImpl;
import org.waveprotocol.box.attachment.jso.AttachmentMetadataJsoImpl;
import org.waveprotocol.wave.client.debug.logger.DomLogger;
import org.waveprotocol.wave.client.scheduler.Scheduler.Task;
import org.waveprotocol.wave.client.scheduler.SchedulerInstance;
import org.waveprotocol.wave.client.scheduler.TimerService;
import org.waveprotocol.wave.common.logging.LoggerBundle;
import org.waveprotocol.wave.communication.gwt.JsonMessage;
import org.waveprotocol.wave.communication.json.JsonException;
import org.waveprotocol.wave.media.model.Attachment;
import org.waveprotocol.wave.model.util.CollectionUtils;
/**
* Gets attachments meta info from server.
*
* @author akaplanov@gmail.com (A. Kaplanov)
*/
public class AttachmentManagerImpl implements SimpleAttachmentManager {
interface GetAttachmentsInfoCallback {
public void onSuccess(List<Attachment> attachments);
public void onFailure(List<Attachment> attachments, String message);
}
private static final String ATTACHMENTS_INFO_URL_BASE = "/attachmentsInfo";
private static final LoggerBundle LOG = new DomLogger(AttachmentManagerImpl.class.getName());
private static SimpleAttachmentManager instance;
private final TimerService scheduler;
private final Map<String, AttachmentImpl> attachmentsInfo = new HashMap<String, AttachmentImpl>();
private final List<String> pendingQueue = new ArrayList<String>();
private final List<Listener> listeners = new ArrayList<Listener>();
public static SimpleAttachmentManager getInstance() {
if (instance != null) {
return instance;
}
instance = new AttachmentManagerImpl();
return instance;
}
private Task getAttachmentsInfoTask = new Task() {
@Override
public void execute() {
getAttachmentsInfo(new GetAttachmentsInfoCallback() {
@Override
public void onSuccess(List<Attachment> attachments) {
for (Attachment attachment : attachments) {
notifyImageUpdated(attachment);
}
}
@Override
public void onFailure(List<Attachment> attachments, String message) {
LOG.error().log("Getting of attachments info failed: " + message);
for (Attachment attachment : attachments) {
notifyImageUpdated(attachment);
}
}
});
}
};
private AttachmentManagerImpl() {
this.scheduler = SchedulerInstance.getMediumPriorityTimer();
}
@Override
public Attachment getAttachment(String attachmentId) {
AttachmentImpl attachment = attachmentsInfo.get(attachmentId);
if (attachment == null) {
attachment = new AttachmentImpl();
attachmentsInfo.put(attachmentId, attachment);
if (!pendingQueue.contains(attachmentId)) {
pendingQueue.add(attachmentId);
scheduler.schedule(getAttachmentsInfoTask);
}
}
return attachment;
}
@Override
public void addListener(Listener listener) {
listeners.add(listener);
}
@Override
public void removeListener(Listener listener) {
listeners.remove(listener);
}
private void notifyImageUpdated(Attachment attachment) {
for (Listener listener : listeners) {
listener.onContentUpdated(attachment);
listener.onThumbnailUpdated(attachment);
}
}
private void getAttachmentsInfo(final GetAttachmentsInfoCallback callback) {
LOG.trace().log("Getting attachments info");
String request = ATTACHMENTS_INFO_URL_BASE + "?attachmentIds=";
for (String attacmentId : pendingQueue) {
if (!request.endsWith("=")) {
request += ",";
}
request += attacmentId;
}
final List<String> requestedAttachments = new ArrayList<String>(pendingQueue);
pendingQueue.clear();
RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, request);
requestBuilder.setCallback(new RequestCallback() {
@Override
public void onResponseReceived(Request request, Response response) {
LOG.trace().log("Attachments info was received: ", response.getText());
if (response.getStatusCode() != Response.SC_OK) {
callback.onFailure(setFailureStatus(requestedAttachments), "Got back status code " + response.getStatusCode());
} else if (!response.getHeader("Content-Type").startsWith("application/json")) {
callback.onFailure(setFailureStatus(requestedAttachments), "Search service did not return json");
} else {
AttachmentsResponseJsoImpl attachmentsProto;
try {
attachmentsProto = JsonMessage.parse(response.getText());
} catch (JsonException e) {
callback.onFailure(setFailureStatus(requestedAttachments), e.getMessage());
return;
}
List<Attachment> attachments = initializeAttachments(attachmentsProto);
callback.onSuccess(attachments);
}
}
@Override
public void onError(Request request, Throwable e) {
LOG.error().log("Getting attachments info error: ", e);
callback.onFailure(setFailureStatus(requestedAttachments), e.getMessage());
}
});
try {
requestBuilder.send();
} catch (RequestException e) {
callback.onFailure(setFailureStatus(requestedAttachments), e.getMessage());
}
}
private List<Attachment> initializeAttachments(AttachmentsResponseJsoImpl protoAttachments) {
List<Attachment> attachments = CollectionUtils.newArrayList();
for (AttachmentMetadataJsoImpl protoAttachment : protoAttachments.getAttachment()) {
AttachmentImpl attachment = attachmentsInfo.get(protoAttachment.getAttachmentId());
if (attachment != null) {
attachment.copyMetadata(protoAttachment);
attachments.add(attachment);
}
}
return attachments;
}
private List<Attachment> setFailureStatus(List<String> attachmentIds) {
List<Attachment> attachments = new ArrayList<Attachment>();
for (String attachmentId : attachmentIds) {
AttachmentImpl attachment = attachmentsInfo.get(attachmentId);
if (attachment != null) {
attachment.setStatus(Attachment.Status.FAILED_AND_NOT_RETRYABLE);
attachments.add(attachment);
}
}
return attachments;
}
}