/* ButtonUploadAgent.java
Purpose:
Description:
History:
Jun 19, 2012 Created by pao
Copyright (C) 2011 Potix Corporation. All Rights Reserved.
*/
package org.zkoss.zats.mimic.impl.operation;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.eclipse.jetty.util.IO;
import org.zkoss.lang.Strings;
import org.zkoss.zats.common.util.MultiPartOutputStream;
import org.zkoss.zats.mimic.AgentException;
import org.zkoss.zats.mimic.ComponentAgent;
import org.zkoss.zats.mimic.impl.ClientCtrl;
import org.zkoss.zats.mimic.impl.EventDataManager;
import org.zkoss.zats.mimic.impl.OperationAgentBuilder;
import org.zkoss.zats.mimic.impl.Util;
import org.zkoss.zats.mimic.operation.UploadAgent;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.sys.DesktopCtrl;
/**
* The abstract builder of upload agent.
* @author pao
* @since 1.1.0
*/
public abstract class AbstractUploadAgentBuilder implements OperationAgentBuilder<ComponentAgent, UploadAgent> {
private final static Logger logger = Logger.getLogger(AbstractUploadAgentBuilder.class.getName());
public Class<UploadAgent> getOperationClass() {
return UploadAgent.class;
}
abstract class AbstractUploadAgentImpl extends AgentDelegator<ComponentAgent> implements UploadAgent {
private HttpURLConnection conn;
private MultiPartOutputStream multipartStream;
private boolean isMultiple;
public AbstractUploadAgentImpl(ComponentAgent target) {
super(target);
}
public void upload(File file, String contentType) {
if (file == null)
throw new NullPointerException("file can't be null.");
InputStream is = null;
try {
is = new BufferedInputStream(new FileInputStream(file));
upload(file.getName(), is, contentType);
} catch (IOException e) {
throw new AgentException(e.getMessage(), e);
} finally {
Util.close(is);
}
}
protected abstract String getUploadFlag();
public void upload(String fileName, InputStream content, String contentType) {
if (fileName == null)
throw new NullPointerException("file name can't be null.");
if (content == null)
throw new NullPointerException("content stream can't be null.");
// first time upload
if (multipartStream == null) {
// fetch and check upload flag
String flag = getUploadFlag();
if (flag == null || flag.length() == 0)
throw new AgentException("upload feature doesn't turn on.");
else {
Map<String, String> attr = new HashMap<String, String>();
for (String token : flag.split("\\s*,\\s*")) {
if (token.trim().length() <= 0)
continue;
String[] tokens = token.split("[\\s=]+");
if (tokens.length == 1)
attr.put("", tokens[0]);
else if (tokens.length >= 2)
attr.put(tokens[0], tokens[1]);
}
String value = attr.get("");
if ("false".equals(value))
throw new AgentException("upload feature doesn't turn on.");
isMultiple = Boolean.parseBoolean(attr.get("multiple"));
}
try {
// parameters
String param = "?uuid={0}&dtid={1}&sid=0&maxsize=undefined";
param = MessageFormat.format(param, target.getUuid(), target.getDesktop().getId());
// open connection
String boundary = Util.generateRandomString(); // boundary for multipart
ClientCtrl cc = (ClientCtrl) getClient();
conn = cc.getConnection("/zkau/upload" + param, "POST");
conn.addRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
conn.setDoInput(true);
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
multipartStream = new MultiPartOutputStream(os, boundary);
} catch (IOException e) {
clean();
throw new AgentException(e.getMessage(), e);
}
} else if (!isMultiple) { // check allow of multiple
throw new AgentException("multiple upload feature doesn't turn on.");
}
try {
// additional headers
String contentDisposition = "Content-Disposition: form-data; name=\"file\"; filename=\"{0}\"";
contentDisposition = MessageFormat.format(contentDisposition, fileName);
String[] headers = new String[] { contentDisposition };
// upload multipart data
multipartStream.startPart(contentType != null ? contentType : "application/octet-stream", headers); // default content type
int b;
while ((b = content.read()) >= 0)
multipartStream.write(b);
} catch (IOException e) {
clean();
throw new AgentException(e.getMessage(), e);
}
}
public void finish() {
if (multipartStream == null)
return;
// finish upload first and get the correct key
clean();
int key = ((DesktopCtrl) target.getDesktop().getDelegatee()).getNextKey() - 1;
String contentId = Strings.encode(new StringBuffer(12).append("z__ul_"), key).toString(); // copy from AuUploader
// perform AU
String cmd = "updateResult";
String desktopId = target.getDesktop().getId();
Event event = new Event(cmd, (Component) target.getDelegatee());
Map<String, Object> data = EventDataManager.getInstance().build(event);
data.put("wid", target.getUuid());
data.put("contentId", contentId);
data.put("sid", "0");
((ClientCtrl) target.getClient()).postUpdate(desktopId, target.getUuid(), cmd, data, false);
((ClientCtrl) target.getClient()).flush(desktopId);
}
private void clean() {
// close output
Util.close(multipartStream);
multipartStream = null;
// close input
InputStream is = null;
try {
String respMsg = conn.getResponseMessage();
is = conn.getInputStream();
String resp = IO.toString(is);
if (logger.isLoggable(Level.FINEST)) {
logger.finest("response message: " + respMsg);
logger.finest("response content: " + resp);
}
} catch (IOException e) {
throw new AgentException(e.getMessage(), e);
} finally {
Util.close(is);
conn = null;
}
}
}
}