package uk.ac.ebi.fg.myequivalents.webservices.client;
import java.io.FilterWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import javax.ws.rs.core.MediaType;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.IOUtils;
import uk.ac.ebi.fg.myequivalents.managers.interfaces.BackupManager;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.representation.Form;
import com.sun.jersey.multipart.FormDataBodyPart;
import com.sun.jersey.multipart.FormDataMultiPart;
/**
* Client implementation of the web service for {@link BackupManager}.
*
* @author brandizi
* <dl><dt>Date:</dt><dd>11 Mar 2015</dd>
*
*/
public class BackupWSClient extends MyEquivalentsWSClient implements BackupManager
{
public BackupWSClient ()
{
super ();
}
public BackupWSClient ( String baseUrl )
{
super ( baseUrl );
}
@Override
public int dump ( OutputStream out, Integer offset, Integer limit )
{
try
{
// Get the dump via REST
Form req = prepareReq ();
if ( offset != null ) req.add ( "offset", offset );
if ( limit != null ) req.add ( "limit", limit );
InputStream wsIn = getRawResultAsStream ( "/dump", req, "xml" );
final int [] result = new int[] { -1 };
// A filter to intercept the XML comment about the number of dumpled items
FilterWriter ctw = new FilterWriter( new OutputStreamWriter ( out, Charsets.UTF_8 ) )
{
private int itracked = 0;
private StringBuffer ctStr = null;
private char csingle[] = new char [ 1 ];
@Override
public void write ( int c ) throws IOException
{
super.write ( c );
csingle [ 0 ] = (char) c;
interceptCountComment ( csingle, 0, 1 );
}
@Override
public void write ( char[] cbuf, int off, int len ) throws IOException
{
super.write ( cbuf, off, len );
interceptCountComment ( cbuf, off, len );
}
@Override
public void write ( String str, int off, int len ) throws IOException
{
super.write ( str, off, len );
char[] buf = new char [ len ];
str.getChars ( off, off + len, new char [ len ], 0 );
interceptCountComment ( buf, 0, len );
}
private void interceptCountComment ( char[] c, int off, int len )
{
int end = off + len;
for ( int i = off; i < end; i++ )
{
if ( result [ 0 ] != -1 ) return; // result already fully tracked
if ( ctStr != null ) // result being built
{
if ( c [ i ] == ' ' )
{
if ( ctStr.length () > 0 )
// second space after '=', the end
result [ 0 ] = Integer.parseInt ( ctStr.toString () );
}
else
// keep collecting result digits
ctStr.append ( c [ i ] );
}
else
{
// Either we haven't seen a comment yet, or we can try to assume we're inside it,
// and scanning up to the possible '='
//
if ( "<!-- dumped-items-count =".charAt ( itracked ) == c [ i ] )
{
// We just started, or we are inside it, maybe
itracked++;
if ( c [ i ] == '=' )
ctStr = new StringBuffer ();
}
else
// Either it's not the right start point, or we went into a comment, but wasn't the right one
itracked = 0;
}
} // for i
} // interceptCountComment ()
};
// Copy the input to the output, putting the count filter above in between
IOUtils.copy ( new InputStreamReader ( wsIn, Charsets.UTF_8 ), ctw );
ctw.flush ();
if ( result [ 0 ] == -1 ) throw new RuntimeException (
"Internal error while dumping myEquivalents: the server didn't send any result count"
);
// The reason why we get a result count is simply to return it here
return result [ 0 ];
}
catch ( IOException ex ) {
throw new RuntimeException ( "Internal error while dumping myEquivalents: " + ex.getMessage (), ex );
}
}
@Override
public int upload ( InputStream in )
{
// Courtesy of: http://neopatel.blogspot.de/2011/04/jersey-posting-multipart-data.html
Client cli = Client.create ();
WebResource wres = cli.resource ( this.baseUrl + this.getServicePath () + "/upload" );
FormDataMultiPart req = new FormDataMultiPart();
if ( this.email != null ) req.field ( "login", this.email );
if ( this.apiPassword != null ) req.field ( "login-secret", this.apiPassword );
req.bodyPart (
new FormDataBodyPart ( "dump-xml", in, MediaType.APPLICATION_OCTET_STREAM_TYPE )
);
return Integer.parseInt ( wres.type ( MediaType.MULTIPART_FORM_DATA ).post ( String.class, req ));
}
@Override
protected String getServicePath ()
{
return "/backup";
}
}