Showing posts with label MarkLogic. Show all posts
Showing posts with label MarkLogic. Show all posts

Friday, September 20, 2013

MarkLogic - using xquery to interact via Alfresco's content repository using the REST API

Using Alfresco community edition 4.2.a, and MarkLogic 6.

It was difficult navigating Alfresco's documentation on the REST API, as there were NO examples, just specs.. and often the specs stated that they were "deprecated".  Ultimately I found this document on CMIS and interacting via http.  (NOTE:  There is a vital typo on page 25 in the cmisra namespace declaration, which causes example to fail.. just remove extraneous slash).

Anyway, I cobbled together an example that demonstrates login, ticket validation, content creation, and logout.  This works in the Query Console.. although the base64 module is my own (see prior post on base64 encoding of binary files).

xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
import module namespace json = "http://marklogic.com/xdmp/json" at "/MarkLogic/json/json.xqy";
import module namespace base64 = "base64" at "utility/base64.xqm";


let $string := concat('{ "username":"admin", "password":"admin" }')
let $data := <data>{$string}</data>

let $login := xdmp:http-post("http:/localhost:8080/alfresco/service/api/login",
  <options xmlns="xdmp:http">
        <data>{$string}</data>
        <headers>
            <content-type>application/json</content-type>
        </headers>
    </options>)
    
let $ticket_xml := json:transform-from-json($login[2])

let $ticket_id := data($ticket_xml//*[local-name() = 'ticket'])

let $uri := concat("http://localhost:8080/alfresco/service/api/login/ticket/",$ticket_id,"?alf_ticket=",$ticket_id)

let $check := xdmp:http-get($uri)
(: if you have a node_id, the following is example of how to retrieve content
let $content_uri := concat("http://localhost:8080/alfresco/service/cmis/i/", $node_id, "/content?alf_ticket=", $ticket_id) :)

let $filedata := base64:encode("/some/path/image.png")  (: insert your own base64 here :)

let $content_uri := concat("http://localhost:8080/alfresco/s/cmis/p/path/children", "?alf_ticket=", $ticket_id)  (: the "path" is the path after "Company Home" :)

let $atomxml :=
<entry xmlns="http://www.w3.org/2005/Atom" 
xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908" 
xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908">
 <title>image.png</title>
 <summary>A sample upload</summary>
 <content type="image/png">{$filedata}</content>
 <cmisra:object>
 <cmis:properties>
 <cmis:propertyId propertyDefinitionId="cm:description"><cmis:value>This is the description property</cmis:value></cmis:propertyId>
 <cmis:propertyId propertyDefinitionId="cmis:objectTypeId"><cmis:value>cmis:content</cmis:value></cmis:propertyId>
 </cmis:properties>
 </cmisra:object>
</entry>

let $upload := xdmp:http-post($content_uri,
  <options xmlns="xdmp:http">
        <data>{concat('<?xml version="1.0" encoding="utf-8"?>',xdmp:quote($atomxml))}</data>
        <headers>
            <content-type>application/atom+xml</content-type>
        </headers>
    </options>)

let $logout := xdmp:http-delete($uri)

return ($check,$upload)


MarkLogic base64 encoding of a binary file using MLJAM

MarkLogic has the function xdmp:base64-encode, which unfortunately only works on xs:string's.

I needed a function to convert an arbitrary file (ie. binary) into a base64 encoded stream in order to put it into an atom+xml http post to feed Alfresco document management system.  Luckily I found MLJAM, which allows you to embed Java into xquery.  I found the needed Java snippet here, and then put it together - the code below should work in the MarkLogic Query console, just set the filename parameter accordingly.

Ultimately MarkLogic should have xdmp:base64-encode work on a binary node, then you could simply do xdmp:base64-encode(xdmp:external-binary("/some/path/image.png"))!

xquery version "1.0-ml";
import module namespace jam = "http://xqdev.com/jam" at "/MarkLogic/jam.xqy";
let $code := <code><![CDATA[
import org.apache.commons.codec.binary.Base64;
private String encodeFileToBase64Binary(String fileName)
throws IOException {
File file = new File(fileName);
byte[] bytes = loadFile(file);
byte[] encoded = Base64.encodeBase64(bytes);
String encodedString = new String(encoded);
return encodedString;
}
 
private static byte[] loadFile(File file) throws IOException {
   InputStream is = new FileInputStream(file);
     long length = file.length();
   if (length > Integer.MAX_VALUE) {
       // File is too large
   }
   byte[] bytes = new byte[(int)length];
   
   int offset = 0;
   int numRead = 0;
   while (offset < bytes.length
          && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
       offset += numRead;
   }
 
   if (offset < bytes.length) {
       throw new IOException("Could not completely read file "+file.getName());
   }
 
   is.close();
   return bytes;
}
  
    return encodeFileToBase64Binary(filename);
]]></code>
  
let $path := "http://localhost:8080/mljam/mljam"
let $connect := jam:start($path, (), ())
let $vars := jam:set("filename", "/some/path/image.png")
let $eval := jam:eval-get($code)
let $end := jam:end()
return $eval

Wednesday, September 12, 2012

MarkLogic xdmp:email with binary attachments need wrapping

According to RFC 2045, MIME base64 encoded attachments need to be wrapped at 76 characters.

Most email clients can handle attachments that are not wrapped (meaning the base64 encoding is not wrapped at 76 charaters), but some, specifically MS Outlook (at least some versions) cannot, and report that the attachment is corrupt.

When sending binary attachments from MarkLogic via xdmp:email
, this wrapping does not occur - causing some recipients to report documents are corrupt.

In order to fix this, we created a function which wraps the base64 encoding prior to sending.

(: Function used for wrapping email attachments :)
declare function local:wrap($wrapped, $unwrapped, $max){
        let $remaining := string-length($unwrapped)

        return if ($remaining <= $max) then concat($wrapped, "&#13;&#10;", substring($unwrapped, 1, $max))
        else local:wrap(concat($wrapped, "&#13;&#10;", substring($unwrapped, 1, $max)), substring($unwrapped, $max+1, $remaining), $max)
};
And it used when building the parameter list:
        let $attachment1 := local:wrap("", xs:string(xs:base64Binary(doc("/some/doc/path/doc.pdf"))), 76)
See documentation on xdmp:email for complete example with attachments.