com.rapid.actions.Mobile.java Source code

Java tutorial

Introduction

Here is the source code for com.rapid.actions.Mobile.java

Source

/*
    
Copyright (C) 2015 - Gareth Edwards / Rapid Information Systems
    
gareth.edwards@rapid-is.co.uk
    
    
This file is part of the Rapid Application Platform
    
Rapid is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as 
published by the Free Software Foundation, either version 3 of the 
License, or (at your option) any later version. The terms require you 
to include the original copyright, and the license notice in all redistributions.
    
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.
    
You should have received a copy of the GNU Affero General Public License
in a file named "COPYING".  If not, see <http://www.gnu.org/licenses/>.
    
*/

package com.rapid.actions;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletContext;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.rapid.core.Action;
import com.rapid.core.Application;
import com.rapid.core.Control;
import com.rapid.core.Page;
import com.rapid.server.RapidHttpServlet;
import com.rapid.server.RapidRequest;

public class Mobile extends Action {

    // private instance variables
    private ArrayList<Action> _successActions, _errorActions, _onlineActions, _childActions;

    // properties
    public ArrayList<Action> getSuccessActions() {
        return _successActions;
    }

    public void setSuccessActions(ArrayList<Action> successActions) {
        _successActions = successActions;
    }

    public ArrayList<Action> getErrorActions() {
        return _errorActions;
    }

    public void setErrorActions(ArrayList<Action> errorActions) {
        _errorActions = errorActions;
    }

    public ArrayList<Action> getOnlineActions() {
        return _onlineActions;
    }

    public void setOnlineActions(ArrayList<Action> onlineActions) {
        _onlineActions = onlineActions;
    }

    // constructors

    // used by jaxb
    public Mobile() {
        super();
    }

    // used by designer
    public Mobile(RapidHttpServlet rapidServlet, JSONObject jsonAction) throws Exception {
        this();
        // save all key/values from the json into the properties 
        for (String key : JSONObject.getNames(jsonAction)) {
            // add all json properties to our properties, except for success and error actions
            if (!"successActions".equals(key) && !"errorActions".equals(key) && !"onlineActions".equals(key))
                addProperty(key, jsonAction.get(key).toString());
        }

        // upload images was modified to have a number of gallery ids (rather than 1) migrate for old versions
        String type = getProperty("actionType");
        // if this is upload images
        if ("uploadImages".equals(type)) {
            // get any single gallery controlId
            String galleryControlId = getProperty("galleryControlId");
            // if not null
            if (galleryControlId != null) {
                // empty the property
                _properties.remove("galleryControlId");
                // move it into the galleryControlIds
                _properties.put("galleryControlIds", "[\"" + galleryControlId + "\"]");
            }
        }

        // grab any successActions
        JSONArray jsonSuccessActions = jsonAction.optJSONArray("successActions");
        // if we had some
        if (jsonSuccessActions != null) {
            _successActions = Control.getActions(rapidServlet, jsonSuccessActions);
        }

        // grab any errorActions
        JSONArray jsonErrorActions = jsonAction.optJSONArray("errorActions");
        // if we had some
        if (jsonErrorActions != null) {
            // instantiate our contols collection
            _errorActions = Control.getActions(rapidServlet, jsonErrorActions);
        }

        // grab any onlineActions
        JSONArray jsonOnlineActions = jsonAction.optJSONArray("onlineActions");
        // if we had some
        if (jsonOnlineActions != null) {
            // instantiate our contols collection
            _onlineActions = Control.getActions(rapidServlet, jsonOnlineActions);
        }
    }

    // overridden methods

    @Override
    public List<Action> getChildActions() {
        // initialise and populate on first get
        if (_childActions == null) {
            // our list of all child actions
            _childActions = new ArrayList<Action>();
            // add child success actions
            if (_successActions != null) {
                for (Action action : _successActions)
                    _childActions.add(action);
            }
            // add child error actions
            if (_errorActions != null) {
                for (Action action : _errorActions)
                    _childActions.add(action);
            }
            // add child online actions
            if (_onlineActions != null) {
                for (Action action : _onlineActions)
                    _childActions.add(action);
            }
        }
        return _childActions;
    }

    @Override
    public String getPageJavaScript(RapidRequest rapidRequest, Application application, Page page,
            JSONObject jsonDetails) throws Exception {
        // refrence to these success and fail actions are sent as callbacks to the on-mobile device file upload function
        if (_successActions == null && _errorActions == null) {
            return null;
        } else {
            String js = "";
            // get our id
            String id = getId();
            // get the control (the slow way)
            Control control = page.getActionControl(id);
            // check if we have any success actions
            if (_successActions != null) {
                js += "function " + id + "success(ev) {\n";
                for (Action action : _successActions) {
                    js += "  " + action.getJavaScript(rapidRequest, application, page, control, jsonDetails).trim()
                            .replace("\n", "\n  ") + "\n";
                }
                js += "}\n";
            }
            // check if we have any success actions
            if (_errorActions != null) {
                js += "function " + id + "error(ev, server, status, message) {\n";
                for (Action action : _errorActions) {
                    js += "  " + action.getJavaScript(rapidRequest, application, page, control, jsonDetails).trim()
                            .replace("\n", "\n  ") + "\n";
                }
                js += "}\n";
            }
            return js;
        }

    }

    // a re-usable function to check whether we are on a mobile device - this is used selectively according to the type and whether the alert should appear or we can silently ignore
    private String getMobileCheck(boolean alert) {
        // check that rapidmobile is available
        String js = "if (typeof _rapidmobile == 'undefined') {\n";
        // check we have errorActions
        if (_errorActions == null) {
            if (alert)
                js += "  alert('This action is only available in Rapid Mobile');\n";
        } else {
            js += "  " + getId() + "error(ev, {}, 1, 'This action is only available in Rapid Mobile');\n";
        }
        js += "} else {\n";
        return js;
    }

    // this function is used where an alternative exists that would not require an error message
    private String getMobileCheckAlternative() {
        // check that rapidmobile is available
        String js = "if (typeof _rapidmobile != 'undefined') {\n";
        // return
        return js;
    }

    // a re-usable function for printing the details of the outputs
    private String getOutputs(RapidHttpServlet rapidServlet, Application application, Page page, String outputsJSON)
            throws JSONException {

        // start the outputs string
        String outputsString = "";

        // read into json Array
        JSONArray jsonOutputs = new JSONArray(outputsJSON);

        // loop
        for (int i = 0; i < jsonOutputs.length(); i++) {

            // get the gps desintation
            JSONObject jsonGpsDestination = jsonOutputs.getJSONObject(i);

            // get the itemId
            String itemId = jsonGpsDestination.getString("itemId");
            // split by escaped .
            String idParts[] = itemId.split("\\.");
            // if there is more than 1 part we are dealing with set properties, for now just update the destintation id
            if (idParts.length > 1)
                itemId = idParts[0];

            // get the field
            String field = jsonGpsDestination.optString("field", "");

            // first try and look for the control in the page
            Control destinationControl = page.getControl(itemId);
            // assume we found it
            boolean pageControl = true;
            // check we got a control
            if (destinationControl == null) {
                // now look for the control in the application
                destinationControl = application.getControl(rapidServlet.getServletContext(), itemId);
                // set page control to false
                pageControl = false;
            }

            // check we got one from either location
            if (destinationControl != null) {

                // get any details we may have
                String details = destinationControl.getDetailsJavaScript(application, page);

                // if we have some details
                if (details != null) {
                    // if this is a page control
                    if (pageControl) {
                        // the details will already be in the page so we can use the short form
                        details = destinationControl.getId() + "details";
                    }
                }

                // if the idParts is greater then 1 this is a set property
                if (idParts.length > 1) {

                    // get the property from the second id part
                    String property = idParts[1];

                    // make the getGps call to the bridge
                    outputsString += "{f:'setProperty_" + destinationControl.getType() + "_" + property + "',id:'"
                            + itemId + "',field:'" + field + "',details:'" + details + "'}";

                } else {

                    outputsString += "{f:'setData_" + destinationControl.getType() + "',id:'" + itemId + "',field:'"
                            + field + "',details:'" + details + "'}";

                } // copy / set property check

                // add a comma if more are to come
                if (i < jsonOutputs.length() - 1)
                    outputsString += ", ";

            } // destination control check   

        } // destination loop

        // return
        return outputsString;

    }

    // a helper method to check controls exist
    private boolean checkControl(ServletContext servletContext, Application application, Page page,
            String controlId) {
        // assume control not found
        boolean controlFound = false;
        // check we got a control id
        if (controlId != null) {
            // if i starts with System
            if (controlId.startsWith("System.")) {
                // we're ok
                controlFound = true;
            } else {
                // look for the control
                if (Control.getControl(servletContext, application, page, controlId) != null)
                    controlFound = true;
            }
        }
        return controlFound;
    }

    @Override
    public String getJavaScript(RapidRequest rapidRequest, Application application, Page page, Control control,
            JSONObject jsonDetails) {
        // start the js
        String js = "";
        // get the servlet
        RapidHttpServlet rapidServlet = rapidRequest.getRapidServlet();
        // get the type
        String type = getProperty("actionType");
        // check we got something
        if (type != null) {

            // check the type
            if ("dial".equals(type) || "sms".equals(type)) {
                // get the number control id
                String numberControlId = getProperty("numberControlId");
                // get the control
                Control numberControl = Control.getControl(rapidServlet.getServletContext(), application, page,
                        numberControlId);
                // check we got one
                if (numberControl == null) {
                    js += "// phone number control " + numberControlId + " not found\n";
                } else {
                    // get the number field
                    String numberField = getProperty("numberField");
                    // mobile check with alert
                    js += getMobileCheck(true);
                    // get number
                    js += "  var number = " + Control.getDataJavaScript(rapidServlet.getServletContext(),
                            application, page, numberControlId, numberField) + ";\n";
                    // sms has a message too
                    if ("sms".equals(type)) {
                        // get the message control id
                        String messageControlId = getProperty("messageControlId");
                        // get the messagecontrol
                        Control messageControl = Control.getControl(rapidServlet.getServletContext(), application,
                                page, messageControlId);
                        // check we got one
                        if (messageControl == null) {
                            js += "// message control " + numberControlId + " not found\n";
                        } else {
                            // get the field
                            String messageField = getProperty("messageField");
                            // get the message
                            js += "  var message = " + Control.getDataJavaScript(rapidServlet.getServletContext(),
                                    application, page, messageControlId, messageField) + ";\n";
                            // send the message
                            js += "  _rapidmobile.openSMS(number, message);\n";
                        }
                    } else {
                        // dial number
                        js += "  _rapidmobile.openPhone(number);\n";
                    }
                    // close mobile check
                    js += "}";
                }

            } else if ("email".equals(type)) {

                // get the email control id
                String emailControlId = getProperty("emailControlId");
                // check we got one
                if (checkControl(rapidServlet.getServletContext(), application, page, emailControlId)) {
                    // get the email field
                    String emailField = getProperty("emailField");
                    // get the email
                    js += "var email = " + Control.getDataJavaScript(rapidServlet.getServletContext(), application,
                            page, emailControlId, emailField) + ";\n";
                    // get the subject js
                    String subjectGetDataJS = Control.getDataJavaScript(rapidServlet.getServletContext(),
                            application, page, getProperty("subjectControlId"), getProperty("subjectField"));
                    // add the subject js
                    js += "var subject = "
                            + (("".equals(subjectGetDataJS) || subjectGetDataJS == null) ? "''" : subjectGetDataJS)
                            + ";\n";
                    // subject safety check
                    js += "if (!subject) subject = ''\n";
                    // get the message js               
                    String messageGetDataJS = Control.getDataJavaScript(rapidServlet.getServletContext(),
                            application, page, getProperty("messageControlId"), getProperty("messageField"));
                    // get the message 
                    js += "var message = "
                            + (("".equals(messageGetDataJS) || messageGetDataJS == null) ? "''" : messageGetDataJS)
                            + ";\n";
                    // message safety check
                    js += "if (!message) message = ''\n";

                    // start the alernative mobile check
                    js += getMobileCheckAlternative();
                    // start the check for the addBarcode function
                    js += "  if (_rapidmobile.openEmail) {\n";
                    // send the message
                    js += "    _rapidmobile.openEmail(email, subject, message);\n";
                    // close the open url check
                    js += "  } else alert('Opening emails is not supported in this version of Rapid Mobile');\n";
                    // else
                    js += "} else {\n";
                    // no rapid mobile so just open in new tab
                    js += "  window.location.href = 'mailto:' + email + '?subject=' + subject + '&body=' + message;\n";
                    // close the mobile check
                    js += "}\n";

                } else {
                    js += "// email control " + emailControlId + " not found\n";
                }

            } else if ("url".equals(type)) {

                // get the url control id
                String urlControlId = getProperty("urlControlId");
                // check we got one
                if (checkControl(rapidServlet.getServletContext(), application, page, urlControlId)) {
                    // get the field
                    String urlField = getProperty("urlField");
                    // get the url
                    js += "var url = " + Control.getDataJavaScript(rapidServlet.getServletContext(), application,
                            page, urlControlId, urlField) + ";\n";
                    // start the alernative mobile check
                    js += getMobileCheckAlternative();
                    // start the check for the addBarcode function
                    js += "  if (_rapidmobile.openURL) {\n";
                    // send the message
                    js += "    _rapidmobile.openURL(url);\n";
                    // close the open url check
                    js += "  } else alert('Opening URLs is not supported in this version of Rapid Mobile');\n";
                    // else
                    js += "} else {\n";
                    // no rapid mobile so just open in new tab
                    js += "  window.open(url, '_blank');\n";
                    // close the mobile check
                    js += "}\n";
                } else {
                    js += "// url control " + urlControlId + " not found\n";
                }

            } else if ("addImage".equals(type)) {

                // get the gallery control Id
                String galleryControlId = getProperty("galleryControlId");
                // get the gallery control
                Control galleryControl = page.getControl(galleryControlId);
                // check if we got one
                if (galleryControl == null) {
                    js += "  //gallery control " + galleryControlId + " not found\n";
                } else {
                    // mobile check with alert
                    js += getMobileCheck(true);
                    int maxSize = Integer.parseInt(getProperty("imageMaxSize"));
                    int quality = Integer.parseInt(getProperty("imageQuality"));
                    js += "  _rapidmobile.addImage('" + galleryControlId + "'," + maxSize + "," + quality + ");\n";
                    // close mobile check
                    js += "}\n";
                }

            } else if ("uploadImages".equals(type)) {

                // make a list of control ids
                List<String> galleryControlIds = new ArrayList<String>();

                // get the old style gallery id
                String galleryControlIdProperty = getProperty("galleryControlId");
                // if we got one
                if (galleryControlIdProperty != null) {
                    //  add to list if it contains something
                    if (galleryControlIdProperty.trim().length() > 0)
                        galleryControlIds.add(galleryControlIdProperty);
                }

                // get the new style gallery ids
                String galleryControlIdsProperty = getProperty("galleryControlIds");
                // if we got one
                if (galleryControlIdsProperty != null) {
                    // clean it up
                    galleryControlIdsProperty = galleryControlIdsProperty.replace("\"", "").replace("[", "")
                            .replace("]", "");
                    // if anything is left
                    if (galleryControlIdsProperty.length() > 0) {
                        // split and loop
                        for (String id : galleryControlIdsProperty.split(",")) {
                            // add to collection
                            galleryControlIds.add(id);
                        }
                    }
                }

                // check if we got one
                if (galleryControlIds.size() == 0) {
                    js += "  // no galleryControls specified\n";
                } else {
                    // assume no success call back
                    String successCallback = "null";
                    // update to name of callback if we have any success actions
                    if (_successActions != null)
                        successCallback = "'" + getId() + "success'";
                    // assume no error call back
                    String errorCallback = "null";
                    // update to name of callback  if we have any error actions
                    if (_errorActions != null)
                        errorCallback = "'" + getId() + "error'";
                    // start building the js
                    js += "var urls = '';\n";
                    // get any urls from the gallery controls
                    for (String id : galleryControlIds) {
                        js += "$('#" + id
                                + "').find('img').each( function() { urls += $(this).attr('src') + ',' });\n";
                    }
                    // if we got any urls
                    js += "if (urls) { \n";
                    // mobile check with alert
                    js += "  " + getMobileCheck(true).replace("\n", "\n  ");
                    // upload the images
                    js += "  _rapidmobile.uploadImages('" + getId() + "', urls, " + successCallback + ", "
                            + errorCallback + ");\n";
                    // close rapid mobile check 
                    js += "  }\n";
                    // close urls check and proceed straight to success call back if none
                    js += "}";
                    // if there is a successCallback call it now
                    if (!"null".equals(successCallback) && successCallback.length() > 0)
                        js += " else {\n  " + successCallback.replace("'", "") + "(ev);\n}\n";
                }

            } else if ("navigate".equals(type)) {

                // get the naviagte source control id
                String navigateControlId = getProperty("navigateControlId");
                // get the control
                Control navigateControl = Control.getControl(rapidServlet.getServletContext(), application, page,
                        navigateControlId);
                // check we got one
                if (navigateControl == null) {
                    js += "// navigate to control " + navigateControlId + " not found\n";
                } else {
                    // get the navigate to field
                    String navigateField = getProperty("navigateField");
                    // get the mode
                    String navigateMode = getProperty("navigateMode");
                    // enclose if we got one
                    if (navigateMode != null)
                        navigateMode = "'" + navigateMode + "'";
                    // mobile check 
                    js += getMobileCheck(true);
                    // get the data
                    js += "  var data = " + Control.getDataJavaScript(rapidServlet.getServletContext(), application,
                            page, navigateControlId, navigateField) + ";\n";
                    // assume no search fields
                    String searchFields = getProperty("navigateSearchFields");
                    // if we got some
                    if (searchFields != null) {
                        // if there's something 
                        if (searchFields.trim().length() > 0) {
                            // build the JavaScript object
                            searchFields = "{searchFields:'" + searchFields.replace("'", "\'") + "'}";
                        } else {
                            // set to null
                            searchFields = null;
                        }
                    }
                    // get a position object
                    js += "  var pos = getMapPosition(data, 0, null, null, " + searchFields + ");\n";
                    // add js, replacing any dodgy inverted commas
                    js += "  if (pos && (pos.lat || pos.lng || pos.s)) _rapidmobile.navigateTo(pos.lat, pos.lng, pos.s, "
                            + navigateMode + ");\n";
                    // close mobile check
                    js += "}\n";
                }

            } else if ("message".equals(type)) {

                // retrieve the message
                String message = getProperty("message");
                // update to empty string if null
                if (message == null)
                    message = "";
                // mobile check with silent fail
                js += getMobileCheck(false);
                // add js, replacing any dodgy inverted commas
                js += "  _rapidmobile.showMessage('" + message.replace("'", "\\'") + "');\n";
                // close mobile check
                js += "}\n";

            } else if ("disableBackButton".equals(type)) {

                // mobile check with silent fail
                js += getMobileCheck(false);
                // add js
                js += "    _rapidmobile.disableBackButton();\n";
                // close mobile check
                js += "  }\n";

            } else if ("sendGPS".equals(type)) {

                // mobile check with alert
                js += getMobileCheck(true);

                // get whether to check if gps is enabled
                boolean checkGPS = Boolean.parseBoolean(getProperty("gpsCheck"));
                // if we had one call it
                if (checkGPS)
                    js += "  _rapidmobile.checkGPS();\n";

                // get the gps frequency into an int
                int gpsFrequency = Integer.parseInt(getProperty("gpsFrequency"));

                // get the gps destinations
                String gpsDestinationsString = getProperty("gpsDestinations");

                // if we had some
                if (gpsDestinationsString != null) {

                    try {

                        // start the getGPS string
                        String getGPSjs = "  _rapidmobile.getGPS(" + gpsFrequency + ",\"[";

                        // add the gpsDestinationsString
                        getGPSjs += getOutputs(rapidServlet, application, page, gpsDestinationsString);

                        // close the get gps string
                        getGPSjs += "]\");\n";

                        // add it into the js
                        js += getGPSjs;

                    } catch (JSONException ex) {

                        // print an error into the js instead
                        js += "  // error reading gpsDestinations : " + ex.getMessage();

                    }

                } // gps destinations check         

                // close mobile check
                js += "}\n";

            } else if ("stopGPS".equals(type)) {

                // mobile check with silent fail
                js += getMobileCheck(false);
                // call stop gps
                js += "  _rapidmobile.stopGPS();\n";
                // close mobile check
                js += "}\n";

            } else if ("online".equals(type)) {

                // check we have online actions
                if (_onlineActions != null) {
                    // check size
                    if (_onlineActions.size() > 0) {

                        try {

                            // ensure we have a details object
                            if (jsonDetails == null)
                                jsonDetails = new JSONObject();

                            // add js online check
                            js += "  if (typeof _rapidmobile == 'undefined' ? true : _rapidmobile.isOnline()) {\n";

                            // get any working / loading page
                            String workingPage = getProperty("onlineWorking");
                            // if there was one 
                            if (workingPage != null) {
                                // show working page as a dialogue
                                js += "  if (Action_navigate) Action_navigate('~?a=" + application.getId() + "&v="
                                        + application.getVersion() + "&p=" + workingPage
                                        + "&action=dialogue',true,'" + getId() + "');\n";
                                // record that we have a working page in the details
                                jsonDetails.put("workingPage", getId());
                            }

                            // get the offline dialogue
                            String offlinePage = getProperty("onlineFail");

                            // loop them (this should clean out the working and offline entries in the details)
                            for (Action action : _onlineActions) {

                                // record that we have an offline page
                                jsonDetails.put("offlinePage", offlinePage);

                                js += "  " + action
                                        .getJavaScript(rapidRequest, application, page, control, jsonDetails).trim()
                                        .replace("\n", "\n  ") + "\n";

                            }

                            // get the working details page (in case none of the actions have used it
                            workingPage = jsonDetails.optString("workingPage", null);

                            // js online check fail
                            js += "} else {\n";

                            // if we have an offline page one show it
                            if (offlinePage != null)
                                js += "  if (Action_navigate) Action_navigate('~?a=" + application.getId() + "&v="
                                        + application.getVersion() + "&p=" + offlinePage
                                        + "&action=dialogue',true,'" + getId() + "');\n";

                            // close online check
                            js += "}\n";

                        } catch (Exception ex) {
                            // print an error instead
                            js = "// failed to print action " + getId() + " JavaScript : " + ex.getMessage() + "\n";
                        }

                    } // online actions size check

                } // online actions check non-null check

            } else if ("addBarcode".equals(type)) {

                try {

                    // mobile check with fail
                    String jsBarcode = getMobileCheck(true);

                    // get the barcodeDestinations
                    String barcodeDestinations = getProperty("barcodeDestinations");

                    // start the check for the addBarcode function
                    jsBarcode += "  if (_rapidmobile.addBarcode) {\n";

                    // start the add barcode call
                    jsBarcode += "    _rapidmobile.addBarcode(\"[";

                    jsBarcode += getOutputs(rapidServlet, application, page, barcodeDestinations);

                    // call get barcode
                    jsBarcode += "]\");\n";

                    // close function check
                    jsBarcode += "  } else alert('Barcode reading is not available in this version of Rapid Mobile');\n";

                    // close mobile check
                    jsBarcode += "}\n";

                    // now safe to add back into main js
                    js += jsBarcode;

                } catch (JSONException ex) {

                    // print an error into the js instead
                    js += "  // error reading barcode : " + ex.getMessage();

                }

            } // mobile action type check

        } // mobile action type non-null check

        // return an empty string
        return js;
    }

}