cancel
Showing results for 
Search instead for 
Did you mean: 

CmisStorageException on checkin

timwebster9
Champ in-the-making
Champ in-the-making
Hi,

I am trying to programmatically add and checkout/checkin documents against Alfresco 4.2f using Apache Chemistry v11.0 (atompub binding).  Frequently I get the following exception from the server while performing a checkin:


org.apache.chemistry.opencmis.commons.exceptions.CmisStorageException: Expected 654502 bytes but retrieved 0 bytes!
   at org.alfresco.opencmis.AlfrescoCmisServiceImpl.copyToTempFile(AlfrescoCmisServiceImpl.java:2812)
   at org.alfresco.opencmis.AlfrescoCmisServiceImpl.checkIn(AlfrescoCmisServiceImpl.java:2029)


If the checkin fails the document remains checkout out, so I then try to delete the document like so (the document here is the object returned from the original createDocument() call):


            if (document.isVersionSeriesCheckedOut()) {
                LOG.info("Cancelling checkout of document with id {}.", document.getId());
                document.cancelCheckOut();
            }

            document.delete();


However, the check to see if it's checked out returns false, and it tries to delete it anyway, resulting in another exception:

org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException: Could not delete/cancel checkout on the original checked out document

Am I doing anything obviously wrong?


Thanks,
12 REPLIES 12

kaynezhang
World-Class Innovator
World-Class Innovator
You can avoid this exception
 CmisStorageException: Expected 654502 bytes but retrieved 0 bytes!
by specifying content stream length when construct ContentStream like below

         File file = new File("C:\\userguide.pdf");
         InputStream fis = new FileInputStream(file);
         DataInputStream dis = new DataInputStream(fis);
         byte[] bytes = new byte[(int) file.length()];
         dis.readFully(bytes);
         ContentStream contentStream = new ContentStreamImpl(file
               .getAbsolutePath(), BigInteger.valueOf(bytes.length), "application/pdf",
               new ByteArrayInputStream(bytes));

ziggy
Champ in-the-making
Champ in-the-making

CmisStorageException: Expected 654502 bytes but retrieved 0 bytes!

I'm not a java person, but did a quick review of the code (since we're seeing similar issues while under load) --

There appear to be multiple things going on...  I would suggest a need for some serious code reviews:

Inside "createTempFile()" -- are multiple issues, that based upon LOAD will personify themselves differently.

    private File copyToTempFile(ContentStream contentStream)
    {
        if (contentStream == null)
        {
            return null;
        }

        File result = null;
        try
        {
            result = TempFileProvider.createTempFile(contentStream.getStream(), "cmis", "content");
        }
        catch (Exception e)
        {
            throw new CmisStorageException("Unable to store content: " + e.getMessage(), e);
        }

        if ((contentStream.getLength() > -1) && (result == null || contentStream.getLength() != result.length()))
        {
            removeTempFile(result);
            throw new CmisStorageException("Expected " + contentStream.getLength() + " bytes but retrieved " +
                    (result == null ? -1 :result.length()) + " bytes!");
        }

        return result;
    }

‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

  1. "result" is out of scope and should be dereferenced when the delete file is performed under the "removeTempFile(result)"
  2. ".createTempFile(contentStream.getStream()..." -- consumes contentStream.getStream() -- and also performs a "close" of the stream in its "Finally"-block.  However, the above code wants to continue to rely on contentStream.getLength() -- as if it should remain in scope  Smiley Sad

aowian
Confirmed Champ
Confirmed Champ

For one, the removeTempFile(result); makes result.length() always be zero. Therefore the exception message is misleading.  Perhaps we ought to be seeing "Expected 654502 bytes but retrieved 654500 bytes!"

*Update*

I patched the war to retain the resultLength

        if ((contentStream.getLength() > -1) && (result == null || contentStream.getLength() != result.length()))
        {
            long resultLength = result.length();
            removeTempFile(result);
            throw new CmisStorageException("Expected " + contentStream.getLength() + " bytes but retrieved " +
                    (result == null ? -1 :resultLength) + " bytes!")
        }

and it still says "... retrieved 0 bytes!". 

I did packet captures on both the cmis client and server sides, and they both show that the posts are garbled.  It looks like the cmis client is generating garbled payloads, and the server cannot parse the content, resulting in zero-length content streams.

timwebster9
Champ in-the-making
Champ in-the-making
Hi,

Thanks for the reply.  I am already doing that however.

I've also discovered that if I put a break point in my code between the checkout and checkin, it always works.  Does the server need some fine-tuning maybe?

kaynezhang
World-Class Innovator
World-Class Innovator
Please reload the object form the repository using 
d.refresh();
or object checking status only maintented in client side.

document.checkIn(**);
document.refresh();// reload the object
if (document.isVersionSeriesCheckedOut()) {
                LOG.info("Cancelling checkout of document with id {}.", document.getId());
                document.cancelCheckOut();
      
            }

            document.delete();

ok thanks, will give that a try.

Regarding the other problem, for now putting a small wait (200 - 500ms) between the checkout and checkin seems to fix it, but obviously this doesn't seem like a long-term solution.  It could be my setup - this is OOB alfresco install with no extra configuration or tuning.

kaynezhang
World-Class Innovator
World-Class Innovator
This is caused by apache chemistry client side caching.

Client side caching is turned on by default. That is, getObject() will first look into the session cache if the object already exists there. If this is the case, it returns the object without talking to the repository. So it might return stale objects.

you can look to http://chemistry.apache.org/java/developing/dev-client-cache.html

Dear kayne zhang,

I've disable cache for session as your instruction, but  in case of multi file upload concurrent, error still miss. To slove this problem, I must to sleep 2s (if multi file upload concurrent). So, do you have other solution? Please give me some advise?

thanks for that - that sorted out the delete problem…:-)