| /* |
| * 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)); |
| } |
| } |