org.xmetdb.rest.protocol.CallableProtocolUpload.java Source code

Java tutorial

Introduction

Here is the source code for org.xmetdb.rest.protocol.CallableProtocolUpload.java

Source

package org.xmetdb.rest.protocol;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import net.idea.modbcum.i.query.IQueryUpdate;
import net.idea.modbcum.p.ProcessorException;
import net.idea.modbcum.p.QueryExecutor;
import net.idea.modbcum.p.UpdateExecutor;
import net.idea.modbcum.q.conditions.EQCondition;
import net.idea.opentox.cli.OTClient;
import net.idea.opentox.cli.structure.Substance;
import net.idea.opentox.cli.structure.SubstanceClient;
import net.idea.opentox.cli.task.FibonacciSequence;
import net.idea.opentox.cli.task.RemoteTask;
import net.idea.restnet.c.task.CallableProtectedTask;
import net.idea.restnet.groups.DBOrganisation;
import net.idea.restnet.groups.DBProject;
import net.idea.restnet.groups.db.CreateGroup;
import net.idea.restnet.i.task.TaskResult;
import net.idea.restnet.user.DBUser;
import net.idea.restnet.user.db.ReadUser;
import net.toxbank.client.policy.AccessRights;
import net.toxbank.client.resource.User;

import org.apache.commons.fileupload.FileItem;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.auth.params.AuthPNames;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.AuthPolicy;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.restlet.data.Form;
import org.restlet.data.Method;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.resource.ResourceException;
import org.xmetdb.rest.protocol.attachments.DBAttachment;
import org.xmetdb.rest.protocol.attachments.DBAttachment.attachment_type;
import org.xmetdb.rest.protocol.attachments.db.AddAttachment;
import org.xmetdb.rest.protocol.db.CreateProtocol;
import org.xmetdb.rest.protocol.db.CreateProtocolVersion;
import org.xmetdb.rest.protocol.db.DeleteProtocol;
import org.xmetdb.rest.protocol.db.PublishProtocol;
import org.xmetdb.rest.protocol.db.ReadProtocol;
import org.xmetdb.rest.protocol.db.ReadProtocolByID;
import org.xmetdb.rest.protocol.db.UpdateProtocol;
import org.xmetdb.rest.protocol.resource.db.ProtocolQueryURIReporter;
import org.xmetdb.xmet.client.Resources;

import ambit2.base.data.Property;

public class CallableProtocolUpload extends CallableProtectedTask<String> {
    public enum UpdateMode {
        create {
            @Override
            public String getDescription() {
                return "New observation";
            }
        },
        update {
            @Override
            public String getDescription() {
                return "Update";
            }
        },
        dataTemplateOnly {
            @Override
            public String getDescription() {
                return "Upload attachment(s)";
            }
        },
        createversion {
            @Override
            public String getDescription() {
                return "Observation new version";
            }
        };
        public String getDescription() {
            return name();
        }
    }

    protected List<FileItem> input;
    protected ProtocolQueryURIReporter reporter;
    protected Connection connection;
    protected UpdateExecutor exec;
    protected String baseReference;
    protected DBUser user;
    protected File dir;
    protected DBProtocol protocol;
    protected Method method;
    protected UpdateMode updateMode = UpdateMode.create;

    protected String queryService;
    protected UsernamePasswordCredentials creds;

    public UpdateMode getUpdateMode() {
        return updateMode;
    }

    public void setUpdateMode(UpdateMode updateMode) {
        this.updateMode = updateMode;
    }

    public boolean isSetDataTemplateOnly() {
        return UpdateMode.dataTemplateOnly.equals(updateMode);
    }

    public void setSetDataTemplateOnly(boolean setDataTemplateOnly) {
        this.updateMode = UpdateMode.dataTemplateOnly;
    }

    /**
     * 
     * @param protocol  NULL if a new protocol, otherwise the protocol which version to be created
     * @param user
     * @param input
     * @param connection
     * @param r
     * @param token
     * @param baseReference
     * @param dir
     */
    public CallableProtocolUpload(Method method, DBProtocol protocol, DBUser user, List<FileItem> input,
            Connection connection, ProtocolQueryURIReporter r, String token, String baseReference, File dir,
            String queryService, UsernamePasswordCredentials creds) throws Exception {
        super(token);
        this.method = method;
        this.protocol = protocol;
        this.connection = connection;
        this.input = input;
        this.reporter = r;
        this.baseReference = baseReference;
        this.user = user;
        this.dir = dir;
        try {
            if (user != null) {
                retrieveAccountNames(user, connection);
                if (user.getID() <= 0)
                    user = null; //throw new Exception("Invalid user "+user.getUserName());
            }
        } catch (Exception x) {
            user = null;
        }
        this.queryService = queryService;
        this.creds = creds;
    }

    @Override
    public TaskResult doCall() throws Exception {
        if (Method.POST.equals(method))
            return create();
        else if (Method.PUT.equals(method))
            return update();
        else if (Method.DELETE.equals(method))
            return delete();
        throw new ResourceException(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED, method.toString());
    }

    @Override
    public String toString() {
        if (Method.DELETE.equals(method))
            return "Remove document";
        if (Method.PUT.equals(method))
            return "Update document";
        else
            return updateMode.getDescription();
    }

    public TaskResult delete() throws ResourceException {
        try {
            connection.setAutoCommit(false);
            //protocol.setOwner(user);
            exec = new UpdateExecutor<IQueryUpdate>();
            exec.setConnection(connection);
            if (isSetDataTemplateOnly()) {
                //DeleteProtocol k = new DeleteProtocol(protocol);
                //exec.process(k);            
            } else {
                DeleteProtocol k = new DeleteProtocol(protocol);
                exec.process(k);
                connection.commit();

            }
            return new TaskResult(String.format("%s%s", baseReference, Resources.protocol), false);
        } catch (ResourceException x) {
            try {
                connection.rollback();
            } catch (Exception xx) {
            }
            throw x;
        } catch (Exception x) {
            try {
                connection.rollback();
            } catch (Exception xx) {
            }
            throw new ResourceException(Status.SERVER_ERROR_INTERNAL, x);
        } finally {
            try {
                exec.close();
            } catch (Exception x) {
            }
            try {
                connection.setAutoCommit(true);
            } catch (Exception x) {
            }
            try {
                connection.close();
            } catch (Exception x) {
            }
        }
    }

    public TaskResult create() throws ResourceException {
        boolean existing = protocol != null && protocol.getIdentifier() != null;
        String identifier = existing ? protocol.getIdentifier() : DBProtocol.generateIdentifier();
        AccessRights policy = new AccessRights(null);
        try {
            if (existing && UpdateMode.dataTemplateOnly.equals(updateMode) && (protocol.getID() <= 0))
                retrieveProtocol(protocol, connection);
        } catch (Exception x) {

        }
        try {
            protocol = ProtocolFactory.getProtocol(protocol, input, 10000000, dir, policy, updateMode);
            if (user != null)
                protocol.setOwner(user);
            else {
                user = (DBUser) protocol.getOwner();
                if ((user != null) && (user.getID() <= 0) && (user.getResourceURL() != null))
                    user.setID(user.parseURI(baseReference));
                //retrieveAccountNames(user, connection);
            }
            if (user == null)
                throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Observation owner not specified!");
        } catch (ResourceException x) {
            throw x;
        } catch (Exception x) {
            throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, x);
        }
        //now write
        switch (updateMode) {
        case dataTemplateOnly: {
            if ((protocol.getAttachments() != null) && protocol.getAttachments().size() > 0)
                try {

                    connection.setAutoCommit(false);
                    //protocol.setOwner(user);
                    exec = new UpdateExecutor<IQueryUpdate>();
                    exec.setConnection(connection);
                    AddAttachment k = new AddAttachment(protocol, null);
                    for (DBAttachment attachment : protocol.getAttachments()) {
                        //.getResourceURL().toString().startsWith("file:")
                        k.setObject(attachment);
                        exec.process(k);
                    }
                    connection.commit();
                    String uri = String.format("%s%s", reporter.getURI(protocol),
                            org.xmetdb.xmet.client.Resources.attachment);
                    return new TaskResult(uri, false);

                } catch (ProcessorException x) {
                    try {
                        connection.rollback();
                    } catch (Exception xx) {
                    }
                    throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, x);
                } catch (ResourceException x) {
                    try {
                        connection.rollback();
                    } catch (Exception xx) {
                    }
                    throw x;
                } catch (Exception x) {
                    try {
                        connection.rollback();
                    } catch (Exception xx) {
                    }
                    throw new ResourceException(Status.SERVER_ERROR_INTERNAL, x);
                } finally {
                    try {
                        exec.close();
                    } catch (Exception x) {
                    }
                    try {
                        connection.setAutoCommit(true);
                    } catch (Exception x) {
                    }
                    try {
                        connection.close();
                    } catch (Exception x) {
                    }
                }
            else
                throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "No attachments found!");
            //         break;
        }
        default: {
            try {
                connection.setAutoCommit(false);
                //protocol.setOwner(user);
                exec = new UpdateExecutor<IQueryUpdate>();
                exec.setConnection(connection);
                /*
                CreateUser quser = new CreateUser(null);
                //user
                DBUser user = protocol.getOwner() instanceof DBUser?
                 (DBUser)protocol.getOwner():
                 new DBUser(protocol.getOwner());
                 protocol.setOwner(user);
                 if (user.getID()<=0) user.setID(user.parseURI(baseReference));
                if (user.getID()<=0) {
                   quser.setObject(user);
                   exec.process(quser);
                }   
                    
                for (User u: protocol.getAuthors()) { 
                   DBUser author =u instanceof DBUser?(DBUser)u:new DBUser(u);
                     if (author.getID()<=0) author.setID(author.parseURI(baseReference));
                      if (author.getID()<=0) {
                 quser.setObject(author);
                 exec.process(quser);
                      }   
                }
                */
                //project
                DBProject p;
                if (protocol.getProject() == null)
                    protocol.setProject(new DBProject(1)); //default xmetdb pproject
                else {
                    p = protocol.getProject() instanceof DBProject ? (DBProject) protocol.getProject()
                            : new DBProject(protocol.getProject());
                    protocol.setProject(p);
                    if (p.getID() <= 0)
                        p.setID(p.parseURI(baseReference));
                    if (p.getID() <= 0) {
                        CreateGroup q1 = new CreateGroup(p);
                        exec.process(q1);
                    }
                }
                //organisation
                DBOrganisation o;
                if (protocol.getOrganisation() == null)
                    protocol.setOrganisation(new DBOrganisation(1)); //default xmetdb org
                else {
                    o = protocol.getOrganisation() instanceof DBOrganisation
                            ? (DBOrganisation) protocol.getOrganisation()
                            : new DBOrganisation(protocol.getOrganisation());
                    protocol.setOrganisation(o);
                    if (o.getID() <= 0)
                        o.setID(o.parseURI(baseReference));
                    if (o.getID() <= 0) {
                        CreateGroup q2 = new CreateGroup(o);
                        exec.process(q2);
                    }
                }

                if (existing) {
                    protocol.setIdentifier(identifier); //in case the web form messed up the identifier
                    //TODO get the real version generated in order to return corect URI
                    CreateProtocolVersion q = new CreateProtocolVersion(DBProtocol.generateIdentifier(), protocol);
                    exec.process(q);
                } else {
                    protocol.setIdentifier(identifier);
                    CreateProtocol q = new CreateProtocol(protocol);
                    exec.process(q);
                    protocol.setID(q.getObject().getID());
                    protocol.setVersion(q.getObject().getVersion());
                    protocol.setIdentifier(String.format("XMETDB%d", protocol.getID()));
                }

                String uri = reporter.getURI(protocol);

                /*
                if ((protocol.getAuthors()!=null) && protocol.getAuthors().size()>0) {
                   AddAuthors k = new AddAuthors(protocol);
                   exec.process(k);
                }
                */
                if ((protocol.getAttachments() != null) && protocol.getAttachments().size() > 0) {
                    for (DBAttachment attachment : protocol.getAttachments()) {
                        AddAttachment k = new AddAttachment(protocol, attachment);
                        exec.process(k);
                        attachment.setID(k.getObject().getID());
                    }

                }

                connection.commit();

                //if commit succeeds, start import, but don't wait for it to complete
                if ((protocol.getAttachments() != null) && protocol.getAttachments().size() > 0) {
                    try {
                        RemoteImport rimport = new RemoteImport(queryService, creds);
                        for (DBAttachment attachment : protocol.getAttachments()) {
                            attachment.setProtocol(protocol);
                            rimport.remoteImport(attachment);

                        }
                    } finally {
                    }
                }
                //will redirect to the SOM editing page
                TaskResult result = new TaskResult(uri + "/som", true);
                /*
                try {
                   //adding the owner and the authors
                   addDefaultProtocolRights(policy,protocol.getOwner(),true,true,true,true);
                   //for (User u: protocol.getAuthors())   addDefaultProtocolRights(policy,u,true,true,true,true);
                   if ((policy.getRules()!=null) && (policy.getRules().size()>0)) {
                      retrieveAccountNames(policy,connection);
                      policy.setResource(new URL(uri));
                      result.setPolicy(generatePolicy(protocol,policy));
                   } else result.setPolicy(null);
                } 
                catch (Exception x) { result.setPolicy(null);}
                */
                return result;
            } catch (ProcessorException x) {
                try {
                    connection.rollback();
                } catch (Exception xx) {
                }
                throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, x);
            } catch (ResourceException x) {
                try {
                    connection.rollback();
                } catch (Exception xx) {
                }
                throw x;
            } catch (Exception x) {
                try {
                    connection.rollback();
                } catch (Exception xx) {
                }
                throw new ResourceException(Status.SERVER_ERROR_INTERNAL, x);
            } finally {
                try {
                    exec.close();
                } catch (Exception x) {
                }
                try {
                    connection.setAutoCommit(true);
                } catch (Exception x) {
                }
                try {
                    connection.close();
                } catch (Exception x) {
                }
            }
        }
        } //switch

    }

    public TaskResult update() throws ResourceException {
        if ((protocol == null) || (!protocol.isValidIdentifier()) || (protocol.getID() <= 0)
                || (protocol.getVersion() <= 0))
            throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Can't update: Not an existing protocol!");

        AccessRights policy = new AccessRights(null);
        try {
            //get only fields from the web form

            DBProtocol newProtocol = ProtocolFactory.getProtocol(null, input, 10000000, dir, policy, updateMode);
            newProtocol.setID(protocol.getID());
            newProtocol.setVersion(protocol.getVersion());
            if (newProtocol.getIdentifier() == null)
                newProtocol.setIdentifier(protocol.getIdentifier());

            //all non-null fields will be updated
            if (newProtocol.getProject() != null) {
                DBProject p = (DBProject) newProtocol.getProject();
                p.setID(p.parseURI(baseReference));
            }
            if (newProtocol.getOrganisation() != null) {
                DBOrganisation p = (DBOrganisation) newProtocol.getOrganisation();
                p.setID(p.parseURI(baseReference));
            }
            if (newProtocol.getOwner() != null) {
                DBUser p = (DBUser) newProtocol.getOwner();
                p.setID(p.parseURI(baseReference));
            }
            /*
            if (newProtocol.getAuthors()!=null)
               for (User u: newProtocol.getAuthors()) { 
                  DBUser author =u instanceof DBUser?(DBUser)u:new DBUser(u);
             if (author.getID()<=0) author.setID(author.parseURI(baseReference));
               }
            */
            protocol = newProtocol;
        } catch (Exception x) {
            throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, x);
        }
        String uri = null;
        try {
            connection.setAutoCommit(false);
            //protocol.setOwner(user);
            exec = new UpdateExecutor<IQueryUpdate>();
            exec.setConnection(connection);

            UpdateProtocol q = new UpdateProtocol(protocol);
            exec.process(q);
            if ((protocol.isPublished() != null) && protocol.isPublished() && (protocol.getEndpoint() != null)) {
                PublishProtocol pq = new PublishProtocol(protocol);
                exec.process(pq);
                retrieveProtocolIdentifier(protocol, connection);
            }
            uri = reporter.getURI(protocol);

            if ((protocol.getAttachments() != null) && protocol.getAttachments().size() > 0)
                for (DBAttachment attachment : protocol.getAttachments()) {
                    AddAttachment k = new AddAttachment(protocol, attachment);
                    exec.process(k);
                }

            connection.commit();

            if ((protocol.getAttachments() != null) && protocol.getAttachments().size() > 0) {
                try {
                    for (DBAttachment attachment : protocol.getAttachments()) {
                        attachment.setProtocol(protocol);
                        RemoteImport rimport = new RemoteImport(queryService, creds);
                        if (!attachment.isImported())
                            rimport.remoteImport(attachment);
                    }
                } finally {
                }
            }
            TaskResult result = new TaskResult(uri, false);

            return result;
        } catch (ProcessorException x) {
            try {
                connection.rollback();
            } catch (Exception xx) {
            }
            throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, x);
        } catch (ResourceException x) {
            try {
                connection.rollback();
            } catch (Exception xx) {
            }
            throw x;
        } catch (Exception x) {
            try {
                connection.rollback();
            } catch (Exception xx) {
            }
            throw new ResourceException(Status.SERVER_ERROR_INTERNAL, x);
        } finally {
            try {
                exec.close();
            } catch (Exception x) {
            }
            try {
                connection.setAutoCommit(true);
            } catch (Exception x) {
            }
            try {
                connection.close();
            } catch (Exception x) {
            }
        }

    }

    protected void addDefaultProtocolRights(AccessRights accessRights, User owner, Boolean get, Boolean post,
            Boolean put, Boolean delete) throws Exception {
        /*
        boolean added = false;
        for (PolicyRule rule: accessRights.getRules()) { 
           if (rule instanceof UserPolicyRule)  
        if (rule.hasSubject(owner)) added = true;
        }
        if (!added)
        */
        //it may be added alreayd, but with different rights. We enforce the owner always having full rights
        accessRights.addUserRule(owner, get, post, put, delete);
    }

    protected void retrieveAccountNames(DBUser user, Connection connection) throws Exception {
        if ((user == null) || (user.getUserName() == null))
            throw new Exception("No owner defined");
        QueryExecutor qexec = new QueryExecutor();
        try {
            qexec.setCloseConnection(false);
            qexec.setConnection(connection);
            ReadUser getUser = new ReadUser();
            getUser.setValue(user);
            getUser.setCondition(EQCondition.getInstance());
            qexec.setConnection(connection);
            ResultSet rs = null;
            try {
                rs = qexec.process(getUser);
                while (rs.next()) {
                    DBUser result = getUser.getObject(rs);
                    user.setID(result.getID());
                }
            } catch (Exception x) {
                if (rs != null)
                    rs.close();
            }
            qexec.setConnection(null);
        } finally {
            try {
                qexec.close();
            } catch (Exception x) {
            }
        }

    }

    protected void retrieveProtocol(DBProtocol protocol, Connection connection) throws Exception {
        QueryExecutor qexec = new QueryExecutor();
        try {
            qexec.setCloseConnection(false);
            qexec.setConnection(connection);
            ReadProtocol getProtocol = new ReadProtocol(protocol);
            qexec.setConnection(connection);
            ResultSet rs = null;
            try {
                rs = qexec.process(getProtocol);
                while (rs.next()) {
                    DBProtocol result = getProtocol.getObject(rs);
                    protocol.setID(result.getID());
                    protocol.setVersion(result.getVersion());
                }
            } catch (Exception x) {
                if (rs != null)
                    rs.close();
            }
            qexec.setConnection(null);
        } finally {
            try {
                qexec.close();
            } catch (Exception x) {
            }
        }

    }

    protected void retrieveProtocolIdentifier(DBProtocol protocol, Connection connection) throws Exception {
        QueryExecutor qexec = new QueryExecutor();
        try {
            qexec.setCloseConnection(false);
            qexec.setConnection(connection);
            ReadProtocolByID getProtocol = new ReadProtocolByID();
            getProtocol.setValue(protocol);
            qexec.setConnection(connection);
            ResultSet rs = null;
            try {
                rs = qexec.process(getProtocol);
                while (rs.next()) {
                    DBProtocol result = getProtocol.getObject(rs);
                    protocol.setIdentifier(result.getIdentifier());
                }
            } catch (Exception x) {
                if (rs != null)
                    rs.close();
            }
            qexec.setConnection(null);
        } finally {
            try {
                qexec.close();
            } catch (Exception x) {
            }
        }

    }
}

class RemoteImport {
    protected String[] algorithms = new String[] { "/algorithm/fingerprints", "/algorithm/struckeys",
            "/algorithm/smartsprop", "/algorithm/inchi" };
    protected String queryService;
    UsernamePasswordCredentials creds = null;

    public RemoteImport(String queryService, UsernamePasswordCredentials creds) {
        super();
        this.queryService = queryService;
        this.creds = creds;
    }

    protected RemoteTask remoteImport(DBAttachment attachment) throws Exception {
        Reference uri = new Reference(queryService);

        HttpClient client = createHTTPClient(uri.getHostDomain(), uri.getHostPort());
        RemoteTask task = new RemoteTask(client, new URL(String.format("%s/dataset", queryService)),
                "text/uri-list", createPOSTEntity(attachment), HttpPost.METHOD_NAME);

        try {
            task = wait(task, System.currentTimeMillis());
            String dataset_uri = "dataset_uri";
            URL dataset = task.getResult();
            if (task.isCompletedOK()) {
                if (!"text/uri-list".equals(attachment.getFormat())) { //was a file
                    //now post the dataset uri to get the /R datasets (query table)
                    attachment.setFormat("text/uri-list");
                    attachment.setDescription(dataset.toExternalForm());
                    task = new RemoteTask(client, new URL(String.format("%s/dataset", queryService)),
                            "text/uri-list", createPOSTEntity(attachment), HttpPost.METHOD_NAME);
                    task = wait(task, System.currentTimeMillis());
                    //indexing 
                    Form form = new Form();
                    form.add(dataset_uri, dataset.toURI().toString());
                    for (String algorithm : algorithms) { //just launch tasks and don't wait
                        List<NameValuePair> formparams = new ArrayList<NameValuePair>();
                        formparams.add(new BasicNameValuePair(dataset_uri, dataset.toURI().toString()));
                        HttpEntity entity = new UrlEncodedFormEntity(formparams, "UTF-8");
                        HttpClient newclient = createHTTPClient(uri.getHostDomain(), uri.getHostPort());
                        try {
                            new RemoteTask(newclient, new URL(String.format("%s%s", queryService, algorithm)),
                                    "text/uri-list", entity, HttpPost.METHOD_NAME);

                        } catch (Exception x) {
                            x.printStackTrace();
                        } finally {
                            try {
                                newclient.getConnectionManager().shutdown();
                            } catch (Exception x) {
                            }
                        }
                    }
                } else {
                    if (attachment.getStructure() != null
                            && attachment.getStructure().getProperty(Property.getNameInstance()) != null)
                        try {
                            updateName(attachment.getDescription(),
                                    attachment.getStructure().getProperty(Property.getNameInstance()));
                        } catch (Exception x) {
                            x.printStackTrace();
                        }
                }
            }

        } catch (Exception x) {
            task.setError(new ResourceException(Status.SERVER_ERROR_BAD_GATEWAY,
                    String.format("Error importing chemical structures dataset to %s", uri), x));
        } finally {
            try {
                client.getConnectionManager().shutdown();
            } catch (Exception x) {
            }
        }
        return task;
    }

    /**
     * /compound/{id} PUT
     * @param compoundURI
     * @param name
     * @return
     * @throws Exception
     */
    protected String updateName(String compoundURI, Object name) throws Exception {
        if ((name == null) || "".equals(name.toString().trim()))
            return null;
        final Reference uri = new Reference(queryService);
        OTClient cli = null;
        //PUT
        try {
            cli = new OTClient() {
                protected HttpClient createHTTPClient() {
                    DefaultHttpClient cli = new DefaultHttpClient();
                    List<String> authpref = new ArrayList<String>();
                    authpref.add(AuthPolicy.BASIC);
                    cli.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF, authpref);
                    cli.getCredentialsProvider()
                            .setCredentials(new AuthScope(uri.getHostDomain(), uri.getHostPort()), creds);
                    return cli;
                };
            };
            SubstanceClient scli = cli.getSubstanceClient();
            Substance substance = new Substance();
            substance.setResourceIdentifier(new URL(compoundURI));
            substance.setName(name.toString().toLowerCase());
            RemoteTask task = scli.setSubstancePropertyAsync(new URL(compoundURI), substance, null, null);
            task.waitUntilCompleted(500);
            if (task.getError() != null)
                throw task.getError();
            return task.getResult().toExternalForm();
        } catch (Exception x) {
            //do smth
            throw x;
        } finally {
            try {
                cli.close();
            } catch (Exception x) {
            }
        }

    }

    protected HttpEntity createPOSTEntity(DBAttachment attachment) throws Exception {
        Charset utf8 = Charset.forName("UTF-8");

        if ("text/uri-list".equals(attachment.getFormat())) {
            List<NameValuePair> formparams = new ArrayList<NameValuePair>();
            formparams.add(new BasicNameValuePair("title", attachment.getProtocol().getIdentifier()));
            formparams.add(new BasicNameValuePair("dataset_uri", attachment.getDescription()));
            formparams.add(new BasicNameValuePair("folder",
                    attachment_type.substrate.equals(attachment.getType()) ? "substrate" : "product"));
            return new UrlEncodedFormEntity(formparams, "UTF-8");
        } else {
            if (attachment.getResourceURL() == null)
                throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Attachment resource URL is null! ");
            MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, null, utf8);
            entity.addPart("title", new StringBody(attachment.getTitle(), utf8));
            entity.addPart("seeAlso", new StringBody(attachment.getDescription(), utf8));
            entity.addPart("license", new StringBody("XMETDB", utf8));
            URI uri = attachment.getResourceURL().toURI();
            entity.addPart("file", new FileBody(new File(uri)));
            return entity;
        }
        //match, seeAlso, license
    }

    protected HttpClient createHTTPClient(String hostName, int port) {
        DefaultHttpClient cli = new DefaultHttpClient();
        List<String> authpref = new ArrayList<String>();
        authpref.add(AuthPolicy.BASIC);
        cli.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF, authpref);
        cli.getCredentialsProvider().setCredentials(new AuthScope(hostName, port), creds);
        ((DefaultHttpClient) cli).addRequestInterceptor(new HttpRequestInterceptor() {
            @Override
            public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
                //if (ssoToken != null)
                //request.addHeader("subjectid",ssoToken.getToken());
            }
        });
        return cli;
    }

    protected long pollInterval = 1500;
    protected long pollTimeout = 10000L * 60L * 5L; //50 min

    protected RemoteTask wait(RemoteTask task, long now) throws Exception {
        if (task.getError() != null)
            throw task.getError();
        if (task.getResult() == null)
            throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST,
                    String.format("%s returns empty contend instead of URI"));
        String result = task.getResult().toString();
        FibonacciSequence sequence = new FibonacciSequence();
        while (!task.poll()) {
            if (task.getError() != null)
                throw task.getError();
            Thread.sleep(sequence.sleepInterval(pollInterval, true, 1000 * 60 * 5));
            Thread.yield();
            if ((System.currentTimeMillis() - now) > pollTimeout)
                throw new ResourceException(Status.SERVER_ERROR_GATEWAY_TIMEOUT, String.format("%s %s ms > %s ms",
                        result == null ? task.getUrl() : result, System.currentTimeMillis() - now, pollTimeout));
        }

        if (task.getError() != null)
            if (task.getError() instanceof ResourceException)
                throw new ResourceException(Status.SERVER_ERROR_BAD_GATEWAY,
                        String.format("%s %d %s", result == null ? task.getUrl() : result,
                                ((ResourceException) task.getError()).getStatus().getCode(),
                                task.getError().getMessage()),
                        task.getError());
            else
                throw new ResourceException(
                        Status.SERVER_ERROR_BAD_GATEWAY, String.format("%s %s",
                                result == null ? task.getUrl() : result, task.getError().getMessage()),
                        task.getError());

        return task;
    }
}