All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.citrix.sharefile.api.AbstractSFApiQuery Maven / Gradle / Ivy

package com.citrix.sharefile.api;

import com.citrix.sharefile.api.async.SFAsyncHelper;
import com.citrix.sharefile.api.constants.SFKeywords;
import com.citrix.sharefile.api.constants.SFQueryParams;
import com.citrix.sharefile.api.enumerations.SFHttpMethod;
import com.citrix.sharefile.api.enumerations.SFSafeEnum;
import com.citrix.sharefile.api.enumerations.SFV3ElementType;
import com.citrix.sharefile.api.exceptions.SFInvalidStateException;
import com.citrix.sharefile.api.exceptions.SFToDoReminderException;
import com.citrix.sharefile.api.gson.auto.SFDefaultGsonParser;
import com.citrix.sharefile.api.interfaces.ISFApiClient;
import com.citrix.sharefile.api.interfaces.ISFApiResultCallback;
import com.citrix.sharefile.api.interfaces.ISFAsyncTask;
import com.citrix.sharefile.api.interfaces.ISFQuery;
import com.citrix.sharefile.api.log.Logger;
import com.citrix.sharefile.api.models.SFODataObject;
import com.citrix.sharefile.api.models.SFSearchResults;
import com.citrix.sharefile.api.utils.Utils;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Created by tarungo on 1/28/2016.
 */
abstract class AbstractSFApiQuery  implements ISFQuery
{
    private static final String TAG = "SFApiQuery";
    protected ISFApiClient apiClient;
    private Object mTag;
    private String mServerResponse;

    /**
     * https://server/provider/version/entity(id)
     *
     * https://myaccount.sf-api.com/sf/v3/Items(id)
     *
     */
    private String mFromEntity = null;
    private String mAction = null;
    private String mSubAction = null;
    private String mHttpMethod = null;
    private String mProviderForUrlPath = "/"+SFProvider.PROVIDER_TYPE_SF+"/v3/";
    private String mId = null;
    private String mActionId = null;
    private final Map mQueryMap = new HashMap();
    private final Map mIdMap = new HashMap();
    private String mBody = null;
    private URI mLink = null; //The URL link obtained for V3connectors from their symbolic link or 302 redirect.
    private boolean mLinkIsParametrized = false;

    @Override
    public ISFQuery setApiClient(ISFApiClient apiClient)
    {
        this.apiClient = apiClient;
        return this;
    }

    /**
     The apiClient has an option to add query any parameters as follows:

     ArrayList expand = new ArrayList(){};
     expand.add(SFKeywords.INFO);
     expand.add(SFKeywords.CHILDREN);
     expand.add(SFKeywords.REDIRECTION);
     expand.add(SFKeywords.CHILDREN+ "/" +SFKeywords.PARENT);
     expand.add(SFKeywords.CHILDREN+ "/" +SFKeywords.REDIRECTION);
     addQueryString(SFQueryParams.EXPAND, expand);

     Expansion parameters are most frequently used so provide a simpler way
     for the apiClient to add them. so that the apiClient can call query.expand("somevalue1").expand("somevalue2")....expand("somevaluen") etc
     */
    private final ArrayList mExpansionParameters = new ArrayList(){};
    private final ArrayList mSelectParameters = new ArrayList(){};
    private final SFFilterParam mFilter = new SFFilterParam();

    public AbstractSFApiQuery(ISFApiClient client)
    {
        this.apiClient = client;
    }



    /**
     * Currently the server is not returning a DownloadSpecification for download requests,
     * its directly returning the download link. For the sake of completeness, implement the local
     * response filler for such requests.
     */
    @Override
    public boolean constructDownloadSpec()
    {
        boolean ret = false;

        if(SFKeywords.Items.equalsIgnoreCase(mFromEntity) && SFKeywords.Download.equalsIgnoreCase(mAction))
        {
            ret = true;
        }

        return ret;
    }

    /**
     * The username and password are used only for connectors auth. These can be set during auth errors or explicitly set during
     * the very first call from this query to avoid double round-trips to the server. We let the application handle setting of this
     * TODO: For security purpose we may want to wipe the credentials from this object when done using for auth.
     */
    private String mUserName;

    /**
     * The username and password are used only for connectors auth. These can be set during auth errors or explicitly set during
     * the very first call from this query to avoid double round-trips to the server. We let the application handle setting of this
     * TODO: For security purpose we may want to wipe the credentials from this object when done using for auth.
     */
    private String mPassword;

    private boolean allowRedirection = true;

    //{@link #getComponentAt(int, int) getComponentAt} method.

    /**
     * When whenever you want to re-execute a previous query with slightly different parameters
     * always use this function to copy feilds from the source query and then modify the necessry feilds.
     */
    public void copyQuery(AbstractSFApiQuery sourceQuery)
    {
        mFromEntity = sourceQuery.mFromEntity;
        mAction = sourceQuery.mAction;
        mHttpMethod = sourceQuery.mHttpMethod;
        mProviderForUrlPath = sourceQuery.mProviderForUrlPath;
        mId = sourceQuery.mId;
        mQueryMap.putAll(sourceQuery.mQueryMap);
        mIdMap.putAll(sourceQuery.mIdMap);
        mBody = sourceQuery.mBody;
        mLink = sourceQuery.mLink;
        mUserName = sourceQuery.mUserName;
        mPassword = sourceQuery.mPassword;
    }

    @Override
    public  ISFQuery expect(Class clazz)
    {
        AbstractSFApiQuery newQuery = AbstractSFApiQueryFactory.getAbstractSFApiQuery(clazz, apiClient);
        newQuery.copyQuery(this);
        return newQuery;
    }

    @Override
    public ISFQuery setCredentials(final String userName,final String password)
    {
        mUserName = userName;
        mPassword = password;
        return this;
    }

    @Override
    public final String getUserName()
    {
        return mUserName;
    }

    @Override
    public final String getPassword()
    {
        return mPassword;
    }

    @Override
    public final ISFQuery  setFrom(String setFrom)
    {
        mFromEntity = setFrom;
        return this;
    }

    /**
     This function takes any uri and store it entirely.
     example if you pass: https://szqatest2.sharefiletest.com/cifs/v3/Items(randdomid)
     This function will store it as: https://szqatest2.sharefiletest.com/cifs/v3/Items(randdomid)
     if the query needs additional params, the call to buildQueryUrlString() will add those to this
     one. In case you want to avoid that, call setFullyParametrizedLink() instead.
     */
    @Override
    public final ISFQuery  setLink(String link) throws URISyntaxException
    {
        if(link!=null)
        {
            mLink = new URI(link);
        }
        return this;
    }

    @Override
    public final URI getLink()
    {
        if(mLink == null)return null;

        //if mLink is base link return with provider
        if(isBaseLink(mLink)){
            try{
                return new URI( mLink + mProviderForUrlPath);
            }catch(URISyntaxException e){
                Logger.e(TAG,e);
            }
        }

        return mLink;
    }

    public final void setProvider(String provider)
    {
        mProviderForUrlPath = provider;
    }

    @Override
    public final ISFQuery  setAction(String action)
    {
        mAction = action;
        return this;
    }

    public final void setHttpMethod(SFHttpMethod httpMethod)
    {
        mHttpMethod = httpMethod.toString();
    }

    /**
     *  setId() and addIds() are mutually exclusive. We will throw and exception if both are called on the same QueryObject
     *  That's since we want to be able to build queries like: 

Items(id) or

Items(principalid=pid, itemid=itemid)

*/ public synchronized final void setId(String id) { if(mIdMap!=null && mIdMap.size() == 0) { mId = id; } else { throw new RuntimeException(SFKeywords.EXCEPTION_MSG_INVALID_PARAMETER_TO_QUERY); } } /** * setId() and addIds() are mutually exclusive. We will throw and exception if both are called on the same QueryObject * That's since we want to be able to build queries like:

Items(id) or

Items(principalid=pid, itemid=itemid)

*/ public synchronized final void addIds(String key,String value) { if(mId == null) { mIdMap.put(key, value); } else { throw new RuntimeException(SFKeywords.EXCEPTION_MSG_INVALID_PARAMETER_TO_QUERY); } } @Override public final ISFQuery addActionIds(String actionid) { mActionId = actionid; return this; } @Override public final ISFQuery addActionIds(Integer actionid) { mActionId = actionid.toString(); return this; } public final ISFQuery addActionIds(SFSafeEnum actionId) { mActionId = actionId.getOriginalString(); return this; } @Override public final ISFQuery addSubAction(String subaction) { mSubAction = subaction; return this; } @Override public final ISFQuery addSubAction(String subaction, SFSafeEnum extras) { mSubAction = subaction; return this; } @Override public final ISFQuery setBody(SFODataObject body) { mBody = new SFDefaultGsonParser().serialize(body.getClass(), body); return this; } public final ISFQuery setBody(String str) { mBody = str; return this; } @Override public final String getBody() { return mBody; } @Override public final ISFQuery addQueryString(String key,Object object) { if(object == null || key == null) { Logger.d(TAG,"Cannot add NULL parameter to queryString"); return this; } mQueryMap.put(key, object.toString()); return this; } @Override public ISFQuery addQueryString(String key, ArrayList ids) { if(ids == null || key == null) { return this; } //put expansion parameters in expansion map instead if(SFQueryParams.EXPAND.equals(key)) { expand(ids); return this; } addQueryStringInternal(key, ids); return this; } private void addQueryStringInternal(String key, ArrayList ids) { if(ids!=null) { StringBuilder sb = new StringBuilder(); boolean isFirst = true; for(String str:ids) { if(!isFirst) { sb.append(SFKeywords.COMMA); } else { isFirst = false; } sb.append(str); } mQueryMap.put(key, sb.toString()); } } @Deprecated public void addQueryString(String key, SFApiQuery query) { throw new SFToDoReminderException(SFKeywords.EXCEPTION_MSG_NOT_IMPLEMENTED); } private boolean isBaseLink(URI uri) { String path = uri.getPath(); if(path !=null && path.replaceAll("/","").length()>0) { return false; } return true; }; /** This functions builds the query url part with : https://subdomain.domain.com/provider/FromEntity(ids,..) */ private final String buildServerURLWithProviderAndEntity(String server) { StringBuilder sb = new StringBuilder(); /* * In case of CIF/SP connectors lets find out the provider type and the server to connect to from the given link */ if(mLink != null) { if(!isBaseLink(mLink)) { mProviderForUrlPath = "/"+SFProvider.getProviderType(mLink.getPath())+"/v3/"; return mLink.toString(); } server = mLink.toString(); } if(!server.startsWith(SFKeywords.PREFIX_HTTPS) && !server.startsWith(SFKeywords.PREFIX_HTTP)) { sb.append(SFKeywords.PREFIX_HTTPS); } sb.append(server); sb.append(mProviderForUrlPath); sb.append(mFromEntity); //Add the single Id or multiple comma separated key=value pairs after entity and enclose within () if(mId!=null) { sb.append(SFKeywords.OPEN_BRACKET); sb.append(mId); sb.append(SFKeywords.CLOSE_BRACKET); } else if (mIdMap!=null && mIdMap.size()>0) { sb.append(SFKeywords.OPEN_BRACKET); Set keyset = mIdMap.keySet(); boolean appendComma = keyset.size() > 1; for(String key:keyset) { String value = mIdMap.get(key); sb.append(key); sb.append(SFKeywords.EQUALS); sb.append(value); if(appendComma) { sb.append(SFKeywords.COMMA); } } sb.append(SFKeywords.CLOSE_BRACKET); } return sb.toString(); } /** *

https://server/provider/version/entity(id) * *

https://myaccount.sf-api.com/sf/v3/Items(id) * *

https://server/provider/version/entity(principalid=pid,itemid=id) * *

https://server/provider/version/entity(id)?$expand=Children * *

https://server/provider/version/entity?$expand=Children * *

https://server/provider/version/entity?$expand=Children&$select=FileCount,Id,Name,Children/Id,Children/Name,Children/CreationDate * *

https://account.sf-api.com/sf/v3/Items(parentid)/Folder?overwrite=false&passthrough=false * @throws UnsupportedEncodingException */ @Override public final String buildQueryUrlString(String server) throws UnsupportedEncodingException { if(mLinkIsParametrized && mLink!=null) { Logger.d(TAG,"Link is fully parametrized"); return mLink.toString(); } StringBuilder sb = new StringBuilder(); sb.append(buildServerURLWithProviderAndEntity(server)); //Add the Actions part if(!Utils.isEmpty(mAction)) { sb.append(SFKeywords.FWD_SLASH); sb.append(mAction); //Add action id if(!Utils.isEmpty(mActionId)) { sb.append(SFKeywords.OPEN_BRACKET); sb.append(mActionId); sb.append(SFKeywords.CLOSE_BRACKET); } //Add sub action if(!Utils.isEmpty(mSubAction)) { sb.append(SFKeywords.FWD_SLASH); sb.append(mSubAction); } } String queryParams = buildQueryParameters(null); if(!Utils.isEmpty(queryParams)) { sb.append(SFKeywords.CHAR_QUERY); sb.append(queryParams); } String queryUrlString = sb.toString(); Logger.d(SFKeywords.TAG,"QUERY URL String = " + queryUrlString); return queryUrlString; } private void addExpansionParams() { if(mExpansionParameters.size()>0) { addQueryStringInternal(SFQueryParams.EXPAND, mExpansionParameters); } } private void addSelectParams() { if(mSelectParameters.size()>0) { addQueryStringInternal(SFQueryParams.SELECT, mSelectParameters); } } private void addFilterParams() { String filters = mFilter.get(); if(!Utils.isEmpty(filters)) { addQueryString(SFQueryParams.FILTER, filters); } } private void addAllQueryParams() { addExpansionParams(); addSelectParams(); addFilterParams(); } private String[] getQueryParamsKeyValuePairs(String queryParams) { return queryParams!=null ? queryParams.split("&") : null; //This will return an array of "Key=values" and wont contain "&". } private boolean shouldSkip(String key, String[] serverSideParameters){ if(serverSideParameters == null || serverSideParameters.length ==0 ){ return false; } for(String str: serverSideParameters){ if(str.startsWith(key)){ return true; } } return false; } private String buildQueryParameters(String[] serverSideParameters) throws UnsupportedEncodingException { addAllQueryParams(); StringBuilder sb = new StringBuilder(); boolean isFirst = true; //Add query key , value pairs if(mQueryMap!=null && mQueryMap.size()>0) { Set keyset = mQueryMap.keySet(); for(String key:keyset) { //If server already has included this key, skip adding from client. if(shouldSkip(key,serverSideParameters)){ continue; } String value = mQueryMap.get(key); if(value!=null) { if(!isFirst) { sb.append(SFKeywords.CHAR_AMPERSAND); } else { isFirst = false; } String urlencoded = URLEncoder.encode(value, SFKeywords.UTF_8).replace("+", "%20"); sb.append(key); sb.append(SFKeywords.EQUALS); sb.append(urlencoded); } } } return sb.toString(); } @Override public final String getHttpMethod() { return mHttpMethod; } /** * we can renew token for Sharefile providers. */ @Override public boolean canReNewTokenInternally() { boolean ret = true; if(mLink!=null) { ret = (SFProvider.PROVIDER_TYPE_SF.equalsIgnoreCase(SFProvider.getProviderType(mLink))); } return ret; } @Override public ISFQuery setHttpMethod(String string) { mHttpMethod = string; return this; } @Override public ISFQuery addIds(URI url) { mLink = url; return this; } @Override public ISFQuery setBody( ArrayList sfoDataObjectsFeed) { mBody = new SFDefaultGsonParser().serialize(sfoDataObjectsFeed.getClass(), sfoDataObjectsFeed); return this; } @Override public ISFQuery setBody(Object object) { mBody = new SFDefaultGsonParser().serialize(object.getClass(), object); return this; } @Override public ISFQuery setLink(URI uri) { mLinkIsParametrized = false; mLink = uri; return this; } @Override public ISFQuery setFullyParametrizedLink(URI uri) { mLinkIsParametrized = true; mLink = uri; return this; } @Override public ISFQuery allowRedirection(boolean value) { allowRedirection = value; return this; } @Override public boolean reDirectionAllowed() { return allowRedirection; } /* For ZK redirection the server is sending back our original query parameters after url decoding. So our search for previous query parameters need to be done using our original format and even the decoded format. */ private boolean containsDecodedParams(String oldQueryParams,String newQueryParams) { if(oldQueryParams == null || newQueryParams == null) { return false; } try { HashMap oldQS = splitQuery(oldQueryParams); HashMap newQS = splitQuery(newQueryParams); for(String key : oldQS.keySet()) { if(!newQS.containsKey(key)) return false; } return true; } catch (Throwable e) { } return false; } private static HashMap splitQuery(String qs) { final HashMap query_pairs = new HashMap(); final String[] pairs = qs.split("&"); for (String pair : pairs) { String[] keyValue = pair.split("="); if(keyValue.length<2) continue; query_pairs.put(keyValue[0], keyValue[1]); } return query_pairs; } @Override public ISFQuery setLinkAndAppendPreviousParameters(URI newuri) throws URISyntaxException, UnsupportedEncodingException { String newQueryParams = newuri.getQuery(); String oldQueryParms = buildQueryParameters(getQueryParamsKeyValuePairs(newQueryParams)); Logger.d(TAG,"oldQparams = " + oldQueryParms); Logger.d(TAG,"newQparams = " + newQueryParams); StringBuilder sb = new StringBuilder(); sb.append(newuri.toString()); if(!Utils.isEmpty(oldQueryParms)) { if(newQueryParams == null || newQueryParams.length() == 0) { sb.append(SFKeywords.CHAR_QUERY); } else { sb.append(SFKeywords.CHAR_AMPERSAND); } sb.append(oldQueryParms); } String strNewUrl = sb.toString(); URI uri = new URI(strNewUrl); Logger.d(TAG,"Setting new URI by appending old params: " + uri.getQuery()); setFullyParametrizedLink(uri); return this; } @Override public ISFQuery setLinkAndAppendPreviousParameters(String string) throws URISyntaxException, UnsupportedEncodingException { setLinkAndAppendPreviousParameters(new URI(string)); return this; } @Override public ISFQuery expand(String expansionParameter) { if(Utils.isEmpty(expansionParameter)) { return this; } mExpansionParameters.add(expansionParameter); return this; } @Override public ISFQuery top(int topItems) { addQueryString(SFQueryParams.TOP,topItems); return this; } @Override public ISFQuery skip(int skipItems) { addQueryString(SFQueryParams.SKIP,skipItems); return this; } @Override public ISFQuery orderBy(String orderParameter, SFKeywords.DIRECTION direction) { addQueryString(SFQueryParams.ORDERBY,orderParameter + " " + direction.toString()); return this; } @Override public ISFQuery filter(String filterValue) { if(Utils.isEmpty(filterValue)) { return this; } mFilter.filter(filterValue); return this; } @Override public ISFQuery is(SFV3ElementType type) { mFilter.is(type); return this; } @Override public ISFQuery select(String selectParam) { if(Utils.isEmpty(selectParam)) { return this; } mSelectParameters.add(selectParam); return this; } private void expand(ArrayList expansionParameters) { if(Utils.isEmpty(expansionParameters)) { return ; } for(String str: expansionParameters) { mExpansionParameters.add(str); } } /** This function takes any uri and stores only its base part along with the provider example if you pass: https://szqatest2.sharefiletest.com/cifs/v3/Capabilities This function will store baseLink as : https://szqatest2.sharefiletest.com */ @Override public ISFQuery setBaseLink(URI uri) throws URISyntaxException { mProviderForUrlPath = "/"+SFProvider.getProviderType(uri)+"/v3/"; String host = uri.getHost(); String protocol = uri.getScheme(); mLink = new URI(protocol + "://" + host); return this; } @Override public void executeAsync(ISFApiResultCallback callback) { if(callback == null) { throw new RuntimeException("Need to set listener to gather Async Result"); } if(apiClient==null) { callback.onError(new SFInvalidStateException("No valid client object set for query"), this); return; } SFAsyncHelper asyncHelper = new SFAsyncHelper(apiClient, this, callback); ISFAsyncTask asyncTask = SFSdk.createAsyncTask(); if(asyncTask == null) { callback.onError(new SFInvalidStateException("Need to set AsyncFactory as per your system"), this); return; } asyncTask.start(asyncHelper); } @Override public void setTag(Object tag) { mTag = tag; } @Override public Object getTag() { return mTag; } @Override public String getStringResponse() { return mServerResponse; } @Override public void setStringResponse(String response) { mServerResponse = response; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy