/**
* 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.manifoldcf.agents.output.opensearchserver;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.apache.manifoldcf.agents.interfaces.IOutputAddActivity;
import org.apache.manifoldcf.agents.interfaces.RepositoryDocument;
import org.apache.manifoldcf.core.common.Base64;
import org.apache.manifoldcf.core.interfaces.ManifoldCFException;
public class OpenSearchServerIndex extends OpenSearchServerConnection
{
private static class Acls
{
private String[] acls = null;
private String[] denyAcls = null;
private String[] shareAcls = null;
private String[] shareDenyAcls = null;
private void setDocument(String[] acls, String[] denyAcls)
{
this.acls = acls;
this.denyAcls = denyAcls;
}
private void setShare(String[] acls, String[] denyAcls)
{
this.shareAcls = acls;
this.shareDenyAcls = denyAcls;
}
}
private static class IndexRequestEntity implements HttpEntity
{
private final String documentURI;
private final RepositoryDocument document;
private final String fileName;
private final Acls acls;
public IndexRequestEntity(String documentURI, RepositoryDocument document,
Acls acls)
{
this.documentURI = documentURI;
this.document = document;
this.fileName = FilenameUtils.getName(documentURI);
this.acls = acls;
}
@Override
public boolean isChunked()
{
return false;
}
@Override
@Deprecated
public void consumeContent()
throws IOException
{
EntityUtils.consume(this);
}
@Override
public boolean isRepeatable()
{
return false;
}
@Override
public boolean isStreaming()
{
return true;
}
@Override
public InputStream getContent()
throws IOException, IllegalStateException
{
return null;
}
private static final void writeFieldCdata(String fieldName,
Collection<String> values, PrintWriter pw)
{
if (CollectionUtils.isEmpty(values))
return;
pw.print("<field name=\"");
pw.print(StringEscapeUtils.escapeXml(fieldName));
pw.print("\">");
for (String value : values)
{
pw.print("<value><![CDATA[");
pw.print(value);
pw.print("]]></value>");
}
pw.println("</field>");
}
private static final void writeField(String fieldName, String value,
PrintWriter pw)
{
if (StringUtils.isEmpty(value))
return;
pw.print("<field name=\"");
pw.print(fieldName);
pw.print("\"><value>");
pw.print(value);
pw.println("</value></field>");
}
private static final void writeFieldValues(String fieldName,
String[] values, PrintWriter pw)
{
if (values == null || values.length == 0)
return;
pw.print("<field name=\"");
pw.print(fieldName);
pw.println("\">");
for (String value : values)
{
pw.print("<value>");
pw.print(value);
pw.println("</value>");
}
pw.println("</field>");
}
@Override
public void writeTo(OutputStream out)
throws IOException
{
PrintWriter pw = new PrintWriter(out);
try
{
pw.println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
pw.println("<index>);");
pw.print("<document>");
List<String> values = new ArrayList<String>(1);
Iterator<String> iter = document.getFields();
if (iter != null)
{
while (iter.hasNext())
{
String fieldName = iter.next();
if ("uri".equals(fieldName))
continue;
Object[] fieldValues = document.getField(fieldName);
if (fieldValues != null && fieldValues.length > 0)
{
values.clear();
for (Object fieldValue : fieldValues)
if (fieldValue != null)
values.add(fieldValue.toString());
writeFieldCdata(fieldName, values, pw);
}
}
}
writeField("uri", documentURI, pw);
if (document.getBinaryLength() > 0)
{
Base64 base64 = new Base64();
pw.print("<binary fileName=\"");
pw.print(fileName);
pw.println("\">");
base64.encodeStream(document.getBinaryStream(), pw);
pw.println("</binary>");
}
if (acls != null)
{
writeFieldValues("userAllow", acls.acls, pw);
writeFieldValues("userDeny", acls.denyAcls, pw);
writeFieldValues("groupAllow", acls.shareAcls, pw);
writeFieldValues("groupDeny", acls.shareDenyAcls, pw);
}
pw.println("</document>");
pw.println("</index>");
}
catch (ManifoldCFException e)
{
throw new IOException(e.getMessage(), e);
}
finally
{
IOUtils.closeQuietly(pw);
}
}
@Override
public long getContentLength()
{
// Unknown (chunked) length
return -1L;
}
@Override
public Header getContentType()
{
return new BasicHeader("Content-type", "text/xml; charset=utf-8");
}
@Override
public Header getContentEncoding()
{
return null;
}
}
/**
* Convert an unqualified ACL to qualified form.
*
* @param acl
* is the initial, unqualified ACL.
* @param authorityNameString
* is the name of the governing authority for this document's acls,
* or null if none.
* @param activities
* is the activities object, so we can report what's happening.
* @return the modified ACL.
*/
protected static String[] convertACL(String[] acl,
String authorityNameString, IOutputAddActivity activities)
throws ManifoldCFException
{
if (acl != null)
{
String[] rval = new String[acl.length];
int i = 0;
while (i < rval.length)
{
rval[i] = activities.qualifyAccessToken(authorityNameString, acl[i]);
i++;
}
return rval;
}
return new String[0];
}
public OpenSearchServerIndex(HttpClient client, String documentURI,
OpenSearchServerConfig config, RepositoryDocument document,
String authorityNameString, IOutputAddActivity activities)
throws ManifoldCFException
{
super(client, config);
Acls acls = new Acls();
Iterator<String> a = document.securityTypesIterator();
if (a != null)
{
while (a.hasNext())
{
String securityType = a.next();
String[] convertedAcls = convertACL(
document.getSecurityACL(securityType), authorityNameString,
activities);
String[] convertedDenyAcls = convertACL(
document.getSecurityDenyACL(securityType), authorityNameString,
activities);
if (securityType.equals(RepositoryDocument.SECURITY_TYPE_DOCUMENT))
{
acls.setDocument(convertedAcls, convertedDenyAcls);
}
else if (securityType.equals(RepositoryDocument.SECURITY_TYPE_SHARE))
{
acls.setShare(convertedAcls, convertedDenyAcls);
}
else
{
// Don't know how to deal with it
setResult(Result.ERROR, "Unhandled security type: " + securityType);
return;
}
}
}
StringBuffer url = getApiUrl("update");
HttpPut put = new HttpPut(url.toString());
put.setEntity(new IndexRequestEntity(documentURI, document, acls));
call(put);
if ("OK".equals(checkXPath(xPathStatus)))
return;
String error = checkXPath(xPathException);
setResult(Result.ERROR, error);
throw new ManifoldCFException("Error, unexpected response: " + error);
}
}