package org.exist.xmldb;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.util.Properties;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import javax.xml.transform.OutputKeys;
import org.apache.log4j.Logger;
import org.apache.xmlrpc.XmlRpcException;
import org.exist.storage.serializers.EXistOutputKeys;
import org.exist.util.VirtualTempFile;
import org.xmldb.api.base.ErrorCodes;
import org.xmldb.api.base.Resource;
import org.xmldb.api.base.ResourceIterator;
import org.xmldb.api.base.ResourceSet;
import org.xmldb.api.base.XMLDBException;
public class RemoteResourceSet implements ResourceSet {
protected RemoteCollection collection;
protected int handle = -1;
protected int hash = -1;
protected List resources;
protected Properties outputProperties;
private static Logger LOG = Logger.getLogger(RemoteResourceSet.class.getName());
public RemoteResourceSet(RemoteCollection col, Properties properties, Object[] resources, int handle, int hash) {
this.handle = handle;
this.hash = hash;
this.resources = new ArrayList(resources.length);
for (int i = 0; i < resources.length; i++) {
this.resources.add(resources[i]);
}
this.collection = col;
this.outputProperties = properties;
}
public void addResource( Resource resource ) {
resources.add( resource );
}
public void clear() throws XMLDBException {
if (handle < 0)
return;
List params = new ArrayList(1);
params.add(new Integer(handle));
if (hash > -1)
params.add(new Integer(hash));
try {
collection.getClient().execute("releaseQueryResult", params);
} catch (XmlRpcException e) {
System.err.println("Failed to release query result on server: " + e.getMessage());
}
handle = -1;
hash = -1;
resources.clear();
}
public ResourceIterator getIterator() throws XMLDBException {
return new NewResourceIterator();
}
public ResourceIterator getIterator( long start ) throws XMLDBException {
return new NewResourceIterator( start );
}
public Resource getMembersAsResource() throws XMLDBException {
List params = new ArrayList(2);
params.add(new Integer(handle));
params.add(outputProperties);
try {
VirtualTempFile vtmpfile=null;
try {
vtmpfile = new VirtualTempFile();
vtmpfile.setTempPrefix("eXistRRS");
vtmpfile.setTempPostfix(".xml");
Map table = (Map) collection.getClient().execute("retrieveAllFirstChunk", params);
long offset = ((Integer)table.get("offset")).intValue();
byte[] data = (byte[])table.get("data");
boolean isCompressed=outputProperties.getProperty(EXistOutputKeys.COMPRESS_OUTPUT, "no").equals("yes");
// One for the local cached file
Inflater dec = null;
byte[] decResult = null;
int decLength = 0;
if(isCompressed) {
dec = new Inflater();
decResult = new byte[65536];
dec.setInput(data);
do {
decLength = dec.inflate(decResult);
vtmpfile.write(decResult,0,decLength);
} while(decLength==decResult.length || !dec.needsInput());
} else {
vtmpfile.write(data);
}
while(offset > 0) {
params.clear();
params.add(table.get("handle"));
params.add(Long.toString(offset));
table = (Map) collection.getClient().execute("getNextExtendedChunk", params);
offset = new Long((String)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);
} while(decLength==decResult.length || !dec.needsInput());
} else {
vtmpfile.write(data);
}
}
if(dec!=null)
dec.end();
RemoteXMLResource res = new RemoteXMLResource( collection, handle, 0, XmldbURI.EMPTY_URI, null );
res.setContent( vtmpfile );
res.setProperties(outputProperties);
return res;
} catch (XmlRpcException xre) {
byte[] data = (byte[]) collection.getClient().execute("retrieveAll", params);
String content;
try {
content = new String(data, outputProperties.getProperty(OutputKeys.ENCODING, "UTF-8"));
} catch (UnsupportedEncodingException ue) {
LOG.warn(ue);
content = new String(data);
}
RemoteXMLResource res = new RemoteXMLResource( collection, handle, 0,
XmldbURI.EMPTY_URI, null );
res.setContent( content );
res.setProperties(outputProperties);
return res;
} catch (IOException ioe) {
throw new XMLDBException(ErrorCodes.VENDOR_ERROR, ioe.getMessage(), ioe);
} catch (DataFormatException dfe) {
throw new XMLDBException(ErrorCodes.VENDOR_ERROR, dfe.getMessage(), dfe);
} finally {
if(vtmpfile!=null) {
try {
vtmpfile.close();
} catch(IOException ioe) {
//IgnoreIT(R)
}
}
}
} catch (XmlRpcException xre) {
throw new XMLDBException(ErrorCodes.INVALID_RESOURCE, xre.getMessage(), xre);
}
}
public Resource getResource( long pos ) throws XMLDBException {
if ( pos >= resources.size() )
return null;
// node or value?
if ( resources.get( (int) pos ) instanceof Object[] ) {
// node
Object[] v = (Object[]) resources.get( (int) pos );
String doc = (String) v[0];
String s_id = (String) v[1];
XmldbURI docUri;
try {
docUri = XmldbURI.xmldbUriFor(doc);
} catch (URISyntaxException e) {
throw new XMLDBException(ErrorCodes.INVALID_URI,e.getMessage(),e);
}
RemoteCollection parent =
new RemoteCollection(collection.getClient(), null, docUri.removeLastSegment());
parent.properties = outputProperties;
RemoteXMLResource res =
new RemoteXMLResource( parent, handle,
(int)pos, docUri, s_id );
res.setProperties(outputProperties);
return res;
} else if ( resources.get( (int) pos ) instanceof Resource )
return (Resource) resources.get( (int) pos );
else {
// value
RemoteXMLResource res = new RemoteXMLResource( collection, handle, (int)pos,
XmldbURI.create(Long.toString( pos )), null );
res.setContent( resources.get( (int) pos ) );
res.setProperties(outputProperties);
return res;
}
}
public long getSize() throws XMLDBException {
return resources == null ? 0 : (long) resources.size();
}
public void removeResource( long pos ) throws XMLDBException {
resources.get( (int) pos );
}
protected void finalize() throws Throwable {
try {
clear();
} finally {
super.finalize();
}
}
class NewResourceIterator implements ResourceIterator {
long pos = 0;
public NewResourceIterator() { }
public NewResourceIterator( long start ) {
pos = start;
}
public boolean hasMoreResources() throws XMLDBException {
return resources == null ? false : pos < resources.size();
}
public Resource nextResource() throws XMLDBException {
return getResource( pos++ );
}
}
}