Package org.exist.xmldb

Source Code of org.exist.xmldb.AbstractRemoteResource

package org.exist.xmldb;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;

import org.apache.xmlrpc.XmlRpcException;
import org.apache.commons.io.output.ByteArrayOutputStream;

import org.exist.security.Permission;
import org.exist.storage.serializers.EXistOutputKeys;
import org.exist.util.EXistInputSource;
import org.exist.util.VirtualTempFile;
import org.xml.sax.InputSource;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.ErrorCodes;
import org.xmldb.api.base.Resource;
import org.xmldb.api.base.XMLDBException;

import static java.nio.charset.StandardCharsets.UTF_8;

public abstract class AbstractRemoteResource
  implements EXistResource, ExtendedResource, Resource
{
  protected XmldbURI path = null ;
  protected String mimeType=null;
  protected RemoteCollection parent;
  protected VirtualTempFile vfile=null;
  protected VirtualTempFile contentVFile=null;
  protected InputSource inputSource = null;
  protected boolean isLocal=false;
  protected long contentLen = 0L;
  protected Permission permissions = null;
 
  protected Date dateCreated= null;
  protected Date dateModified= null;
 
  public AbstractRemoteResource(RemoteCollection parent,XmldbURI documentName)
    throws XMLDBException
  {
    this.parent = parent;
    if (documentName.numSegments()>1) {
      this.path = documentName;
    } else {
      this.path = parent.getPathURI().append(documentName);
    }
  }
   
        @Override
  protected void finalize()
    throws Throwable
  {
    freeResources();
    super.finalize();
  }
 
        @Override
  public void freeResources() {
    vfile = null;
    inputSource = null;
    if(contentVFile!=null) {
      contentVFile.delete();
      contentVFile=null;
    }
    isLocal=true;
  }
 
  protected Properties getProperties() {
    return parent.properties;
  }

  /* (non-Javadoc)
   * @see org.xmldb.api.base.Resource#getContent()
   */
  public Object getContent()
    throws XMLDBException
  {
    final Object res=getExtendedContent();
    // Backward compatibility
    if(isLocal)  {return res;}
    if(res!=null) {
      if(res instanceof File) {
        return readFile((File)res);
      } else if(res instanceof InputSource) {
        return readFile((InputSource)res);
      }
    }
   
    return res;
  }
 
  /* (non-Javadoc)
   * @see org.xmldb.api.base.Resource#getContent()
   */
  // Backward compatibility
  protected byte[] getData()
    throws XMLDBException
  {
    final Object res=getExtendedContent();
    if(res!=null) {
      if(res instanceof File) {
        return readFile((File)res);
      } else if(res instanceof InputSource) {
        return readFile((InputSource)res);
      } else if(res instanceof String) {
                return ((String)res).getBytes(UTF_8);
      }
    }
   
    return (byte[])res;
  }
 
  public long getContentLength()
    throws XMLDBException
  {
    return contentLen;
  }
 
  /* (non-Javadoc)
   * @see org.exist.xmldb.EXistResource#getCreationTime()
   */
  public Date getCreationTime()
    throws XMLDBException
  {
    return dateCreated;
  }
 
  public long getExtendedContentLength()
    throws XMLDBException
  {
    return contentLen;
  }
 
  /* (non-Javadoc)
   * @see org.exist.xmldb.EXistResource#getLastModificationTime()
   */
  public Date getLastModificationTime()
    throws XMLDBException
  {
    return dateModified;
  }
 
  /* (non-Javadoc)
  * @see org.exist.xmldb.EXistResource#getMimeType()
  */
  public String getMimeType() {
    return mimeType;
  }
 
  /* (non-Javadoc)
   * @see org.xmldb.api.base.Resource#getParentCollection()
   */
  public Collection getParentCollection()
    throws XMLDBException
  {
    return parent;
  }
 
  /* (non-Javadoc)
   * @see org.exist.xmldb.EXistResource#getPermissions()
   */
  public Permission getPermissions() {
    return permissions;
  }
 
  protected boolean setContentInternal(Object value)
    throws XMLDBException
  {
    freeResources();
    boolean wasSet=false;
    if(value instanceof VirtualTempFile) {
        vfile = (VirtualTempFile)value;
        // Assuring the virtual file is close state
        try {
          vfile.close();
        } catch(final IOException ioe) {
          // IgnoreIT(R)
        }
        setExtendendContentLength(vfile.length());
        wasSet=true;
    } else if(value instanceof File) {
      vfile = new VirtualTempFile((File) value);
      setExtendendContentLength(vfile.length());
      wasSet=true;
    } else if (value instanceof InputSource) {
      inputSource = (InputSource) value;
        wasSet=true;
    } else if(value instanceof byte[]) {
      vfile = new VirtualTempFile((byte[])value);
      setExtendendContentLength(vfile.length());
      wasSet=true;
    } else if(value instanceof String) {
            vfile = new VirtualTempFile(((String)value).getBytes(UTF_8));
            setExtendendContentLength(vfile.length());
            wasSet=true;
    }
   
    return wasSet;
  }
 
  protected void setExtendendContentLength(long len) {
    this.contentLen = len;
  }
 
  public void setContentLength(int len) {
    this.contentLen = len;
  }
 
  public void setContentLength(long len) {
    this.contentLen = len;
  }
 
  /* (non-Javadoc)
  * @see org.exist.xmldb.EXistResource#setMimeType(java.lang.String)
  */
  public void setMimeType(String mime) {
    this.mimeType = mime;
  }
 
  public void setPermissions(Permission perms) {
    permissions = perms;
  }
 
  public void getContentIntoAFile(File localfile)
    throws XMLDBException
  {
    FileOutputStream fos=null;
    BufferedOutputStream bos=null;
    try {
      fos=new FileOutputStream(localfile);
      bos=new BufferedOutputStream(fos);
     
      getContentIntoAStream(bos);
    } catch (final IOException ioe) {
      throw new XMLDBException(ErrorCodes.VENDOR_ERROR, ioe.getMessage(), ioe);
    } finally {
      if(bos!=null) {
        try {
          bos.close();
        } catch(final IOException ioe) {
          // IgnoreIT(R)
        }
      }
      if(fos!=null) {
        try {
          fos.close();
        } catch(final IOException ioe) {
          // IgnoreIT(R)
        }
      }
    }
  }
 
    protected void getRemoteContentIntoLocalFile(final OutputStream os, final boolean isRetrieve, final int handle, final int pos) throws XMLDBException {
        Properties properties = getProperties();
        if(properties == null) {
            properties = new Properties();
        }
       
        final String command;
        final List<Object> params = new ArrayList<Object>();
        if(isRetrieve) {
            command = "retrieveFirstChunk";
            params.add(Integer.valueOf(handle));
            params.add(Integer.valueOf(pos));
        } else {
            command = "getDocumentData";
            params.add(path.toString());
        }
        params.add(properties);
       
        try {
            final VirtualTempFile vtmpfile = new VirtualTempFile();
            vtmpfile.setTempPrefix("eXistARR");
            vtmpfile.setTempPostfix("XMLResource".equals(getResourceType())?".xml":".bin");

            Map<?,?> table = (Map<?,?>) parent.getClient().execute(command, params);
           
            final String method;
            final boolean useLongOffset;
            if(table.containsKey("supports-long-offset") && (Boolean)(table.get("supports-long-offset"))) {
                useLongOffset = true;
                method = "getNextExtendedChunk";
            } else {
                useLongOffset = false;
                method = "getNextChunk";
            }
           
            long offset = ((Integer)table.get("offset")).intValue();
            byte[] data = (byte[])table.get("data");
            final boolean isCompressed = "yes".equals(properties.getProperty(EXistOutputKeys.COMPRESS_OUTPUT, "no"));
               
            // One for the local cached file
            Inflater dec = null;
            byte[] decResult = null;
            int decLength;
            if(isCompressed) {
                dec = new Inflater();
                decResult = new byte[65536];
                dec.setInput(data);
                do {
                    decLength = dec.inflate(decResult);
                    vtmpfile.write(decResult,0,decLength);
                    // And other for the stream where we want to save it!
                    if(os != null) {
                        os.write(decResult, 0, decLength);
                    }
                } while(decLength == decResult.length || !dec.needsInput());
               
            } else {
                vtmpfile.write(data);
                // And other for the stream where we want to save it!
                if(os != null) {
                    os.write(data);
                }
            }
               
            while(offset > 0) {
                params.clear();
                params.add(table.get("handle"));
                params.add(useLongOffset?Long.toString(offset):Integer.valueOf((int)offset));
                table = (Map<?,?>) parent.getClient().execute(method, params);
                offset = useLongOffset?Long.valueOf((String)table.get("offset")).longValue():((Integer)table.get("offset")).longValue();
                data = (byte[])table.get("data");

                // One for the local cached file
                if(isCompressed) {
                    dec.setInput(data);
                    do {
                        decLength = dec.inflate(decResult);
                        vtmpfile.write(decResult,0,decLength);
                        // And other for the stream where we want to save it!
                        if(os != null) {
                            os.write(decResult, 0, decLength);
                        }
                    } while(decLength == decResult.length || !dec.needsInput());
                } else {
                    vtmpfile.write(data);
                    // And other for the stream where we want to save it!
                     if(os != null) {
                        os.write(data);
                    }
                }
            }
           
            if(dec != null) {
                dec.end();
            }

            isLocal = false;
            contentVFile = vtmpfile;
        } catch(final XmlRpcException xre) {
                throw new XMLDBException(ErrorCodes.INVALID_RESOURCE, xre.getMessage(), xre);
        } catch(final IOException ioe) {
                throw new XMLDBException(ErrorCodes.VENDOR_ERROR, ioe.getMessage(), ioe);
        } catch(final DataFormatException dfe) {
                throw new XMLDBException(ErrorCodes.VENDOR_ERROR, dfe.getMessage(), dfe);
        } finally {
            if(contentVFile!=null) {
                try {
                    contentVFile.close();
                } catch(final IOException ioe) {
                    //IgnoreIT(R)
                }
            }
        }
    }

  protected static InputStream getAnyStream(Object obj)
    throws XMLDBException
  {
    if(obj instanceof String) {
            return new ByteArrayInputStream(((String)obj).getBytes(UTF_8));
    } else if(obj instanceof byte[]) {
      return new ByteArrayInputStream((byte[])obj);
    } else {
      throw new XMLDBException(ErrorCodes.VENDOR_ERROR,"don't know how to handle value of type " + obj.getClass().getName());
    }
  }
 
  protected void getContentIntoAStreamInternal(OutputStream os, Object obj, boolean isRetrieve, int handle, int pos)
    throws XMLDBException
  {
    if(vfile!=null || contentVFile!=null || inputSource!=null || obj!=null) {
      InputStream bis=null;
      try {
        // First, the local content, then the remote one!!!!
        if(vfile!=null) {
          bis=vfile.getByteStream();
        } else if(inputSource!=null) {
          bis=inputSource.getByteStream();
        } else if(obj!=null) {
          bis=getAnyStream(obj);
        } else {
          bis=contentVFile.getByteStream();
        }
        int readed;
        final byte buffer[]=new byte[65536];
        while((readed=bis.read(buffer))!=-1) {
          os.write(buffer,0,readed);
        }
      } catch(final IOException ioe) {
        throw new XMLDBException(ErrorCodes.VENDOR_ERROR,ioe.getMessage(),ioe);
      } finally {
        if(inputSource!=null) {
          if(bis!=null) {
            // As it comes from an input source, we cannot blindly close it,
            // but at least let's reset it! (if it is possible)
            if(bis.markSupported()) {
              try {
                bis.reset();
              } catch(final IOException ioe) {
                //IgnoreIT(R)
              }
            }
          }
        } else {
          if(bis!=null) {
            try {
              bis.close();
            } catch(final IOException ioe) {
              //IgnoreIT(R)
            }
          }
        }
      }
    } else {
      // Let's fetch it, and save just in time!!!
      getRemoteContentIntoLocalFile(os,isRetrieve,handle,pos);
    }
  }

  protected Object getExtendedContentInternal(Object obj, boolean isRetrieve, int handle, int pos)
    throws XMLDBException
  {
    if(obj != null)
      {return obj;}
   
    if(vfile!=null)
      {return vfile.getContent();}
    if(inputSource!=null)
      {return inputSource;}
   
    if(contentVFile==null)
      {getRemoteContentIntoLocalFile(null,isRetrieve,handle,pos);}
   
    return contentVFile.getContent();
  }

  protected InputStream getStreamContentInternal(Object obj, boolean isRetrieve, int handle, int pos)
    throws XMLDBException
  {
    InputStream retval=null;
   
    if(vfile!=null) {
      try {
        retval=vfile.getByteStream();
      } catch(final IOException fnfe) {
        throw new XMLDBException(ErrorCodes.VENDOR_ERROR, fnfe.getMessage(), fnfe);
      }
    } else if(inputSource!=null) {
      retval=inputSource.getByteStream();
    } else if(obj!=null) {
      retval=getAnyStream(obj);
    } else {
      // At least one value, please!!!
      if(contentVFile==null)
        {getRemoteContentIntoLocalFile(null,isRetrieve,handle,pos);}
     
      try {
        retval=contentVFile.getByteStream();
      } catch(final IOException fnfe) {
        throw new XMLDBException(ErrorCodes.VENDOR_ERROR, fnfe.getMessage(), fnfe);
      }
    }
   
    return retval;
  }

  protected long getStreamLengthInternal(Object obj)
    throws XMLDBException
  {
    long retval=-1;
    if(vfile!=null) {
      retval=vfile.length();
    } else if(inputSource!=null && inputSource instanceof EXistInputSource) {
      retval=((EXistInputSource)inputSource).getByteStreamLength();
    } else if(obj!=null) {
      if(obj instanceof String) {
                retval=((String)obj).getBytes(UTF_8).length;
      } else if(obj instanceof byte[]) {
        retval=((byte[])obj).length;
      } else {
        throw new XMLDBException(ErrorCodes.VENDOR_ERROR,"don't know how to handle value of type " + obj.getClass().getName());
      }
    } else if(contentVFile!=null) {
      retval=contentVFile.length();
    } else {
      final Properties properties = getProperties();
      final List<Object> params = new ArrayList<Object>();
      params.add(path.toString());
      params.add(properties);
      try {
        final Map<?,?> table = (Map<?,?>) parent.getClient().execute("describeResource", params);
        if(table.containsKey("content-length-64bit")) {
          final Object o = table.get("content-length-64bit");
          if(o instanceof Long) {
            retval = ((Long)o).longValue();
          } else {
            retval = Long.parseLong((String)o);
          }
        } else {
          retval=((Integer)table.get("content-length")).intValue();
        }
      } catch (final XmlRpcException xre) {
        throw new XMLDBException(ErrorCodes.INVALID_RESOURCE, xre.getMessage(), xre);
      }
    }
   
    return retval;
  }


 
  private static byte[] readFile(File file)
    throws XMLDBException
  {
    final String errmsg="file "+ file.getAbsolutePath();
                InputStream is = null;
    try {
                        is = new FileInputStream(file);
     
                        return readFile(is,errmsg);

    } catch (final FileNotFoundException e) {
      throw new XMLDBException(ErrorCodes.VENDOR_ERROR,
        errmsg + " could not be found", e);
    }
                finally
                {
                    if(is != null)
                    {
                        try
                        {
                            is.close();
                        }
                        catch(final IOException ioe)
                        {
                            //ignore(ioe);
                        }
                    }
                }
  }

  private static byte[] readFile(InputSource is)
    throws XMLDBException
  {
    String retval="<streamunknown>";
    if(is instanceof EXistInputSource) {
      retval=((EXistInputSource)is).getSymbolicPath();
    }
    return readFile(is.getByteStream(),"input source "+retval);
  }

  private static byte[] readFile(InputStream is,String errmsg)
    throws XMLDBException
  {
    if(errmsg==null)
      {errmsg="stream";}
    try {
      final ByteArrayOutputStream bos = new ByteArrayOutputStream(2048);
      final byte[] temp = new byte[1024];
      int count = 0;
      while((count = is.read(temp)) > -1) {
        bos.write(temp, 0, count);
      }
      return bos.toByteArray();
    } catch (final IOException e) {
      throw new XMLDBException(ErrorCodes.VENDOR_ERROR,
        "IO exception while reading " + errmsg, e);
    }
  }
 
  protected void setDateCreated(Date dateCreated) {
    this.dateCreated = dateCreated;
  }
 
  protected void setDateModified(Date dateModified) {
    this.dateModified = dateModified;
  }
}
TOP

Related Classes of org.exist.xmldb.AbstractRemoteResource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.