blob: f4164c593dc916efb944c162f0ba2b00418721d1 [file] [log] [blame]
/*
* 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.apache.chemistry.opencmis.client.bindings.spi.browser;
import static org.apache.chemistry.opencmis.commons.impl.CollectionsHelper.isNotEmpty;
import static org.apache.chemistry.opencmis.commons.impl.CollectionsHelper.isNullOrEmpty;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.GregorianCalendar;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.chemistry.opencmis.commons.data.Ace;
import org.apache.chemistry.opencmis.commons.data.Acl;
import org.apache.chemistry.opencmis.commons.data.BulkUpdateObjectIdAndChangeToken;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.data.Properties;
import org.apache.chemistry.opencmis.commons.data.PropertyData;
import org.apache.chemistry.opencmis.commons.enums.DateTimeFormat;
import org.apache.chemistry.opencmis.commons.impl.Constants;
import org.apache.chemistry.opencmis.commons.impl.DateTimeHelper;
import org.apache.chemistry.opencmis.commons.impl.IOUtils;
import org.apache.chemistry.opencmis.commons.impl.MimeHelper;
import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
public final class FormDataWriter {
private static final String CONTENT_TYPE_URLENCODED = "application/x-www-form-urlencoded;charset=utf-8";
private static final String CONTENT_TYPE_FORMDATA = "multipart/form-data; boundary=";
private static final String CRLF = "\r\n";
private static final int BUFFER_SIZE = 64 * 1024;
private final String boundary;
private final Map<String, String> parameters = new LinkedHashMap<String, String>();
private ContentStream contentStream;
public FormDataWriter(String action) {
this(action, null);
}
public FormDataWriter(String action, ContentStream contentStream) {
addParameter(Constants.CONTROL_CMISACTION, action);
this.contentStream = contentStream;
boundary = "aPacHeCheMIStryoPEncmiS" + Long.toHexString(action.hashCode()) + action
+ Long.toHexString(System.currentTimeMillis()) + Long.toHexString(this.hashCode());
}
public void addParameter(String name, Object value) {
if (name == null || value == null) {
return;
}
parameters.put(name, UrlBuilder.normalizeParameter(value));
}
public void addPropertiesParameters(Properties properties, DateTimeFormat dateTimeFormat) {
if (properties == null) {
return;
}
int idx = 0;
for (PropertyData<?> prop : properties.getPropertyList()) {
if (prop == null) {
continue;
}
String idxStr = "[" + idx + "]";
addParameter(Constants.CONTROL_PROP_ID + idxStr, prop.getId());
if (isNotEmpty(prop.getValues())) {
if (prop.getValues().size() == 1) {
addParameter(Constants.CONTROL_PROP_VALUE + idxStr,
convertPropertyValue(prop.getFirstValue(), dateTimeFormat));
} else {
int vidx = 0;
for (Object obj : prop.getValues()) {
String vidxStr = "[" + vidx + "]";
addParameter(Constants.CONTROL_PROP_VALUE + idxStr + vidxStr,
convertPropertyValue(obj, dateTimeFormat));
vidx++;
}
}
}
idx++;
}
}
public void addSuccinctFlag(boolean succinct) {
if (succinct) {
addParameter(Constants.CONTROL_SUCCINCT, "true");
}
}
public void addPoliciesParameters(List<String> policies) {
if (policies == null) {
return;
}
int idx = 0;
for (String policy : policies) {
if (policy != null) {
String idxStr = "[" + idx + "]";
addParameter(Constants.CONTROL_POLICY + idxStr, policy);
idx++;
}
}
}
public void addAddAcesParameters(Acl acl) {
addAcesParameters(acl, Constants.CONTROL_ADD_ACE_PRINCIPAL, Constants.CONTROL_ADD_ACE_PERMISSION);
}
public void addRemoveAcesParameters(Acl acl) {
addAcesParameters(acl, Constants.CONTROL_REMOVE_ACE_PRINCIPAL, Constants.CONTROL_REMOVE_ACE_PERMISSION);
}
private void addAcesParameters(Acl acl, String principalControl, String permissionControl) {
if (acl == null || acl.getAces() == null) {
return;
}
int idx = 0;
for (Ace ace : acl.getAces()) {
if (ace.getPrincipalId() != null && isNotEmpty(ace.getPermissions())) {
String idxStr = "[" + idx + "]";
addParameter(principalControl + idxStr, ace.getPrincipalId());
int permIdx = 0;
for (String perm : ace.getPermissions()) {
if (perm != null) {
String permIdxStr = "[" + permIdx + "]";
addParameter(permissionControl + idxStr + permIdxStr, perm);
permIdx++;
}
}
idx++;
}
}
}
public void addObjectIdsAndChangeTokens(List<BulkUpdateObjectIdAndChangeToken> objectIdsAndChangeTokens) {
if (isNullOrEmpty(objectIdsAndChangeTokens)) {
return;
}
int idx = 0;
for (BulkUpdateObjectIdAndChangeToken oc : objectIdsAndChangeTokens) {
if (oc == null || oc.getId() == null || oc.getId().length() == 0) {
continue;
}
String idxStr = "[" + idx + "]";
addParameter(Constants.CONTROL_OBJECT_ID + idxStr, oc.getId());
addParameter(Constants.CONTROL_CHANGE_TOKEN + idxStr,
(oc.getChangeToken() == null ? "" : oc.getChangeToken()));
idx++;
}
}
public void addSecondaryTypeIds(List<String> secondaryTypeIds) {
addSecondaryTypeIdParameters(secondaryTypeIds, Constants.CONTROL_ADD_SECONDARY_TYPE);
}
public void removeSecondaryTypeIds(List<String> secondaryTypeIds) {
addSecondaryTypeIdParameters(secondaryTypeIds, Constants.CONTROL_REMOVE_SECONDARY_TYPE);
}
private void addSecondaryTypeIdParameters(List<String> secondaryTypeIds, String secondaryTypeIdControl) {
if (isNullOrEmpty(secondaryTypeIds)) {
return;
}
int idx = 0;
for (String typeId : secondaryTypeIds) {
if (typeId == null || typeId.length() == 0) {
continue;
}
String idxStr = "[" + idx + "]";
addParameter(secondaryTypeIdControl + idxStr, typeId);
idx++;
}
}
private String convertPropertyValue(Object value, DateTimeFormat dateTimeFormat) {
if (value == null) {
return null;
}
if (value instanceof GregorianCalendar) {
if (dateTimeFormat == DateTimeFormat.EXTENDED) {
return DateTimeHelper.formatXmlDateTime((GregorianCalendar) value);
} else {
return String.valueOf(((GregorianCalendar) value).getTimeInMillis());
}
}
return value.toString();
}
public String getContentType() {
return (contentStream == null ? CONTENT_TYPE_URLENCODED : CONTENT_TYPE_FORMDATA + boundary);
}
public void write(OutputStream out) throws IOException {
InputStream stream = (contentStream == null ? null : contentStream.getStream());
if (stream == null) {
boolean first = true;
byte[] amp = IOUtils.toUTF8Bytes("&");
for (Map.Entry<String, String> param : parameters.entrySet()) {
if (first) {
first = false;
} else {
out.write(amp);
}
out.write(IOUtils.toUTF8Bytes(param.getKey() + "=" + URLEncoder.encode(param.getValue(), IOUtils.UTF8)));
}
} else {
writeLine(out);
// parameters
for (Map.Entry<String, String> param : parameters.entrySet()) {
writeLine(out, "--" + boundary);
writeLine(out, "Content-Disposition: form-data; name=\"" + param.getKey() + "\"");
writeLine(out, "Content-Type: text/plain; charset=utf-8");
writeLine(out);
writeLine(out, param.getValue());
}
// content
String filename = contentStream.getFileName();
if (filename == null || filename.length() == 0) {
filename = "content";
}
String mediaType = contentStream.getMimeType();
if (mediaType == null || mediaType.indexOf('/') < 1 || mediaType.indexOf('\n') > -1
|| mediaType.indexOf('\r') > -1) {
mediaType = Constants.MEDIATYPE_OCTETSTREAM;
}
writeLine(out, "--" + boundary);
writeLine(
out,
"Content-Disposition: "
+ MimeHelper.encodeContentDisposition(MimeHelper.DISPOSITION_FORM_DATA_CONTENT, filename));
writeLine(out, "Content-Type: " + mediaType);
writeLine(out, "Content-Transfer-Encoding: binary");
writeLine(out);
IOUtils.copy(stream, out, BUFFER_SIZE);
writeLine(out);
writeLine(out, "--" + boundary + "--");
}
}
private void writeLine(OutputStream out) throws IOException {
writeLine(out, null);
}
private void writeLine(OutputStream out, String s) throws IOException {
s = (s == null ? CRLF : s + CRLF);
out.write(IOUtils.toUTF8Bytes(s));
}
}