org.rest.client.activity.RequestActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.rest.client.activity.RequestActivity.java

Source

/*******************************************************************************
 * Copyright 2012 Pawe Pszty
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package org.rest.client.activity;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.rest.client.ClientFactory;
import org.rest.client.ExternalEventsFactory;
import org.rest.client.RestClient;
import org.rest.client.analytics.GoogleAnalytics;
import org.rest.client.analytics.GoogleAnalyticsApp;
import org.rest.client.event.AddEncodingEvent;
import org.rest.client.event.ClearFormEvent;
import org.rest.client.event.HttpEncodingChangeEvent;
import org.rest.client.event.HttpMethodChangeEvent;
import org.rest.client.event.OverwriteUrlEvent;
import org.rest.client.event.ProjectChangeEvent;
import org.rest.client.event.ProjectChangeRequestEvent;
import org.rest.client.event.ProjectDeleteEvent;
import org.rest.client.event.ProjectDeleteRequestEvent;
import org.rest.client.event.RequestChangeEvent;
import org.rest.client.event.RequestEndEvent;
import org.rest.client.event.RequestStartActionEvent;
import org.rest.client.event.URLFieldToggleEvent;
import org.rest.client.event.UrlValueChangeEvent;
import org.rest.client.gdrive.DriveAuth;
import org.rest.client.gdrive.DriveApi;
import org.rest.client.gdrive.DriveFileItem;
import org.rest.client.jso.ExternalDriveCreateData;
import org.rest.client.jso.ExternalDriveCreateResponse;
import org.rest.client.place.RequestPlace;
import org.rest.client.request.RedirectData;
import org.rest.client.request.RequestHeadersParser;
import org.rest.client.request.URLParser;
import org.rest.client.storage.StoreResultCallback;
import org.rest.client.storage.store.LocalStore;
import org.rest.client.storage.store.ProjectStoreWebSql;
import org.rest.client.storage.store.RequestDataStoreWebSql;
import org.rest.client.storage.store.objects.FormEncodingObject;
import org.rest.client.storage.store.objects.HistoryObject;
import org.rest.client.storage.store.objects.ProjectObject;
import org.rest.client.storage.store.objects.RequestObject;
import org.rest.client.storage.websql.HeaderRow;
import org.rest.client.tutorial.TutorialFactory;
import org.rest.client.ui.AddEncodingView;
import org.rest.client.ui.EditProjectView;
import org.rest.client.ui.RequestView;
import org.rest.client.ui.ResponseView;
import org.rest.client.ui.desktop.StatusNotification;

import com.allen_sauer.gwt.log.client.Log;
import com.google.code.gwt.database.client.service.DataServiceException;
import com.google.code.gwt.database.client.service.ListCallback;
import com.google.code.gwt.database.client.service.VoidCallback;
import com.google.gwt.chrome.def.BackgroundJsCallback;
import com.google.gwt.chrome.def.BackgroundPageCallback;
import com.google.gwt.core.client.Callback;
import com.google.gwt.core.client.JavaScriptException;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.storage.client.Storage;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.xhr2.client.Header;
import com.google.gwt.xhr2.client.RequestHeader;
import com.google.gwt.xhr2.client.Response;
import com.google.web.bindery.event.shared.EventBus;
import com.google.web.bindery.event.shared.HandlerRegistration;

/**
 * Activities typically restore state ("wake up"), perform initialization
 * ("set up"), and load a corresponding UI ("show up")
 * 
 * @author Pawe Pszty
 * 
 */
public class RequestActivity extends AppActivity implements RequestView.Presenter, ResponseView.ResponsePresenter {

    final private RequestPlace place;
    private EventBus eventBus;
    protected ResponseView responseView;
    protected RequestView requestView;
    FlowPanel viewFlowPanel;
    TutorialFactory tutorialFactory = null;
    private String currentRequestEtag = null;

    private final static String ANALYTICS_EVENT_CATEGORY = "Request view";

    public RequestActivity(RequestPlace place, ClientFactory clientFactory) {
        super(clientFactory);
        this.place = place;
    }

    @Override
    public void start(AcceptsOneWidget panel, com.google.gwt.event.shared.EventBus eventBus) {

        this.eventBus = eventBus;
        super.start(panel, eventBus);
        if (RestClient.currentlyOpenedProject > 0) {
            RestClient.previouslyOpenedProject = RestClient.currentlyOpenedProject;
            RestClient.currentlyOpenedProject = -1;
        }

        Storage store = Storage.getSessionStorageIfSupported();
        store.removeItem(LocalStore.RESTORED_REQUEST);
        store.removeItem(LocalStore.CURRENT_GOOGLE_DRIVE_ITEM);
        currentRequestEtag = null;

        requestView = this.clientFactory.getRequestView();
        requestView.reset();

        requestView.setPresenter(this);
        viewFlowPanel = new FlowPanel();
        viewFlowPanel.add(requestView);
        panel.setWidget(viewFlowPanel);

        String entryId = place.getEntryId();

        if (place.isHistory()) {
            try {
                int historyId = Integer.parseInt(entryId);
                restoreRequestFromHistory(historyId);
            } catch (Exception e) {
                if (RestClient.isDebug()) {
                    Log.error("Unable read history ID", e);
                }
                StatusNotification.notify("Unable read history ID", StatusNotification.TYPE_ERROR,
                        StatusNotification.TIME_SHORT);
                restoreLatestRequest();
            }
        } else if (place.isProject()) {
            try {
                int projectId = Integer.parseInt(entryId);
                RestClient.currentlyOpenedProject = projectId;
                restoreRequestFromProject(projectId, -1);
            } catch (Exception e) {
                if (RestClient.isDebug()) {
                    Log.error("Unable read project ID", e);
                }
                StatusNotification.notify("Unable read project ID", StatusNotification.TYPE_ERROR,
                        StatusNotification.TIME_SHORT);
                restoreLatestRequest();
            }

        } else if (place.isProjectsEndpoint()) {
            try {
                int endpointId = Integer.parseInt(entryId);
                restoreRequestFromProject(-1, endpointId);
            } catch (Exception e) {
                if (RestClient.isDebug()) {
                    Log.error("Unable read project's endpoint ID", e);
                }
                StatusNotification.notify("Unable read project data", StatusNotification.TYPE_ERROR,
                        StatusNotification.TIME_SHORT);
                restoreLatestRequest();
            }
        } else if (place.isSaved()) {
            try {
                int savedId = Integer.parseInt(entryId);
                restoreFormSavedRequest(savedId);
            } catch (Exception e) {
                if (RestClient.isDebug()) {
                    Log.error("Unable read saved item ID", e);
                }
                StatusNotification.notify("Unable read saved request data", StatusNotification.TYPE_ERROR,
                        StatusNotification.TIME_SHORT);
                restoreLatestRequest();
            }
        } else if (place.isExternal()) {
            createExternalRequest(entryId);
        } else if (place.isGdrive()) {
            if (place.isCreate()) {
                fromGoogleDriveAction(entryId);
            } else {
                fromGoogleDriveFile(entryId);
            }
        } else {
            restoreLatestRequest();
        }
        observeEvents();
        activateTutorial();
    }

    private void fromGoogleDriveAction(final String entryId) {
        requestView.reset();

        clientFactory.getChromeMessagePassing().postMessage(ExternalEventsFactory.EXT_GET_EXTERNAL_REQUEST_DATA,
                entryId, new BackgroundJsCallback() {

                    @Override
                    public void onSuccess(JavaScriptObject message) {
                        ExternalDriveCreateResponse response;
                        try {
                            response = message.cast();
                        } catch (Exception e) {
                            StatusNotification.notify("Unable to read response from background page",
                                    StatusNotification.TYPE_ERROR, StatusNotification.TIME_MEDIUM);
                            return;
                        }
                        if (response.isError()) {
                            StatusNotification.notify(response.getErrorMessage(), StatusNotification.TYPE_ERROR,
                                    StatusNotification.TIME_MEDIUM);
                            return;
                        }
                        ExternalDriveCreateData data = response.getData();
                        if (data == null) {
                            StatusNotification.notify("No data passed to application.",
                                    StatusNotification.TYPE_ERROR, StatusNotification.TIME_MEDIUM);
                            return;
                        }

                        Storage store = Storage.getSessionStorageIfSupported();
                        store.setItem(LocalStore.GOOGLE_DRIVE_CREATE_FOLDER_ID, data.getFolderId());
                        store.setItem(LocalStore.GOOGLE_DRIVE_CREATE_USER_ID, data.getUserId());

                        tutorialFactory = new TutorialFactory("gdriveCreate", true);
                        requestView.setUpDriveTutorial(tutorialFactory);

                    }

                    @Override
                    public void onError(String message) {

                        Log.error("Error get gdrive data", message);
                    }
                });

    }

    private void fromGoogleDriveFile(final String entryId) {

        final DialogBox loader = new DialogBox(false);
        loader.setAnimationEnabled(false);
        loader.setAutoHideEnabled(false);
        loader.setAutoHideOnHistoryEventsEnabled(true);
        loader.setGlassEnabled(true);

        HTML html = new HTML("<div class=\"dialogTitle\">Loading file from Google Drive </div>");
        loader.add(html);

        loader.show();
        loader.center();

        DriveApi.hasSession(new DriveApi.SessionHandler() {
            @Override
            public void onResult(DriveAuth result) {
                if (result == null) {
                    //not logged in user
                    DriveApi.auth(new DriveApi.SessionHandler() {
                        @Override
                        public void onResult(DriveAuth result) {
                            if (result == null) {
                                loader.hide();
                                return;
                            }
                            getFileMetadataFromDrive(entryId, loader);
                        }
                    }, false);
                    return;
                }
                getFileMetadataFromDrive(entryId, loader);
            }
        });
    }

    private void getFileMetadataFromDrive(final String fileId, final DialogBox loader) {

        DriveApi.getFileMetadata(fileId, new DriveApi.FileMetadataHandler() {

            @Override
            public void onLoad(DriveFileItem response) {
                if (response == null) {
                    loader.hide();
                    StatusNotification.notify("Unable read from gdrive. ", StatusNotification.TYPE_ERROR,
                            StatusNotification.TIME_SHORT);
                    return;
                }

                downloadFileFromDrive(fileId, response, loader);
            }

            @Override
            public void onError(JavaScriptException exc) {
                loader.hide();
                if (RestClient.isDebug()) {
                    Log.error("Unable read from gdrive.", exc);
                }
                StatusNotification.notify("Unable read from gdrive. " + exc.getMessage(),
                        StatusNotification.TYPE_ERROR, StatusNotification.TIME_SHORT);
            }
        });
    }

    private void downloadFileFromDrive(final String fileId, final DriveFileItem response, final DialogBox loader) {

        final String fileUrl = response.getDownloadUrl();
        final String fileTitle = response.getTitle();
        final String fileEtag = response.getEtag();

        if (currentRequestEtag != null && fileEtag != null && fileEtag.equals(currentRequestEtag)) {
            //nothing has changed.
            loader.hide();
            requestView.setGDriveConstrols();
            return;
        }

        currentRequestEtag = fileEtag;

        DriveApi.downloadFile(fileUrl, new DriveApi.FileDownloadHandler() {
            @Override
            public void onError(JavaScriptException exc) {
                loader.hide();
                if (RestClient.isDebug()) {
                    Log.error("Unable download from gdrive.", exc);
                }
                StatusNotification.notify("Unable download from gdrive. " + exc.getMessage(),
                        StatusNotification.TYPE_ERROR, StatusNotification.TIME_SHORT);
            }

            @Override
            public void onDownload(String content) {
                if (content == null) {
                    loader.hide();
                    //request error
                    StatusNotification.notify("Unable download from gdrive. ", StatusNotification.TYPE_ERROR,
                            StatusNotification.TIME_SHORT);
                    return;
                }
                RequestObject values = null;
                try {
                    values = RequestObject.fromString(content);
                } catch (Exception e) {
                    loader.hide();
                    if (RestClient.isDebug()) {
                        Log.error("Invalid ARC file.", e);
                    }
                    StatusNotification.notify("Invalid ARC file.", StatusNotification.TYPE_ERROR,
                            StatusNotification.TIME_SHORT);
                    return;
                }

                if (values == null) {
                    StatusNotification.notify("Invalid ARC file.", StatusNotification.TYPE_ERROR,
                            StatusNotification.TIME_SHORT);
                } else {
                    Storage store = Storage.getSessionStorageIfSupported();
                    store.setItem(LocalStore.CURRENT_GOOGLE_DRIVE_ITEM, fileId);
                }

                values.setGDriveId(fileId);
                values.setName(fileTitle);

                setViewParameters(values);
                loader.hide();
            }
        });
    }

    /**
     * 
     * @param projectId -1 if project ID is unknown
     * @param endpointId -1 for default endpoint (first one) 
     * @param requestView
     */
    private void restoreRequestFromProject(int projectId, int endpointId) {
        if (projectId == -1 && endpointId == -1) {
            if (RestClient.isDebug()) {
                Log.error("Project ID and endpoint ID can't be -1 at once.");
            }
            StatusNotification.notify("Unable read project data", StatusNotification.TYPE_ERROR);
            restoreLatestRequest();
            return;
        }
        final ProjectStoreWebSql projectsStore = clientFactory.getProjectsStore();
        if (endpointId == -1) {
            projectsStore.getByKey(projectId, new StoreResultCallback<ProjectObject>() {

                @Override
                public void onSuccess(ProjectObject result) {
                    restoreDefaultRequestFromProject(result, requestView);
                }

                @Override
                public void onError(Throwable e) {
                    if (RestClient.isDebug()) {
                        Log.error("Unable read project data.", e);
                    }
                    StatusNotification.notify("Unable read project data", StatusNotification.TYPE_ERROR);
                }
            });
        } else {
            clientFactory.getRequestDataStore().getByKey(endpointId, new StoreResultCallback<RequestObject>() {
                @Override
                public void onSuccess(final RequestObject result) {
                    if (result.getProject() > 0) {
                        RestClient.currentlyOpenedProject = result.getProject();
                        projectsStore.getByKey(result.getProject(), new StoreResultCallback<ProjectObject>() {

                            @Override
                            public void onSuccess(ProjectObject project) {
                                restoreProjectEndpoint(project, result);
                            }

                            @Override
                            public void onError(Throwable e) {
                                if (RestClient.isDebug()) {
                                    Log.error("Unable read project data.", e);
                                }
                                StatusNotification.notify("Unable read project data",
                                        StatusNotification.TYPE_ERROR);
                            }
                        });
                    } else {
                        if (RestClient.isDebug()) {
                            Log.error("Project does not contain selected endpoint.");
                        }
                        StatusNotification.notify("Project does not contain selected endpoint.",
                                StatusNotification.TYPE_ERROR);
                    }
                }

                @Override
                public void onError(Throwable e) {
                    if (RestClient.isDebug()) {
                        Log.error("Unable read project data.", e);
                    }
                    StatusNotification.notify("Unable read project's endpoint data", StatusNotification.TYPE_ERROR);
                }
            });
        }
    }

    private void restoreDefaultRequestFromProject(final ProjectObject project, final RequestView requestView) {
        if (project == null || project.getId() <= 0) {
            if (RestClient.isDebug()) {
                Log.error("No such project.");
            }
            StatusNotification.notify("No such project.", StatusNotification.TYPE_ERROR);
            return;
        }
        clientFactory.getRequestDataStore().getService().getProjectDefaultRequests(project.getId(),
                new ListCallback<RequestObject>() {

                    @Override
                    public void onFailure(DataServiceException error) {
                        if (RestClient.isDebug()) {
                            Log.error("Can't find default endpoint for this project. Database error.", error);
                        }
                        StatusNotification.notify("Can't find default endpoint for this project.",
                                StatusNotification.TYPE_ERROR);
                    }

                    @Override
                    public void onSuccess(List<RequestObject> result) {
                        if (result == null || result.size() == 0) {
                            if (RestClient.isDebug()) {
                                Log.error("Can't find default endpoint for this project.");
                            }
                            StatusNotification.notify("Can't find default endpoint for this project.",
                                    StatusNotification.TYPE_ERROR);
                            return;
                        }
                        restoreProjectEndpoint(project, result.get(0));
                    }
                });
    }

    private void restoreProjectEndpoint(final ProjectObject project, final RequestObject request) {
        showProjectRelatedData(project.getId(), project);

        // if can overwrite current params first restore latest request
        // and then set parameters.
        if (RestClient.currentlyOpenedProject == RestClient.previouslyOpenedProject) {

            if (RestClient.isDebug()) {
                Log.debug("Restoring data for the same project as previous.");
            }

            RequestObject.restoreLatest(new Callback<RequestObject, Throwable>() {
                @Override
                public void onSuccess(RequestObject result) {
                    restoreProjectEndpointWithLatestData(result, project, request, requestView);
                }

                @Override
                public void onFailure(Throwable reason) {
                    StatusNotification.notify("Unable to complete :(", StatusNotification.TYPE_CRITICAL);
                    Log.error("Unable to restore project data :(", reason);
                }
            });

            return;
        }
        //treat it as a default projects request

        requestView.setHeaders(request.getHeaders());
        requestView.setMethod(request.getMethod());
        requestView.setPayload(request.getPayload());
        requestView.setEncoding(request.getEncoding());
        requestView.setUrl(request.getURL());

        setUserDefinedContentEncodingValues(request.getEncoding(), request.getHeaders());
        RestClient.fixChromeLayout();
        Storage store = Storage.getSessionStorageIfSupported();
        store.setItem(LocalStore.RESTORED_REQUEST, "" + request.getId());

    }

    private void restoreProjectEndpointWithLatestData(RequestObject lesteSavedRequest, final ProjectObject project,
            final RequestObject request, final RequestView requestView) {

        if (request.isSkipHeaders()) {
            requestView.setHeaders(lesteSavedRequest.getHeaders());
        } else {
            requestView.setHeaders(request.getHeaders());
        }
        if (request.isSkipMethod()) {
            requestView.setMethod(lesteSavedRequest.getMethod());
        } else {
            requestView.setMethod(request.getMethod());
        }
        if (request.isSkipPayload()) {
            requestView.setPayload(lesteSavedRequest.getPayload());
        } else {
            requestView.setPayload(request.getPayload());
        }
        requestView.setEncoding(request.getEncoding());
        if (RestClient.isDebug()) {
            Log.debug("Restoring encoding to ." + request.getEncoding());
        }

        String oldUrl = lesteSavedRequest.getURL();

        String newUrl = request.getURL();
        URLParser urlData = new URLParser().parse(newUrl);
        URLParser oldUrlData = new URLParser().parse(oldUrl);

        if (request.isSkipHistory()) {
            //remove hash from restored and get one from latest
            urlData.setAnchor(oldUrlData.getAnchor());
        }
        if (request.isSkipParams()) {
            //remove query string from restored and get one from latest
            urlData.setQuery(oldUrlData.getQuery());
        }
        if (request.isSkipPath()) {
            //remove path from restored and get one from latest
            urlData.setPath(oldUrlData.getPath());
        }
        if (request.isSkipProtocol()) {
            //remove hash from restored and get one from latest
            urlData.setProtocol(oldUrlData.getProtocol());
        }
        if (request.isSkipServer()) {
            //remove hash from restored and get one from latest
            urlData.setAuthority(oldUrlData.getAuthority());
        }

        requestView.setUrl(urlData.toString());

        setUserDefinedContentEncodingValues(request.getEncoding(), request.getHeaders());
        RestClient.fixChromeLayout();
        Storage store = Storage.getSessionStorageIfSupported();
        store.setItem(LocalStore.RESTORED_REQUEST, "" + request.getId());
    }

    private void showProjectRelatedData(final int projectId, final ProjectObject project) {
        clientFactory.getRequestDataStore().getService().getProjectRequests(projectId,
                new ListCallback<RequestObject>() {

                    @Override
                    public void onFailure(DataServiceException error) {
                        if (RestClient.isDebug()) {
                            Log.error("Unable to find related projects.", error);
                        }
                    }

                    @Override
                    public void onSuccess(final List<RequestObject> request) {
                        if (request.size() == 0) {
                            return;
                        }
                        int _endpointId = -1;
                        if (place.isProjectsEndpoint()) {
                            try {
                                _endpointId = Integer.parseInt(place.getEntryId());
                            } catch (Exception e) {
                            }
                        }
                        final int endpointId = _endpointId;

                        if (project == null) {
                            ProjectStoreWebSql projectsStore = clientFactory.getProjectsStore();
                            projectsStore.getByKey(projectId, new StoreResultCallback<ProjectObject>() {

                                @Override
                                public void onSuccess(ProjectObject project) {
                                    requestView.setProjectData(project, request, endpointId);
                                }

                                @Override
                                public void onError(Throwable e) {
                                    if (RestClient.isDebug()) {
                                        Log.error("Unable read project data.", e);
                                    }
                                    StatusNotification.notify("Unable read project related data",
                                            StatusNotification.TYPE_ERROR);
                                }
                            });
                        } else {
                            requestView.setProjectData(project, request, endpointId);
                        }
                    }
                });
    }

    /**
     * Register event handlers from system's event bus to handle relevant data.
     * Registered events:
     *  - Request start 
     *  - Request end
     *  - 
     */
    private void observeEvents() {

        //When request starts disable UI controls
        RequestStartActionEvent.register(eventBus, new RequestStartActionEvent.Handler() {
            @Override
            public void onStart(Date time) {
                requestView.handleRequestStartActionEvent(time);
                GoogleAnalytics.sendEvent("Engagement", "Click", "Request start");
                GoogleAnalyticsApp.sendEvent("Engagement", "Click", "Request start");
            }
        });

        OverwriteUrlEvent.register(eventBus, new OverwriteUrlEvent.Handler() {
            @Override
            public void onUrlChange(String url) {
                requestView.setUrl(url);
            }
        });

        RequestChangeEvent.register(eventBus, new RequestChangeEvent.Handler() {
            @Override
            public void onChange(RequestChangeEvent event) {
                requestView.handleRequestChangeEvent(event);
            }
        });

        RequestEndEvent.register(eventBus, new RequestEndEvent.Handler() {
            @Override
            public void onResponse(boolean success, final Response response, long requestTime) {

                requestView.handleRequestEndEvent();

                if (responseView != null) {
                    responseView.asWidget().removeFromParent();
                    responseView = null;
                }

                responseView = clientFactory.getResponseView();
                viewFlowPanel.add(responseView);
                responseView.setPresenter(RequestActivity.this);
                responseView.setResponseData(success, response, requestTime);

                /**
                 * Get request and response headers data from Chrome Extensions API
                 */
                clientFactory.getChromeMessagePassing().postMessage(
                        ExternalEventsFactory.EXT_GET_COLLECTED_REQUEST_DATA, null, new BackgroundPageCallback() {
                            @Override
                            public void onSuccess(String result) {
                                if (result == null) {
                                    responseView.setRequestHeadersExternal(null);
                                    responseView.setResponseHeadersExternal(null);
                                    responseView.scrollToView();
                                    return;
                                }
                                JSONObject parsedResponse = null;
                                try {
                                    parsedResponse = JSONParser.parseStrict(result).isObject();
                                } catch (Exception e) {
                                    responseView.setRequestHeadersExternal(null);
                                    responseView.setResponseHeadersExternal(null);
                                    responseView.scrollToView();
                                    return;
                                }

                                responseView.setRequestHeadersExternal(
                                        extractHeadersExternal(parsedResponse, "REQUEST_HEADERS"));
                                responseView.setResponseHeadersExternal(
                                        extractHeadersExternal(parsedResponse, "RESPONSE_HEADERS"));

                                //look for redirections
                                JSONValue redirectValue = parsedResponse.get("REDIRECT_DATA");
                                if (redirectValue != null) {
                                    ArrayList<RedirectData> redirects = getRedirectData(redirectValue.isArray());
                                    if (redirects != null && redirects.size() > 0) {
                                        responseView.setRedirectData(redirects);
                                    }
                                }

                                responseView.scrollToView();
                            }

                            @Override
                            public void onError(String message) {
                                if (RestClient.isDebug()) {
                                    Log.error("Unknown error occured: " + message);
                                }
                            }
                        });
            }
        });

        ProjectChangeRequestEvent.register(eventBus, new ProjectChangeRequestEvent.Handler() {
            @Override
            public void onProjectChange(final ProjectObject project) {
                if (project == null) {
                    return;
                }
                ProjectStoreWebSql store = clientFactory.getProjectsStore();
                store.put(project, project.getId(), new StoreResultCallback<Integer>() {

                    @Override
                    public void onSuccess(Integer result) {
                        ProjectChangeEvent ev = new ProjectChangeEvent(project);
                        eventBus.fireEvent(ev);

                        if (RestClient.currentlyOpenedProject == project.getId()) {
                            requestView.updateProjectMetadata(project);
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        if (RestClient.isDebug()) {
                            Log.error("Unable to update project data", e);
                        }
                        StatusNotification.notify("Unable to update project data", StatusNotification.TYPE_ERROR,
                                StatusNotification.TIME_SHORT);
                    }
                });
            }
        });
        ProjectDeleteRequestEvent.register(eventBus, new ProjectDeleteRequestEvent.Handler() {

            @Override
            public void onProjectDelete(final int projectId) {
                ProjectStoreWebSql projectStore = clientFactory.getProjectsStore();
                projectStore.remove(projectId, new StoreResultCallback<Boolean>() {

                    @Override
                    public void onSuccess(Boolean result) {
                        if (!result.booleanValue()) {
                            if (RestClient.isDebug()) {
                                Log.error("Unable to delete project data");
                            }
                            StatusNotification.notify("Unable to delete project data",
                                    StatusNotification.TYPE_ERROR, StatusNotification.TIME_SHORT);
                            return;
                        }

                        RequestDataStoreWebSql requestsStore = clientFactory.getRequestDataStore();
                        requestsStore.getService().deleteFromProject(projectId, new VoidCallback() {

                            @Override
                            public void onFailure(DataServiceException error) {
                                if (RestClient.isDebug()) {
                                    Log.error("Unable to delete project related  data", error);
                                }
                                ProjectDeleteEvent ev = new ProjectDeleteEvent(projectId);
                                eventBus.fireEvent(ev);
                                goTo(new RequestPlace(null));
                            }

                            @Override
                            public void onSuccess() {
                                ProjectDeleteEvent ev = new ProjectDeleteEvent(projectId);
                                eventBus.fireEvent(ev);
                                goTo(new RequestPlace(null));
                            }
                        });

                    }

                    @Override
                    public void onError(Throwable e) {
                        if (RestClient.isDebug()) {
                            Log.error("Unable to delete project data", e);
                        }
                        StatusNotification.notify("Unable to delete project data", StatusNotification.TYPE_ERROR,
                                StatusNotification.TIME_SHORT);
                    }
                });
            }
        });
    }

    private ArrayList<RedirectData> getRedirectData(JSONArray response) {
        ArrayList<RedirectData> result = new ArrayList<RedirectData>();
        if (response == null) {
            return result;
        }
        int size = response.size();
        for (int i = 0; i < size; i++) {
            JSONValue itemValue = response.get(i);
            JSONObject item = itemValue.isObject();
            if (item == null)
                continue;

            boolean fromCache = item.get("fromCache").isBoolean().booleanValue();
            String redirectUrl = item.get("redirectUrl").isString().stringValue();

            String statusLine = null;
            JSONValue statusLineValue = item.get("statusLine");
            if (statusLineValue != null) {
                statusLine = item.get("statusLine").isString().stringValue();
            }
            int statusCode = Integer.parseInt(item.get("statusCode").isNumber().toString());
            ArrayList<Header> headers = extractHeadersExternal(item, "responseHeaders");
            RedirectData redirect = new RedirectData();
            redirect.setRedirectUrl(redirectUrl);
            redirect.setFromCache(fromCache);
            redirect.setResponseHeaders(headers);
            redirect.setStatusCode(statusCode);
            if (statusLine != null)
                redirect.setStatusLine(statusLine);
            result.add(redirect);
        }
        return result;
    }

    private ArrayList<Header> extractHeadersExternal(JSONObject response, String key) {
        ArrayList<Header> headers = new ArrayList<Header>();
        JSONValue valuesValue = response.get(key);
        if (valuesValue == null) {
            return headers;
        }
        JSONArray arr = valuesValue.isArray();
        if (arr == null) {
            return headers;
        }
        int len = arr.size();
        for (int i = 0; i < len; i++) {
            JSONValue item = arr.get(i);
            final String name = item.isObject().get("name").isString().stringValue();
            final String value = item.isObject().get("value").isString().stringValue();
            Header header = new Header() {
                @Override
                public String getName() {
                    return name;
                }

                @Override
                public String getValue() {
                    return value;
                }

                @Override
                public String toString() {
                    return name + " : " + value;
                }
            };
            headers.add(header);
        }
        return headers;
    }

    /**
     * Restore request from history DB
     * @param historyId
     * @param requestView
     */
    private void restoreRequestFromHistory(int historyId) {
        RestClient.getClientFactory().getHistoryRequestStore().getByKey(historyId,
                new StoreResultCallback<HistoryObject>() {

                    @Override
                    public void onSuccess(HistoryObject result) {
                        requestView.setUrl(result.getURL());
                        requestView.setMethod(result.getMethod());
                        requestView.setHeaders(result.getHeaders());
                        requestView.setPayload(result.getPayload());
                        setUserDefinedContentEncodingValues(result.getEncoding(), result.getHeaders());

                        Date date = new Date((long) result.getTime());
                        String lastUseDate = DateTimeFormat.getFormat(PredefinedFormat.DATE_TIME_FULL).format(date);
                        requestView.setRequestName("Last used: " + lastUseDate);
                        RestClient.fixChromeLayout();
                    }

                    @Override
                    public void onError(Throwable e) {
                        if (RestClient.isDebug()) {
                            Log.error("Unable read history data", e);
                        }
                        StatusNotification.notify("Unable read history data", StatusNotification.TYPE_ERROR);
                    }
                });
    }

    private void createExternalRequest(final String requestUUID) {
        clientFactory.getChromeMessagePassing().postMessage(ExternalEventsFactory.EXT_GET_EXTERNAL_REQUEST_DATA,
                requestUUID, new BackgroundPageCallback() {
                    @Override
                    public void onSuccess(String result) {
                        if (result.isEmpty()) {
                            StatusNotification.notify("Data from external extension is no longer available :(",
                                    StatusNotification.TYPE_CRITICAL, StatusNotification.TIME_MEDIUM);
                            return;
                        }
                        JSONValue parsedValue = null;
                        try {
                            parsedValue = JSONParser.parseStrict(result);
                        } catch (Exception e) {
                        }
                        if (parsedValue == null) {
                            Log.error("Malformed External Data Exception. Passed data: " + result);
                            StatusNotification.notify("Unable to read data from external extension :(",
                                    StatusNotification.TYPE_CRITICAL, StatusNotification.TIME_MEDIUM);
                            return;
                        }
                        JSONObject obj = parsedValue.isObject();
                        if (obj.containsKey("error")) {
                            if (obj.get("error").isBoolean().booleanValue()) {
                                Log.error("Error get External Data. Message: "
                                        + obj.get("message").isString().stringValue());
                                StatusNotification.notify(obj.get("message").isString().stringValue(),
                                        StatusNotification.TYPE_CRITICAL, StatusNotification.TIME_MEDIUM);
                                return;
                            }
                        }
                        if (obj.containsKey("data")) {
                            JSONObject dataObj = obj.get("data").isObject();
                            if (dataObj.containsKey("url")) {
                                requestView.setUrl(dataObj.get("url").isString().stringValue());
                            }
                            if (dataObj.containsKey("method")) {
                                requestView.setMethod(dataObj.get("method").isString().stringValue());
                            }
                            if (dataObj.containsKey("headers")) {
                                requestView.setHeaders(dataObj.get("headers").isString().stringValue());
                            }
                            if (dataObj.containsKey("payload")) {
                                requestView.setPayload(dataObj.get("payload").isString().stringValue());
                            }
                            if (dataObj.containsKey("encoding")) {
                                requestView.setEncoding(dataObj.get("encoding").isString().stringValue());
                            }
                        }
                        RestClient.fixChromeLayout();
                    }

                    @Override
                    public void onError(String message) {
                        if (RestClient.isDebug()) {
                            Log.error("Unknown error occured: " + message);
                        }
                    }
                });

    }

    private void restoreFormSavedRequest(final int savedId) {
        clientFactory.getRequestDataStore().getByKey(savedId, new StoreResultCallback<RequestObject>() {

            @Override
            public void onSuccess(RequestObject result) {

                Storage store = Storage.getSessionStorageIfSupported();
                store.setItem(LocalStore.RESTORED_REQUEST, "" + savedId);
                setViewParameters(result);

            }

            @Override
            public void onError(Throwable e) {
                Log.error("Unable read stored data :(", e);
                StatusNotification.notify("Unable read stored data :(", StatusNotification.TYPE_CRITICAL,
                        StatusNotification.TIME_MEDIUM);
            }
        });
    }

    /**
     * Restore latest, not saved request
     * @param view
     */
    private void restoreLatestRequest() {
        RequestObject.restoreLatest(new Callback<RequestObject, Throwable>() {
            @Override
            public void onSuccess(RequestObject result) {
                setViewParameters(result);
            }

            @Override
            public void onFailure(Throwable caught) {
            }
        });
    }

    /**
     * 
     * @param selectCurrentEncoding
     * @param headers
     */
    private void setUserDefinedContentEncodingValues(String _selectCurrentEncoding, String headers) {

        if (headers != null) {
            ArrayList<RequestHeader> requerstHeadersList = RequestHeadersParser.stringToHeaders(headers);
            for (RequestHeader h : requerstHeadersList) {
                if (h.getName().toLowerCase().equals("content-type")) {
                    _selectCurrentEncoding = h.getValue();
                }
            }
        }

        final String selectCurrentEncoding = _selectCurrentEncoding;
        clientFactory.getFormEncodingStore().all(new StoreResultCallback<Map<Integer, FormEncodingObject>>() {

            @Override
            public void onSuccess(Map<Integer, FormEncodingObject> result) {
                final RequestView view = clientFactory.getRequestView();
                String encodingToSelect = selectCurrentEncoding;

                if (selectCurrentEncoding == null) {
                    encodingToSelect = view.getEncoding();
                }

                String[] values = new String[result.size()];
                Set<Integer> keys = result.keySet();
                int i = 0;
                for (Integer k : keys) {
                    FormEncodingObject dbvalue = result.get(k);
                    if (dbvalue != null)
                        values[i] = dbvalue.getEncoding();
                    i++;
                }
                view.appendEncodingValues(values);
                view.setEncoding(encodingToSelect);
            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
                Log.error("getFormEncodingsStore.all in RequestActivity", e);
            }
        });
    }

    @Override
    public String mayStop() {

        //      Storage store = Storage.getSessionStorageIfSupported();
        //      String restored = store.getItem(LocalStore.RESTORED_REQUEST);
        //      if(restored != null && !restored.isEmpty()){
        //TODO: check if something is changed, if it is changed set warning.  
        //      }

        revokeDownloadData();
        if (tutorialFactory != null) {
            tutorialFactory.clear();
        }

        RequestObject ro = RequestObject.createRequest();
        ro.setEncoding(requestView.getEncoding());
        ro.setHeaders(requestView.getHeaders());
        ro.setMethod(requestView.getMethod());
        ro.setPayload(requestView.getPayload());
        ro.setURL(requestView.getUrl());
        ro.setName(requestView.getRequestName());
        ro.setProject(RestClient.currentlyOpenedProject);
        Storage store = Storage.getSessionStorageIfSupported();
        String gDriveFileId = store.getItem(LocalStore.CURRENT_GOOGLE_DRIVE_ITEM);
        String restoredRequestId = store.getItem(LocalStore.RESTORED_REQUEST);
        if (restoredRequestId != null) {
            try {
                int savedId = Integer.parseInt(restoredRequestId);
                ro.setId(savedId);
            } catch (Exception e) {
            }
        }

        if (gDriveFileId != null && !gDriveFileId.isEmpty()) {
            ro.setGDriveId(gDriveFileId);
        }
        this.clientFactory.getLocalStore().put(ro.toJSON(), LocalStore.LATEST_REQUEST_KEY,
                new StoreResultCallback<String>() {
                    @Override
                    public void onSuccess(String result) {
                    }

                    @Override
                    public void onError(Throwable e) {
                    }
                });

        return null;
    }

    private static HandlerRegistration addDialogRegistrtion = null;

    @Override
    public void requestAddEncodingDialog(final String previousEncoding) {
        AddEncodingView dialog = clientFactory.getAddEncodingView(eventBus);
        dialog.show();

        final RequestView view = this.clientFactory.getRequestView();

        final AddEncodingEvent.Handler handler = new AddEncodingEvent.Handler() {
            @Override
            public void onAddEncoding(final String encoding) {
                addDialogRegistrtion.removeHandler();
                if (encoding == null || encoding.isEmpty()) {
                    view.setEncoding(previousEncoding);
                } else {
                    FormEncodingObject feo = FormEncodingObject.create();
                    feo.setEncoding(encoding);
                    clientFactory.getFormEncodingStore().put(feo, null, new StoreResultCallback<Integer>() {
                        @Override
                        public void onSuccess(Integer result) {
                            setUserDefinedContentEncodingValues(encoding, null);
                        }

                        @Override
                        public void onError(Throwable e) {
                            e.printStackTrace();
                            if (RestClient.isDebug()) {
                                Log.error(
                                        "RequestActivity::requestAddEncodingDialog->AddEncodingEvent.Handler->store::put",
                                        e);
                            }
                            view.setEncoding(previousEncoding);
                        }
                    });
                }

                addDialogRegistrtion = null;
            }
        };

        addDialogRegistrtion = AddEncodingEvent.register(eventBus, handler);
    }

    @Override
    public void fireClearAllEvent() {

        RestClient.previouslyOpenedProject = RestClient.currentlyOpenedProject;
        RestClient.currentlyOpenedProject = -1;
        Storage store = Storage.getLocalStorageIfSupported();
        store.removeItem(LocalStore.LATEST_REQUEST_KEY);

        Storage sessionStore = Storage.getSessionStorageIfSupported();
        sessionStore.removeItem(LocalStore.RESTORED_REQUEST);
        sessionStore.removeItem(LocalStore.CURRENT_GOOGLE_DRIVE_ITEM);

        eventBus.fireEvent(new ClearFormEvent());

        goTo(new RequestPlace("default"));
        GoogleAnalytics.sendEvent("Engagement", "Click", "Clear request form");
    }

    @Override
    public void getResponseHeadersInfo(ArrayList<String> names,
            final Callback<List<HeaderRow>, Throwable> callback) {

        clientFactory.getHeadersStore().getResponseHeadersByName(names, new StoreResultCallback<List<HeaderRow>>() {

            @Override
            public void onSuccess(List<HeaderRow> result) {
                callback.onSuccess(result);
            }

            @Override
            public void onError(Throwable e) {
                callback.onFailure(e);
            }
        });
    }

    @Override
    public void getRequestHeadersInfo(ArrayList<String> names,
            final Callback<List<HeaderRow>, Throwable> callback) {
        clientFactory.getHeadersStore().getRequestHeadersByName(names, new StoreResultCallback<List<HeaderRow>>() {

            @Override
            public void onSuccess(List<HeaderRow> result) {
                callback.onSuccess(result);
            }

            @Override
            public void onError(Throwable e) {
                callback.onFailure(e);
            }
        });
    }

    private String exportFileObjectUrl = null;

    @Override
    public String createDownloadData(String body, String endoding) {
        if (exportFileObjectUrl != null) {
            revokeDownloadData();
        }
        exportFileObjectUrl = createDownloadDataImpl(body, endoding);
        return exportFileObjectUrl;
    }

    private final native String createDownloadDataImpl(String data, String endoding) /*-{
                                                                                     var blob = new $wnd.Blob([data], {type: endoding});
                                                                                     return $wnd.URL.createObjectURL(blob);
                                                                                     }-*/;

    @Override
    public void revokeDownloadData() {
        if (exportFileObjectUrl != null) {
            revokeDownloadDataImpl(exportFileObjectUrl);
            exportFileObjectUrl = null;
        }
    }

    private final native void revokeDownloadDataImpl(String url) /*-{
                                                                 $wnd.URL.revokeObjectURL(url);
                                                                 }-*/;

    private void activateTutorial() {
        tutorialFactory = new TutorialFactory("request");

        if (!tutorialFactory.canStartTutorial()) {
            return;
        }
        requestView.setUpTutorial(tutorialFactory);
    }

    @Override
    public void fireEncodingChangeEvent(String newEncoding) {
        eventBus.fireEvent(new HttpEncodingChangeEvent(newEncoding));
    }

    @Override
    public void fireMethodChangeEvent(String newMethod) {
        eventBus.fireEvent(new HttpMethodChangeEvent(newMethod));
    }

    @Override
    public void fireUrlChangeEvent(String newUrl) {
        eventBus.fireEvent(new UrlValueChangeEvent(newUrl));
        requestView.handleUrlValueChangeEvent(newUrl);
    }

    @Override
    public void fireUrlToggleEvent(boolean isNowSimpleView) {
        eventBus.fireEvent(new URLFieldToggleEvent(isNowSimpleView));
        GoogleAnalytics.sendEvent(ANALYTICS_EVENT_CATEGORY, "URL widget toggle",
                isNowSimpleView ? "Single line" : "Details form");
        GoogleAnalyticsApp.sendEvent(ANALYTICS_EVENT_CATEGORY, "URL widget toggle",
                isNowSimpleView ? "Single line" : "Details form");
    }

    @Override
    public void fireRequestStartActionEvent(Date startTime) {
        eventBus.fireEvent(new RequestStartActionEvent(startTime));
    }

    @Override
    public void deleteCurrentEndpoint() {
        String _entryId = place.getEntryId();
        final int entryId = Integer.parseInt(_entryId);
        if (place.isProjectsEndpoint()) {
            try {
                clientFactory.getRequestDataStore().remove(entryId, new StoreResultCallback<Boolean>() {

                    @Override
                    public void onSuccess(Boolean result) {
                        if (result.booleanValue()) {
                            goTo(RequestPlace.Tokenizer.fromProjectDefault(RestClient.currentlyOpenedProject));
                        } else {
                            if (RestClient.isDebug()) {
                                Log.error("Unable delete endpoint. Unknown error.");
                            }
                            StatusNotification.notify("Unable delete endpoint. Unknown error.",
                                    StatusNotification.TYPE_ERROR, StatusNotification.TIME_SHORT);
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        if (RestClient.isDebug()) {
                            Log.error("Unable delete endpoint ", e);
                        }
                        StatusNotification.notify("Unable delete endpoint", StatusNotification.TYPE_ERROR,
                                StatusNotification.TIME_SHORT);
                    }
                });

            } catch (Exception e) {
                if (RestClient.isDebug()) {
                    Log.error("Unable read project's endpoint ID", e);
                }
                StatusNotification.notify("Unable read project data", StatusNotification.TYPE_ERROR,
                        StatusNotification.TIME_SHORT);
            }
        } else if (place.isProject()) {
            clientFactory.getRequestDataStore().getService().getProjectDefaultRequests(entryId,
                    new ListCallback<RequestObject>() {

                        @Override
                        public void onFailure(DataServiceException error) {
                            if (RestClient.isDebug()) {
                                Log.error("Can't find selected endpoint.", error);
                            }
                            StatusNotification.notify("Can't find selected endpoint.",
                                    StatusNotification.TYPE_ERROR);
                        }

                        @Override
                        public void onSuccess(List<RequestObject> result) {
                            if (result == null || result.size() == 0) {
                                if (RestClient.isDebug()) {
                                    Log.error("Can't find selected endpoint. No database entries.");
                                }
                                StatusNotification.notify("Can't find selected endpoint. No database entries.",
                                        StatusNotification.TYPE_ERROR);
                                return;
                            }

                            clientFactory.getRequestDataStore().remove(result.get(0).getId(),
                                    new StoreResultCallback<Boolean>() {

                                        @Override
                                        public void onSuccess(Boolean result) {
                                            if (result.booleanValue()) {
                                                goTo(RequestPlace.Tokenizer
                                                        .fromProjectDefault(RestClient.currentlyOpenedProject));
                                            } else {
                                                if (RestClient.isDebug()) {
                                                    Log.error("Unable delete endpoint. Unknown error.");
                                                }
                                                StatusNotification.notify("Unable delete endpoint. Unknown error.",
                                                        StatusNotification.TYPE_ERROR,
                                                        StatusNotification.TIME_SHORT);
                                            }
                                        }

                                        @Override
                                        public void onError(Throwable e) {
                                            if (RestClient.isDebug()) {
                                                Log.error("Unable delete endpoint ", e);
                                            }
                                            StatusNotification.notify("Unable delete endpoint",
                                                    StatusNotification.TYPE_ERROR, StatusNotification.TIME_SHORT);
                                        }
                                    });
                        }
                    });
        }
    }

    @Override
    public EditProjectView getEditProjectDialog() {
        return clientFactory.getEditProjectView();
    }

    private void setViewParameters(RequestObject result) {
        if (result == null) {
            requestView.setUrl(null);
            requestView.setMethod(null);
            requestView.setHeaders(null);
            requestView.setPayload(null);
            requestView.setEncoding(null);
            requestView.setRequestName(null);
            return;
        }

        if (result.getGDriveId() != null) {
            //         Google Drive item
            //         goTo(RequestPlace.Tokenizer.fromDriveFile(result.getGDriveId()));
            //         return;
            Storage store = Storage.getSessionStorageIfSupported();
            store.setItem(LocalStore.CURRENT_GOOGLE_DRIVE_ITEM, result.getGDriveId());
            requestView.setGDriveConstrols();
        }

        if (result.getId() > 0) {
            Storage store = Storage.getSessionStorageIfSupported();
            store.setItem(LocalStore.RESTORED_REQUEST, "" + result.getId());
        }

        if (result.getProject() > 0) {
            showProjectRelatedData(result.getProject(), null);
            RestClient.currentlyOpenedProject = result.getProject();
        } else {
            //if name is available, set name
            requestView.setRequestName(result.getName());
            if (result.getId() > 0) {
                clientFactory.getRequestDataStore().getByKey(result.getId(),
                        new StoreResultCallback<RequestObject>() {

                            @Override
                            public void onSuccess(RequestObject result) {
                                if (result == null) {
                                    return;
                                }
                                requestView.setRequestName(result.getName());
                            }

                            @Override
                            public void onError(Throwable e) {
                            }
                        });
            }
        }

        requestView.setUrl(result.getURL());
        requestView.setMethod(result.getMethod());
        requestView.setHeaders(result.getHeaders());
        requestView.setPayload(result.getPayload());
        setUserDefinedContentEncodingValues(result.getEncoding(), result.getHeaders());
        RestClient.fixChromeLayout();
    }

    @Override
    public void refreshCurrentDriveItem() {
        Storage store = Storage.getSessionStorageIfSupported();
        String entryId = store.getItem(LocalStore.CURRENT_GOOGLE_DRIVE_ITEM);
        if (entryId == null || entryId.isEmpty()) {
            if (RestClient.isDebug()) {
                Log.debug("Not a Google Drive item.");
            }
            return;
        }
        fromGoogleDriveFile(entryId);
    }

    @Override
    public void changeSavedName(final String name, final Callback<Boolean, Throwable> callback) {
        final Storage store = Storage.getSessionStorageIfSupported();

        if (place.isGdrive() || place.isProject() || place.isProjectsEndpoint()) {
            callback.onSuccess(false);
            return;
        }
        String restored = store.getItem(LocalStore.RESTORED_REQUEST);
        if (restored != null && !restored.isEmpty()) {
            int savedId = -1;
            try {
                savedId = Integer.parseInt(restored);
            } catch (Exception e) {
                if (RestClient.isDebug()) {
                    Log.debug("Unable to change request name", e);
                }
                callback.onFailure(e);
                return;
            }

            clientFactory.getRequestDataStore().getService().updateName(name, savedId, new VoidCallback() {
                @Override
                public void onFailure(DataServiceException error) {
                    if (RestClient.isDebug()) {
                        Log.error("Unable to change name :(", error);
                    }
                    StatusNotification.notify("Unable to change name :(", StatusNotification.TYPE_ERROR,
                            StatusNotification.TIME_SHORT);
                    callback.onFailure(error);
                }

                @Override
                public void onSuccess() {
                    callback.onSuccess(true);
                }
            });

            return;
        }

        RestClient.collectRequestData(new Callback<RequestObject, Throwable>() {

            @Override
            public void onSuccess(final RequestObject result) {
                result.setName(name);
                RestClient.saveRequestData(result, new Callback<RequestObject, Throwable>() {
                    @Override
                    public void onSuccess(RequestObject result) {
                        store.setItem(LocalStore.RESTORED_REQUEST, "" + result.getId());
                        callback.onSuccess(true);
                    }

                    @Override
                    public void onFailure(Throwable reason) {
                        StatusNotification.notify("Unable to save request data!", StatusNotification.TYPE_ERROR,
                                StatusNotification.TIME_MEDIUM);
                        callback.onFailure(reason);
                    }
                });
            }

            @Override
            public void onFailure(Throwable reason) {
                if (RestClient.isDebug()) {
                    Log.error("Unable to save request data. Can't collect current request data.", reason);
                }
                StatusNotification.notify("Unable to save request data!", StatusNotification.TYPE_ERROR,
                        StatusNotification.TIME_MEDIUM);
                callback.onFailure(reason);
            }
        });

    }

    @Override
    public void urlContextMenuOpenedAction() {
        GoogleAnalytics.sendEvent(ANALYTICS_EVENT_CATEGORY, "URL widget context menu", "Open menu");
        GoogleAnalyticsApp.sendEvent(ANALYTICS_EVENT_CATEGORY, "URL widget toggle", "Open menu");
    }

    @Override
    public void urlContextMenuActionPerformed(String actionName) {
        GoogleAnalytics.sendEvent(ANALYTICS_EVENT_CATEGORY, "URL widget context menu action", actionName);
        GoogleAnalyticsApp.sendEvent(ANALYTICS_EVENT_CATEGORY, "URL widget toggle action", actionName);
    }

}