connectivity.ClarolineService.java Source code

Java tutorial

Introduction

Here is the source code for connectivity.ClarolineService.java

Source

/**
 * Claroline Mobile - Android
 * 
 * @package     connectivity
 * 
 * @author      Devos Quentin (q.devos@student.uclouvain.be)
 * @version     1.0
 *
 * @license     ##LICENSE##
 * @copyright   2013 - Devos Quentin
 */
package connectivity;

import java.io.ByteArrayOutputStream;
import java.util.Iterator;
import java.util.regex.Pattern;

import javax.net.ssl.SSLException;

import model.Cours;
import model.ModelBase;
import model.ResourceList;
import model.ResourceModel;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import util.Tools;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Base64;
import android.util.Log;
import app.App;

import com.activeandroid.query.Select;
import com.google.gson.JsonSyntaxException;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.BinaryHttpResponseHandler;
import com.loopj.android.http.JsonHttpResponseHandler;
import com.loopj.android.http.RequestParams;

/**
 * Claroline Mobile - Android
 * 
 * Service providing all the methods callable on the web service of Claroline.
 * 
 * @author Devos Quentin (q.devos@student.uclouvain.be)
 * @version 1.0
 */
public class ClarolineService {

    /**
     * Numeric Constant.
     */
    private static final int C100 = 100;
    /**
     * Regex pattern.
     */
    private static final Pattern PLATFORM_SETTINGS = Pattern
            .compile("<!-- PLATFORM SETTINGS (.*) PLATFORM SETTINGS -->");

    /**
     * Debug tag.
     */
    private static final String TAG = "ClarolineService";

    /**
     * {@link ClarolineClient}.
     */
    private ClarolineClient mClient;

    /**
     * Internal counter.
     */
    private int mCounter = 0;

    /**
     * Specific handler for the profile picture.
     */
    private BinaryHttpResponseHandler mProfilePictureHandler = new BinaryHttpResponseHandler() {
        @Override
        public void onFailure(final Throwable error) {
            Log.e("ClarolineClient", error.getLocalizedMessage());
        };

        @Override
        public void onSuccess(final byte[] binaryData) {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inPreferredConfig = Bitmap.Config.ARGB_8888;
            Bitmap bm = BitmapFactory.decodeByteArray(binaryData, 0, binaryData.length);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            bm.compress(Bitmap.CompressFormat.JPEG, C100, baos);

            App.getPrefs().edit()
                    .putString(App.SETTINGS_USER_IMAGE, Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT))
                    .apply();
        };
    };

    /**
     * Default constructor without arguments.
     */
    public ClarolineService() {
        mClient = ClarolineClient.getInstance();
    }

    /**
     * Verify that the current host has a valid version of the module installed.
     * 
     * @param handler
     *            the handler to execute after the request
     */
    public void checkForModuleValidity(final JsonHttpResponseHandler handler) {
        mClient.siteCall(mClient.getUrl(App.getPrefs().getString(App.SETTINGS_PLATFORM_MODULE, "/module/MODULE/")),
                handler);
        RequestParams p = ClarolineClient.getRequestParams(SupportedModules.USER, SupportedMethods.getPlatformData);
        mClient.serviceQuery(p, handler);
    }

    /**
     * Verify that the passed host is a valid Claroline platform.
     * 
     * @param hostURL
     *            the requested url
     * @param handler
     *            the handler to execute after the request
     */
    public void checkHostValidity(final String hostURL, final AsyncHttpResponseHandler handler) {
        mClient.get(hostURL.replace(' ', '\0'), new AsyncHttpResponseHandler() {
            @Override
            public void onFailure(final Throwable error, final String content) {
                if (error.getCause() instanceof SSLException
                        && App.getPrefs().getBoolean(App.SETTINGS_HTTP_NO_SSL, false)) {
                    checkHostValidity(hostURL.replace("https://", "http://"), handler);
                } else {
                    handler.onFailure(error, content);
                }
            }

            @Override
            public void onFinish() {
                handler.onFinish();
            }

            @Override
            public void onSuccess(final String content) {
                handler.onSuccess(String.valueOf(
                        content.contains("<!-- - - - - - - - - - - Claroline " + "Body - - - - - - - - - -->"))
                        + "#" + hostURL);
            }
        });
    }

    /**
     * Gets the cours list.
     * 
     * @param handler
     *            the handler to execute after the request
     * 
     */
    public void getCourseList(final AsyncHttpResponseHandler handler) {
        RequestParams p = ClarolineClient.getRequestParams(SupportedModules.USER, SupportedMethods.getCourseList);
        mClient.serviceQuery(p, new JsonHttpResponseHandler() {
            @Override
            public void onFinish() {
                handler.onFinish();
            }

            @Override
            public void onSuccess(final JSONArray array) {
                for (int i = 0; i < array.length(); i++) {
                    try {
                        JSONObject item = array.getJSONObject(i);
                        Cours c = new Select().from(Cours.class).where("SysCode = ?", item.get("sysCode"))
                                .executeSingle();
                        if (c == null) {
                            c = App.getGSON().fromJson(item.toString(), Cours.class);
                        } else {
                            c.update(item);
                        }
                        c.setUpdated(true);
                        c.setLoadedDate(DateTime.now());
                        c.save();

                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
                Tools.cleanTableAfterUpdate(Cours.class, "1=1");
                handler.onSuccess(array.toString());
            }
        });
    }

    /**
     * Gets the URL tokenized for the requested document. Can be used during 30
     * secs.
     * 
     * @param syscode
     *            the syscode of the document course
     * @param resId
     *            the unique resource identifier of the requested document.
     * @param handler
     *            the handler to execute after the request
     */
    public void getDownloadTokenizedUrl(final String syscode, final String resId,
            final AsyncHttpResponseHandler handler) {
        RequestParams rp = ClarolineClient.getRequestParams(SupportedModules.CLDOC,
                SupportedMethods.getSingleResource, syscode, resId);
        mClient.serviceQuery(rp, new JsonHttpResponseHandler() {
            @Override
            public void onSuccess(final JSONObject response) {
                if (response.has("token")) {
                    try {
                        handler.onSuccess(mClient
                                .getUrl(App.getPrefs().getString(App.SETTINGS_PLATFORM_MODULE, "/module/MOBILE/")
                                        + "download.php?token=" + response.getString("token")));
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

    /**
     * Retrieves the page at the specified url.
     * 
     * @param url
     *            the url of the page to get
     * @param handler
     *            the handler to execute after the request
     */
    public void getPageFor(final String url, final AsyncHttpResponseHandler handler) {
        mClient.siteCall(url, handler);
    }

    /**
     * Gets all the resources for a requested Tool.
     * 
     * @param list
     *            the requested Tool
     * @param handler
     *            the handler to execute after the request
     */
    public void getResourcesForList(final ResourceList list, final AsyncHttpResponseHandler handler) {
        RequestParams rp = ClarolineClient.getRequestParams(list.getLabel(), SupportedMethods.getResourcesList,
                list.getCours().getSysCode());
        if (ResourceModel.class.equals(list.getResourceType())) {
            rp.add("forceGeneric", "1");
        }

        mClient.serviceQuery(rp, new JsonHttpResponseHandler() {

            @Override
            public void onFinish() {
                handler.onFinish();
            }

            @Override
            public void onSuccess(final JSONArray array) {
                Log.i(TAG, array.toString());
                for (int i = 0; i < array.length(); i++) {
                    try {
                        ModelBase mb = new Select().from(list.getResourceType())
                                .where("List = ? AND ResourceString = ?", array.getJSONObject(i).get("resourceId"))
                                .executeSingle();
                        if (mb == null) {
                            mb = App.getGSON().fromJson(array.get(i).toString(), list.getResourceType());
                        } else {
                            mb.update(array.getJSONObject(i));
                        }
                        mb.setList(list);
                        mb.setLoadedDate(DateTime.now());
                        mb.setUpdated(true);
                        mb.save();
                    } catch (JSONException e) {
                        e.printStackTrace();
                    } catch (JsonSyntaxException e) {
                        e.printStackTrace();
                    }
                }
                list.setLoadedDate(DateTime.now());
                list.save();

                Tools.cleanTableAfterUpdate(list.getResourceType(), "List = ?", list);
                handler.onSuccess(array.toString());
            }
        });
    }

    /**
     * Gets the content of one specific resource.
     * 
     * @param syscode
     *            the course code
     * @param label
     *            the tool label
     * @param type
     *            the resource type
     * @param resourceIdentifier
     *            the resource unique identifier
     * @param handler
     *            the handler to execute after the request
     */
    public void getSingleResource(final String syscode, final String label, final Class<? extends ModelBase> type,
            final String resourceIdentifier, final AsyncHttpResponseHandler handler) {
        RequestParams p = ClarolineClient.getRequestParams(Enum.valueOf(SupportedModules.class, label),
                SupportedMethods.getSingleResource, syscode, resourceIdentifier);
        mClient.serviceQuery(p, new JsonHttpResponseHandler() {

            @Override
            public void onFinish() {
                handler.onFinish();
            }

            @Override
            public void onSuccess(final JSONObject response) {
                ModelBase mb;
                try {
                    mb = new Select().from(type)
                            .where("List = ? AND ResourceString = ?", response.get("resourceId")).executeSingle();
                    if (mb == null) {
                        mb = App.getGSON().fromJson(response.toString(), type);
                    } else {
                        mb.update(response);
                    }
                    mb.setLoadedDate(DateTime.now());
                    mb.save();

                } catch (JSONException e1) {
                    e1.printStackTrace();
                }
                handler.onSuccess(response.toString());
            }
        });
    }

    /**
     * Gets the tool list for the given course.
     * 
     * @param cours
     *            the course to load
     * @param handler
     *            the handler to execute after the request
     */
    public void getToolListForCours(final Cours cours, final AsyncHttpResponseHandler handler) {
        RequestParams rp = ClarolineClient.getRequestParams(SupportedModules.USER, SupportedMethods.getToolList,
                cours.getSysCode());
        mClient.serviceQuery(rp, new JsonHttpResponseHandler() {

            @Override
            public void onFinish() {
                handler.onFinish();
            }

            @Override
            public void onSuccess(final JSONArray response) {
                for (int i = 0; i < response.length(); i++) {
                    try {
                        JSONObject item = response.getJSONObject(i);
                        ResourceList rl = new Select().from(ResourceList.class)
                                .where("Cours = ? AND label = ?", cours, item.getString("label")).executeSingle();
                        if (rl == null) {
                            rl = App.getGSON().fromJson(item.toString(), ResourceList.class);
                            rl.setCours(cours);
                            rl.setResourceType(SupportedModules.getTypeForModule(rl.getLabel()));
                        } else {
                            rl.update(item);
                        }
                        rl.setUpdated(true);
                        rl.save();
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }

                cours.setLoadedDate(DateTime.now());
                cours.save();
                Tools.cleanTableAfterUpdate(ResourceList.class, "Cours = ?", cours);
                handler.onSuccess(response.toString());
            }
        });
    }

    /**
     * Gets the last updates.
     * 
     * @param handler
     *            the handler to execute if the request is successful
     */
    public void getUpdates(final AsyncHttpResponseHandler handler) {
        RequestParams p = ClarolineClient.getRequestParams(SupportedModules.USER, SupportedMethods.getUpdates);
        mClient.serviceQuery(p, new JsonHttpResponseHandler() {

            @Override
            public void onFailure(final Throwable e, final String array) {
                Log.e("ClarolineClient", "FAILURE ! :" + e.getLocalizedMessage());
            }

            @Override
            public void onFinish() {
                handler.onFinish();
            }

            @Override
            public void onSuccess(final JSONArray response) {
                handler.onSuccess(response.toString());
            }

            @SuppressWarnings("unchecked")
            @Override
            public void onSuccess(final JSONObject object) {

                Iterator<String> iterOnCours = object.keys();
                while (iterOnCours.hasNext()) {
                    final String syscode = iterOnCours.next();
                    final Cours upCours = new Select().from(Cours.class).where("Syscode = ?", syscode)
                            .executeSingle();

                    if (upCours == null) {
                        getCourseList(new AsyncHttpResponseHandler() {
                            @Override
                            public void onSuccess(final String content) {
                                Cours cours = new Select().from(Cours.class).where("Syscode = ?", syscode)
                                        .executeSingle();

                                if (cours != null) {
                                    updateCompleteCourse(cours, null, new AsyncHttpResponseHandler());
                                }
                            }
                        });
                        continue;
                    } else {
                        try {
                            JSONObject jsonCours = object.getJSONObject(syscode);
                            Iterator<String> iterOnMod = jsonCours.keys();
                            while (iterOnMod.hasNext()) {
                                final String modKey = iterOnMod.next();
                                ResourceList upList = new Select().from(ResourceList.class)
                                        .where("Cours = ? AND label = ?", upCours, modKey).executeSingle();

                                if (upList == null) {
                                    getToolListForCours(upCours, new AsyncHttpResponseHandler() {
                                        @Override
                                        public void onSuccess(final String content) {
                                            ResourceList list = new Select().from(ResourceList.class)
                                                    .where("Cours = ? AND label = ?", upCours, modKey)
                                                    .executeSingle();
                                            if (list != null) {
                                                getResourcesForList(list, new AsyncHttpResponseHandler());
                                            }
                                        }
                                    });
                                    continue;
                                } else {
                                    try {
                                        JSONObject jsonRes = jsonCours.getJSONObject(modKey);
                                        Iterator<String> iterOnKeys = jsonRes.keys();
                                        while (iterOnKeys.hasNext()) {
                                            String resourceString = iterOnKeys.next();
                                            ModelBase upRes = new Select()
                                                    .from(SupportedModules.getTypeForModule(modKey))
                                                    .where("List = ?", upList).executeSingle();
                                            if (upRes == null) {
                                                getResourcesForList(upList, new AsyncHttpResponseHandler());
                                            } else {
                                                DateTime date = DateTime.parse(
                                                        jsonRes.optString(resourceString, ""),
                                                        DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
                                                upRes.setDate(date);
                                                upRes.setNotifiedDate(date);
                                            }
                                        }
                                    } catch (JSONException e) {
                                        e.printStackTrace();
                                    }

                                }
                            }
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                }

                handler.onSuccess(object.toString());
            }
        });
    }

    /**
     * Gets the data about the current user.
     * 
     * @param handler
     *            the handler to execute if the request is successful
     */
    public void getUserData(final AsyncHttpResponseHandler handler) {
        RequestParams p = ClarolineClient.getRequestParams(SupportedModules.USER, SupportedMethods.getUserData);
        mClient.serviceQuery(p, new JsonHttpResponseHandler() {
            @Override
            public void onFinish() {
                handler.onFinish();
            }

            @Override
            public void onSuccess(final JSONObject jsonUser) {
                String previousPicture = App.getPrefs().getString(App.SETTINGS_PICTURE, "");
                App.getPrefs().edit()
                        .putString(App.SETTINGS_FIRST_NAME, jsonUser.optString(App.SETTINGS_FIRST_NAME))
                        .putString(App.SETTINGS_LAST_NAME, jsonUser.optString(App.SETTINGS_LAST_NAME))
                        .putBoolean(App.SETTINGS_IS_PLATFORM_ADMIN,
                                jsonUser.optBoolean(App.SETTINGS_IS_PLATFORM_ADMIN))
                        .putString(App.SETTINGS_OFFICIAL_CODE,
                                String.valueOf(jsonUser.optInt(App.SETTINGS_OFFICIAL_CODE)))
                        .putString(App.SETTINGS_PLATFORM_NAME, jsonUser.optString(App.SETTINGS_PLATFORM_NAME))
                        .putString(App.SETTINGS_INSTITUTION_NAME, jsonUser.optString(App.SETTINGS_INSTITUTION_NAME))
                        .putString(App.SETTINGS_PICTURE, jsonUser.optString(App.SETTINGS_PICTURE)).apply();

                String imgUrl = jsonUser.optString(App.SETTINGS_PICTURE, "");
                if (!imgUrl.equals("") && !imgUrl.equals(previousPicture)) {
                    mClient.get(imgUrl, mProfilePictureHandler);
                }
                handler.onSuccess(jsonUser.toString());
            }
        });
    }

    /**
     * Updates completely the course, loading first the Tool list, then the
     * resources for each tool.
     * 
     * @param cours
     *            the course to load
     * @param activity
     *            the calling activity
     * @param handler
     *            the handler to execute after the request
     */
    public void updateCompleteCourse(final Cours cours, final Activity activity,
            final AsyncHttpResponseHandler handler) {
        getToolListForCours(cours, new AsyncHttpResponseHandler() {

            @Override
            public void onFinish() {
                handler.onFinish();
            }

            @Override
            public void onSuccess(final String response) {
                mCounter = 0;
                for (ResourceList list : cours.lists()) {
                    getResourcesForList(list, new AsyncHttpResponseHandler() {
                        @Override
                        public void onSuccess(final String response) {
                            synchronized (cours) {
                                mCounter++;
                                cours.notify();
                            }
                        }
                    });
                }
                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            synchronized (cours) {
                                while (mCounter < cours.lists().size()) {
                                    cours.wait();
                                }
                                mCounter = 0;

                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } finally {
                            if (activity != null) {
                                activity.runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        handler.onSuccess(response);
                                    }
                                });
                            }
                        }
                    }
                }).start();
            }
        });
    }
}