net.frontlinesms.plugins.forms.FormsPluginController.java Source code

Java tutorial

Introduction

Here is the source code for net.frontlinesms.plugins.forms.FormsPluginController.java

Source

/*
 * FrontlineSMS <http://www.frontlinesms.com>
 * Copyright 2007, 2008 kiwanja
 * 
 * This file is part of FrontlineSMS.
 * 
 * FrontlineSMS is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version.
 * 
 * FrontlineSMS 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 Lesser
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with FrontlineSMS. If not, see <http://www.gnu.org/licenses/>.
 */
/*
 *GRASP(Geo-referential Real-time Acquisition Statistics Platform) Designer Tool <http://www.fabaris.it>
 * Copyright  2012 ,Fabaris s.r.l
 * This file is part of GRASP Designer Tool.  
 *  GRASP Designer Tool is free software: you can redistribute it and/or modify it
 *  under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or (at
 *  your option) any later version.  
 *  GRASP Designer Tool 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 Lesser  General Public License for more details.  
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with GRASP Designer Tool. 
 *  If not, see <http://www.gnu.org/licenses/>
 */
package net.frontlinesms.plugins.forms;

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.JOptionPane;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import net.frontlinesms.AppProperties;
import net.frontlinesms.FrontlineSMS;
import net.frontlinesms.data.domain.Contact;
import net.frontlinesms.data.domain.FrontlineMessage;
import net.frontlinesms.data.domain.Group;
import net.frontlinesms.data.repository.ContactDao;
import net.frontlinesms.data.repository.GroupMembershipDao;
import net.frontlinesms.data.repository.UserDao;
import net.frontlinesms.listener.IncomingMessageListener;
import net.frontlinesms.plugins.BasePluginController;
import net.frontlinesms.plugins.PluginController;
import net.frontlinesms.plugins.PluginControllerProperties;
import net.frontlinesms.plugins.PluginInitialisationException;
import net.frontlinesms.plugins.forms.data.FormHandlingException;
import net.frontlinesms.plugins.forms.data.domain.Form;
import net.frontlinesms.plugins.forms.data.domain.FormField;
import net.frontlinesms.plugins.forms.data.domain.FormFieldType;
import net.frontlinesms.plugins.forms.data.domain.FormResponse;
import net.frontlinesms.plugins.forms.data.domain.ResponseValue;
import net.frontlinesms.plugins.forms.data.repository.FormDao;
import net.frontlinesms.plugins.forms.data.repository.FormResponseCoordsDao;
import net.frontlinesms.plugins.forms.data.repository.FormResponseDao;
import net.frontlinesms.plugins.forms.data.repository.SurveyDao;
import net.frontlinesms.plugins.forms.data.repository.V_FieldPositionIndexDao;
import net.frontlinesms.plugins.forms.exceptions.ContactExistsException;
import net.frontlinesms.plugins.forms.exceptions.ContactFormOwnershipException;
import net.frontlinesms.plugins.forms.request.DataSubmissionRequest;
import net.frontlinesms.plugins.forms.request.FormsRequestDescription;
import net.frontlinesms.plugins.forms.request.NewFormRequest;
import net.frontlinesms.plugins.forms.request.SubmittedFormData;
import net.frontlinesms.plugins.forms.response.FormsResponseDescription;
import net.frontlinesms.plugins.forms.response.NewFormsResponse;
import net.frontlinesms.plugins.forms.response.SubmittedDataResponse;
import net.frontlinesms.plugins.forms.ui.DefaultComponentDescriptor;
import net.frontlinesms.plugins.forms.ui.FormsThinletTabController;
import net.frontlinesms.ui.Event;
import net.frontlinesms.ui.UiGeneratorController;
import net.frontlinesms.ui.i18n.InternationalisationUtils;
import net.frontlinesms.ui.i18n.TextResourceKeyOwner;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.context.ApplicationContext;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

/**
 * Controller for the FrontlineForms plugin.
 *
 * @author Alex
 * @author Fabaris Srl: Andrea Zanchi,Attila Aknai,Maria Cilione,Rajimol Joseph
 * @author UNOPS:Mureed Al-BArgouthi
 * www.fabaris.it <http://www.fabaris.it/>
 */
@PluginControllerProperties(name = "Forms", i18nKey = "plugins.forms.forms", iconPath = "/icons/form.png", springConfigLocation = "classpath:net/frontlinesms/plugins/forms/frontlineforms-spring-hibernate.xml", hibernateConfigPath = "classpath:net/frontlinesms/plugins/forms/frontlineforms.hibernate.cfg.xml")
@TextResourceKeyOwner
public class FormsPluginController extends BasePluginController implements IncomingMessageListener {

    String imagesPath = AppProperties.getInstance().getWebServerImagesPath();

    // > CONSTANTS
    /**
     * Filename and path of the XML for the FrontlineForms tab.
     */
    private static final String XML_FORMS_TAB = "/ui/plugins/forms/formsTab.xml";

    /**
     * I18n Text key: SMS text: "There is a new form available: xyz"
     */
    private static final String I18N_NEW_FORMS_SMS = "sms.form.available";
    private static final String I18N_NEW_FORMS_S_XForm = "sms.form.xform";
    private static final String I18N_FORM_RESPONSE_OK = "form.response.ok";
    private static final String I18N_FORM_RESPONSE_ERROR = "form.response.error";
    private static final String I18N_FORM_RESPONSE_EXIST = "form.response.exist";
    // > INSTANCE PROPERTIES
    /**
     * the {@link FrontlineSMS} instance that this plugin is attached to
     */
    private FrontlineSMS frontlineController;
    /**
     * the {@link FormsMessageHandler} for processing incoming and outgoing
     * messages
     */
    private FormsMessageHandler formsMessageHandler;
    /**
     * Fabaris_a.zanchi the {@link CustomFormsMessageHandler} for customized
     * processing of incoming and outgoing messages
     */
    private CustomFormsMessageHandler customFormsMessageHandler;
    /**
     * DAO for forms
     */
    private FormDao formDao;
    /**
     * DAO for contacts
     */
    private ContactDao contactDao;
    /**
     * DAO for form responses
     */
    private FormResponseDao formResponseDao;
    /**
     * Fabaris_a.zanchi DAO for Surveys
     */
    private SurveyDao surveyDao;
    /**
     * Fabaris_a.zanchi DAO for GroupMembership
     */
    private GroupMembershipDao groupMembershipDao;
    /**
     * Fabaris_a.aknai DAO for User
     */
    private UserDao userDao;
    private UiGeneratorController uiGenController;
    private V_FieldPositionIndexDao v_FieldPositionIndexDao;
    private FormResponseCoordsDao coordsDao;
    //private ConfigurationDao configurationDao;                     //<---------------- 17/10/2013

    // > CONFIG METHODS
    /**
     * @see PluginController#init(FrontlineSMS, ApplicationContext)
     */
    public void init(FrontlineSMS frontlineController, ApplicationContext applicationContext)
            throws PluginInitialisationException {
        this.frontlineController = frontlineController;
        this.contactDao = frontlineController.getContactDao();
        this.userDao = this.frontlineController.getUserDao();
        this.frontlineController.addIncomingMessageListener(this);
        /* Fabaris_a.zanchi: instantiates the CustomFormsMessageHandler */
        this.customFormsMessageHandler = new CustomFormsMessageHandler(this);
        this.surveyDao = frontlineController.getSurveyDao();
        this.groupMembershipDao = frontlineController.getGroupMembershipDao();
        try {
            this.formDao = (FormDao) applicationContext.getBean("formDao");
            this.formResponseDao = (FormResponseDao) applicationContext.getBean("formResponseDao");
            this.v_FieldPositionIndexDao = (V_FieldPositionIndexDao) applicationContext.getBean("vFieldDao");
            this.coordsDao = (FormResponseCoordsDao) applicationContext.getBean("formResponseCoordDao");

            //this.configurationDao = (ConfigurationDao)applicationContext.getBean("configurationDao");   //<------------------------ 17/10/2013
            String handlerClassName = FormsProperties.getInstance().getHandlerClassName();
            setHandler(handlerClassName);
        } catch (Throwable t) {
            log.warn("Unable to load form handler class.", t);
            throw new PluginInitialisationException(t);
        }
    }

    public void logInfo(String message) {
        log.trace(message);
    }

    void setHandler(String handlerClassName)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        this.formsMessageHandler = (FormsMessageHandler) Class.forName(handlerClassName).newInstance();
        this.formsMessageHandler.init(this);
    }

    // > ACCESSORS
    /**
     * @return {@link #formsMessageHandler}
     */
    public FormsMessageHandler getHandler() {
        return this.formsMessageHandler;
    }

    /**
     * @return {@link #frontlineController}
     */
    public FrontlineSMS getFrontlineController() {
        return this.frontlineController;
    }

    /**
     * @param frontlineController new value for {@link #frontlineController}
     */
    void setFrontlineController(FrontlineSMS frontlineController) {
        this.frontlineController = frontlineController;
    }

    void setFormsMessageHandler(FormsMessageHandler formsMessageHandler) {
        this.formsMessageHandler = formsMessageHandler;
    }

    /**
     * Set {@link #formResponseDao}
     *
     * @param formResponseDao new value for {@link #formResponseDao}
     */
    @Required
    public void setFormResponseDao(FormResponseDao formResponseDao) {
        this.formResponseDao = formResponseDao;
    }

    /**
     * Set {@link #formDao}
     *
     * @param formsDao new value for {@link #formDao}
     */
    @Required
    public void setFormsDao(FormDao formsDao) {
        this.formDao = formsDao;
    }

    public void setContactDao(ContactDao contactDao) {
        this.contactDao = contactDao;
    }

    public SurveyDao getSurveyDao() {
        return this.surveyDao;
    }

    public UserDao getUserDao() {
        return userDao;
    }

    /**
     * @see net.frontlinesms.plugins.PluginController#deinit()
     */
    public void deinit() {
        if (this.frontlineController != null) {
            this.frontlineController.removeIncomingMessageListener(this);
        }
    }

    //   public ConfigurationDao getConfigurationDao(){
    //      return this.configurationDao;
    //   }
    /**
     * @see BasePluginController#initThinletTab(UiGeneratorController)
     */
    public Object initThinletTab(UiGeneratorController uiController) {
        FormsThinletTabController tabController = new FormsThinletTabController(this, uiController);
        tabController.setContactDao(this.frontlineController.getContactDao());
        tabController.setGroupMembershipDao(this.frontlineController.getGroupMembershipDao());
        tabController.setFormsDao(formDao);
        tabController.setFormResponseDao(formResponseDao);
        tabController.setContactDao(contactDao);

        //tabController.setConfigurationDao(configurationDao);         //<--------------------- 17/10/2013
        uiGenController = uiController;

        Object formsTab = uiController.loadComponentFromFile(XML_FORMS_TAB, tabController);
        tabController.setTabComponent(formsTab);

        tabController.refresh();

        return formsTab;
    }

    // > EVENT HANDLING METHODS
    /**
     * Process a new message coming into the system.
     */
    public void incomingMessageEvent(FrontlineMessage message) {
        try {
            /*
             * Commented by Fabaris_a.zanchi FormsRequestDescription request =
             * this.formsMessageHandler.handleIncomingMessage(message);
             */

            /*
             * Fabaris_a.zanchi call to the CustomFormsMessageHandler to do
             * custom processing on the message
             */
            FormsRequestDescription request = this.customFormsMessageHandler.handleIncomingMessage(message);

            FormsResponseDescription response;
            if (request instanceof DataSubmissionRequest) {
                response = handleDataSubmissionRequest((DataSubmissionRequest) request, message.getSenderMsisdn());
            } else if (request instanceof NewFormRequest) {
                response = handleNewFormRequest((NewFormRequest) request, message.getSenderMsisdn());
            } else {
                throw new IllegalStateException("Unknown form request description type: " + request);
            }

            // If there is a response to send back to the form submitter, then
            // process it
            if (response != null) {
                handleResponse(request.getSmsPort(), message.getSenderMsisdn(), response);
            }
        } catch (Throwable t) {
            log.info("There was a problem handling incoming message as forms message.", t);
        }
    }

    public String incomingHTTPResponse(String phone, String data) {
        // System.out.println("FormsPluginController.incomingHTTPResponse()");
        FrontlineMessage message = FrontlineMessage.createIncomingMessage(System.currentTimeMillis(), phone, "",
                data);
        // System.out.println("FormsPluginController.incomingHTTPResponse().message:"+message);
        try {
            FormsRequestDescription request = this.customFormsMessageHandler.handleIncomingMessage(message);
            FormsResponseDescription response = null;
            // System.out.println("request:"+request);
            if (request instanceof DataSubmissionRequest) {
                response = handleDataSubmissionRequest((DataSubmissionRequest) request, message.getSenderMsisdn());
            }
            // If there is a response to send back to the form submitter, then
            // process it
            if (response != null) {
                Collection<FrontlineMessage> messages = this.customFormsMessageHandler
                        .handleOutgoingMessage(response);
                if (messages.size() == 0) {
                    return null;
                }
                for (FrontlineMessage m : messages) {
                    String resp = m.getTextContent();
                    String description = InternationalisationUtils.getI18nString(I18N_FORM_RESPONSE_OK);
                    uiGenController.getHomeTabController()
                            .newEvent(new Event(Event.TYPE_HTTP_RESPONSE_OK, description));
                    return resp;
                }
            }
        } catch (FormHandlingException e) {
            uiGenController.getHomeTabController().newEvent(new Event(Event.TYPE_HTTP_RESPONSE_ERROR,
                    InternationalisationUtils.getI18nString(I18N_FORM_RESPONSE_ERROR, e.getMessage())));
            return e.getMessage();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            // System.err.println("Error parsing incoming message!!");
            e.printStackTrace();
            uiGenController.getHomeTabController().newEvent(new Event(Event.TYPE_HTTP_RESPONSE_ERROR,
                    InternationalisationUtils.getI18nString(I18N_FORM_RESPONSE_ERROR, e.getMessage())));
            return e.getMessage();
        }
        return null;
    }

    /* default access to allow for unit test */
    void handleResponse(Integer smsPort, String senderMsisdn, FormsResponseDescription response)
            throws FormHandlingException {
        /*
         * Commented by Fabaris_a.zanchi Collection<FrontlineMessage>
         * responseMessages =
         * this.formsMessageHandler.handleOutgoingMessage(response);
         */

        /* Call to the CustomFormsMessageHandler */
        Collection<FrontlineMessage> responseMessages = this.customFormsMessageHandler
                .handleOutgoingMessage(response);
        log.info("Sending forms response.  Response messages: " + responseMessages.size());
        for (FrontlineMessage responseMessage : responseMessages) {
            // Make sure that the response is sent to the correct recipient!
            responseMessage.setRecipientMsisdn(senderMsisdn);
            if (smsPort != null) {
                responseMessage.setRecipientSmsPort(smsPort);
            }
            this.frontlineController.sendMessage(responseMessage);
        }
        log.trace("Response messages sent.");
    }

    // > PRIVATE HELPER METHODS
    /**
     * Handles a request of type: {@link DataSubmissionRequest}
     *
     * @param request
     * @param senderMsisdn
     * @return a response of type {@link SubmittedDataResponse}
     */
    /* default access to allow for unit test */
    SubmittedDataResponse handleDataSubmissionRequest(DataSubmissionRequest request, String senderMsisdn) {
        /**
         * List of data IDs of the successfully processed responses
         */
        Collection<SubmittedFormData> dataIds = new HashSet<SubmittedFormData>();
        long id = 0;
        for (SubmittedFormData submittedData : request.getSubmittedData()) {

            log.trace("In handle Data Submission Request ............................ ");

            Form form = this.formDao.getFromId_IdMac(submittedData.getFormId_IdMac());
            if (form == null) {
                log.warn("No form found for submitted data with dataId: " + submittedData.getDataId());
                continue;
            }

            List<ResponseValue> responseValues = submittedData.getDataValues();
            if (form.getEditableFieldCount() != responseValues.size()) {
                log.info("Editable field count mismatch: submitted " + responseValues.size() + "/"
                        + form.getEditableFieldCount());
                continue;
            }

            // Commented by Fabaris_a.zanchi
            // this.formResponseDao.saveResponse(new FormResponse(senderMsisdn,
            // form, responseValues));
            /**
             * Modified by mureed Check the images in submitted form
             */
            FormResponse newResponse = new FormResponse(senderMsisdn, form, responseValues,
                    submittedData.getClientVersion());
            // Fabaris_a.zanchi puts in the FormResponse the identificator
            // retrieved from message
            newResponse.setCode_Form(request.getFormResponseName());
            FormResponse responseOnDB = this.formResponseDao.getFormResponse(newResponse.getCode_Form());
            if (responseOnDB != null) {
                this.uiGenController.getHomeTabController().newEvent(new Event(Event.TYPE_HTTP_RESPONSE_ERROR,
                        InternationalisationUtils.getI18nString(I18N_FORM_RESPONSE_EXIST)));
                dataIds.add(submittedData);
                continue;
            }
            //Save the response and return the entity
            //this.formResponseDao.saveResponse(newResponse);
            FormResponse entityStored = this.formResponseDao.saveResponseAndReturnEntity(newResponse);

            long formResponseId = entityStored.getId();

            log.trace("image check ............................ ");
            String imageValue = "";

            String instancePath = imagesPath + System.getProperty("file.separator") + formResponseId;
            for (ResponseValue responseValue : responseValues) {
                if (responseValue.isIsImage()) {
                    imageValue = responseValue.toString();
                    try {
                        File instanceDirectory = new File(instancePath);
                        if (!instanceDirectory.exists()) {
                            if (instanceDirectory.mkdir()) {

                            } else {
                                log.error("Failed to create instance directory ");
                            }
                        }
                        convertByteImageToFile(Base64.decodeBase64(responseValue.getTempValue()),
                                instancePath + System.getProperty("file.separator") + imageValue);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            log.trace("create image file from here ............................ ");

            List<ResponseValue> resValues = entityStored.getResults();
            for (ResponseValue resVal : resValues) {
                resVal.setFormResponseID(formResponseId);
                if (resVal.getRVRepeatCount() == -1) {
                    List<ResponseValue> repeatableValues = resVal.getRepetablesValues();
                    for (ResponseValue repVal : repeatableValues) {
                        repVal.setFormResponseID(formResponseId);
                    }
                }
            }
            this.formResponseDao.updateResponse(entityStored);

            id = entityStored.getId();

            int positionIndex = this.v_FieldPositionIndexDao
                    .getGeoPositionIndexByFormId(entityStored.getParentForm().getId(), "GEOLOCATION");
            String geoValue = "";
            if (positionIndex != -1) {
                for (ResponseValue responseValue : responseValues) {
                    if (responseValue.getPositionIndex() == positionIndex) {
                        geoValue = responseValue.toString();
                        break;
                    }
                }
                System.out.println("11111111111111111111111111111111111 ");
                this.coordsDao.insertResponseCoords(entityStored.getId(), geoValue);
            }

            this.formDao.finaliseForm(form);
            dataIds.add(submittedData);
        }

        SubmittedDataResponse ret = new SubmittedDataResponse(dataIds);
        ret.setFormIdentificator(request.getFormIdentificator());
        ret.setFormResponseName(request.getFormResponseName());
        ret.setFormResponceId(id);
        return ret;
    }

    /**
     * Handles a request of type {@link NewFormRequest}
     *
     * @param request
     * @param message
     * @return a response of type {@link NewFormsResponse}, or <code>null</code>
     * if no response should be sent.
     */
    /* default access to allow for unit test */
    NewFormsResponse handleNewFormRequest(NewFormRequest request, String senderMsisdn) {
        Contact contact = this.contactDao.getFromMsisdn(senderMsisdn);
        if (contact == null || !contact.isActive()) {
            // This contact is not known, so there cannot be any forms available
            // for him
            return null;
        } else {
            Collection<Form> newForms = this.formDao.getFormsForUser(contact,
                    ((NewFormRequest) request).getCurrentFormIds());
            return new NewFormsResponse(contact, newForms);
        }
    }

    /**
     * Send a form to a collection of contacts.
     *
     * @param form the form to send
     * @param contacts the contacts to send the form to
     */
    // public void sendForm(Form form, Collection<Contact> contacts) {
    /**
     * Aggiunto da FABARIS_maria .
     *
     * @return
     */
    public int sendForm(Form form, Collection<Contact> contacts, List<String> xform) {
        // Send a text SMS to each contact informing them that a new form is
        // available.
        int sentCount = 0;
        String messageContent = InternationalisationUtils.getI18nString(I18N_NEW_FORMS_SMS, form.getName());
        System.out.println("26-aprile=" + messageContent);
        /**
         * Fabaris_maria c.
         */
        String xf = xform.get(0);
        // xf = xf.replace("[[", "");
        // xf = xf.replace("]]", "");
        // xf = xf.replace(", ", "");
        xf = xf.trim();
        // System.out.println("XF:"+xf);
        String strversionflsms = new String();
        try {
            // Fabaris_a.zanchi the only change here is calling removeEmptyGroup
            // on the xform
            strversionflsms = removeEmptyGroups(insertSoftwareVersionNumber(xf, form));
        } catch (Exception e1) {
            e1.printStackTrace();
            log.error(e1.getMessage());
            JOptionPane.showMessageDialog(null,
                    InternationalisationUtils.getI18nString(FormsThinletTabController.I18N_FORM_COMPONENTS_ERROR),
                    "", JOptionPane.ERROR_MESSAGE);
            return sentCount;
        }
        // concatenazione dei due messaggi per 'l invio dei form
        String x_forms = messageContent + "<__>" + strversionflsms;
        System.out.println("----------- complete message --------------");
        System.out.println(x_forms);
        /**
         * maria c.
         */
        for (Contact c : contacts) {
            // TODO if it is possible, we could send forms directly to people
            // here
            // this.frontlineController.sendTextMessage(c.getPhoneNumber(),
            // messageContent);
            /**
             * Fabaris_maria c.
             */
            sentCount++;
            this.frontlineController.sendTextMessage(c.getPhoneNumber(), x_forms);
            /**
             * maria c.
             */
        }
        return sentCount;
    }

    /**
     * @return The {@link FormDao of the plugin controller}
     */
    public FormDao getFormDao() {
        return formDao;
    }

    /**
     * Fabaris_a.zanchi This method extracts the Form Id from the "id" attribute
     * of <data> tag
     *
     * @param xmlContent String who contains the xml
     * @return a String representing the form ID
     * @throws Exception
     */
    public static String getFormIdFromXml(String xmlContent) throws Exception {
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        InputSource inStream = new InputSource();
        inStream.setCharacterStream(new StringReader(xmlContent));
        org.w3c.dom.Document xmlDoc = docBuilder.parse(inStream);
        xmlDoc.getDocumentElement().normalize();
        NodeList nodeList = xmlDoc.getElementsByTagName("id");
        Node dataNode = nodeList.item(0);
        Element elem = (Element) dataNode;
        // String id = elem.getAttribute("id");
        String id = elem.getFirstChild().getNodeValue();
        return id;

    }

    /**
     * Fabaris_a.zanchi This method extracts from the xml the value of a
     * FormField
     *
     * @param xmlContent String containing the entire xml
     * @param formField object of type {@link FormField}
     * @return a String with the value of the respective FormField extracted
     * from the xmlConent
     * @throws Exception
     */
    public static String getFormDataXml(String xmlContent, FormField formField) throws Exception {
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        InputSource inStream = new InputSource();
        inStream.setCharacterStream(new StringReader(xmlContent));
        org.w3c.dom.Document xmlDoc = docBuilder.parse(inStream);
        xmlDoc.getDocumentElement().normalize();
        String fieldValue = null;
        if (formField.getType() != FormFieldType.REPEATABLES) {
            if (formField.getType() != FormFieldType.CURRENCY_FIELD) {
                //30.10.2013
                //NodeList nodeList = xmlDoc.getElementsByTagName(String.valueOf(formField.getId()).trim() + "_" + formField.getPositionIndex());

                NodeList nodeList = xmlDoc
                        .getElementsByTagName(formField.getName().trim() + "_" + formField.getPositionIndex());
                if (nodeList.getLength() == 0) // check if the field exsists in xml
                {
                    return "";
                }
                Node dataNode = nodeList.item(0);
                Element elem = (Element) dataNode;
                if (elem.getFirstChild() == null) {
                    return "";
                }
                fieldValue = elem.getFirstChild().getNodeValue();
            } else {
                // search for import value
                //30.10.2013
                //NodeList nodeList = xmlDoc.getElementsByTagName(String.valueOf(formField.getId()).trim() + "_" + formField.getPositionIndex());

                NodeList nodeList = xmlDoc
                        .getElementsByTagName(formField.getName().trim() + "_" + formField.getPositionIndex());
                if (nodeList.getLength() == 0) // check if the field exsists in
                // xml
                {
                    return "";
                }
                Node dataNode = nodeList.item(0);
                Element elem = (Element) dataNode;
                if (elem.getFirstChild() == null) {
                    return "";
                }
                fieldValue = elem.getFirstChild().getNodeValue();
                // Search for currency
                //30.10.2013
                //NodeList nodeList2 = xmlDoc.getElementsByTagName(String.valueOf(formField.getId()).trim() + "_" + formField.getPositionIndex() + "_curr");

                NodeList nodeList2 = xmlDoc.getElementsByTagName(
                        formField.getName().trim() + "_" + formField.getPositionIndex() + "_curr");
                Node dataNode2 = nodeList2.item(0);
                Element currencyElem = (Element) dataNode2;
                if (currencyElem.getFirstChild() != null) {
                    fieldValue = fieldValue + currencyElem.getFirstChild().getNodeValue();
                }
            }
        } else {
            // In this case we have to search "deeper"
            //30.10.2013
            //NodeList nodeList = xmlDoc.getElementsByTagName(String.valueOf(formField.getId()).trim() + "_" + formField.getPositionIndex());

            NodeList nodeList = xmlDoc
                    .getElementsByTagName(formField.getName().trim() + "_" + formField.getPositionIndex());
            Node dataNode = nodeList.item(0);
            Element elem = (Element) dataNode;
            //30.10.2013
            //NodeList repNodeList = elem.getElementsByTagName(formField.getId_flsmsId().trim());

            NodeList repNodeList = elem.getElementsByTagName(formField.getName().trim());
            Node repNode = repNodeList.item(0);
            Element repEelem = (Element) repNode;
            if (repEelem.getFirstChild() == null) {
                return "";
            }
            fieldValue = repEelem.getFirstChild().getNodeValue();
        }
        return fieldValue;
    }

    /**
     * Fabaris_a.zanchi Static utility method to extract tag contents from a xml
     *
     * @param xmlContent The xml conent
     * @param tag the specified xml tag we want to fetch contents from
     * @return a List of Strings with the tags' content
     */
    public static List<String> getTagContentFromXml(String xmlContent, String tag) throws Exception {
        List<String> ret = new ArrayList<String>();
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        InputSource inStream = new InputSource();
        inStream.setCharacterStream(new StringReader(xmlContent));
        org.w3c.dom.Document xmlDoc = docBuilder.parse(inStream);
        xmlDoc.getDocumentElement().normalize();
        if (!tag.equals("client_version")) {
            NodeList nodeList = xmlDoc.getElementsByTagName(tag);
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node dataNode = nodeList.item(i);
                Element elem = (Element) dataNode;
                ret.add(elem.getFirstChild().getNodeValue());
            }
        } else {
            // Search for client version not knowing its index
            NodeList dataNode = xmlDoc.getElementsByTagName("data");
            Element dataElem = (Element) dataNode.item(0);
            NodeList allNodes = dataElem.getChildNodes();
            for (int i = 0; i < allNodes.getLength(); i++) {
                if (allNodes.item(i).getNodeName().contains("client_version")) {
                    ret.add(allNodes.item(i).getTextContent());
                }
            }
        }
        return ret;
    }

    /**
     * Fabaris_a.zanchi This method inserts the designer software version number
     * in the outgoing xform It also creates an empty tag for the client version
     *
     * @param xmlContent the string representation of the xform
     */
    public static String insertSoftwareVersionNumber(String xmlContent, Form form) throws Exception {
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        InputSource inStream = new InputSource();
        inStream.setCharacterStream(new StringReader(xmlContent));
        org.w3c.dom.Document xmlDoc = docBuilder.parse(inStream);
        xmlDoc.getDocumentElement().normalize();
        Node versionNode = xmlDoc.getElementsByTagName(DefaultComponentDescriptor.DESINGER_VERSION_TAGNAME + "_"
                + DefaultComponentDescriptor.DESIGNER_VERSION_INDEX).item(0);
        if (versionNode != null) {
            versionNode.setTextContent(form.getDesignerVersion());
        }
        /*
         * NodeList nodeList = xmlDoc.getElementsByTagName("h:head"); Node
         * headNode = nodeList.item(0); Node modelNode =
         * xmlDoc.getElementsByTagName("model").item(0); Element newElemDesigner
         * = xmlDoc.createElement("designer_version"); Element newElemClient =
         * xmlDoc.createElement("client_version"); Node newNodeDesigner = (Node)
         * newElemDesigner; Node newNodeClient = (Node) newElemClient; String
         * designerVersion = form.getDesignerVersion(); if (designerVersion ==
         * null) designerVersion = "";
         * newNodeDesigner.appendChild(xmlDoc.createTextNode(designerVersion));
         * newNodeClient.appendChild(xmlDoc.createTextNode(""));
         * headNode.insertBefore(newNodeDesigner, modelNode);
         * headNode.insertBefore(newNodeClient, modelNode);
         */
        TransformerFactory tFactory = TransformerFactory.newInstance();
        Transformer trans = tFactory.newTransformer();
        trans.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        StringWriter sWriter = new StringWriter();
        Result result = new StreamResult(sWriter);
        trans.transform(new DOMSource(xmlDoc), result);
        String result2 = sWriter.getBuffer().toString();
        System.out.println("-------- inserting version ------------");
        System.out.println(result2);
        return result2;
    }

    /**
     * Fabaris_a.zanchi Method to extract values form repeatable components
     *
     * @param textContent the xml message
     * @param ff the formfield of the container object
     * @param formField the formfield of repeatable object
     * @param index the number of repetition currently ectracting
     * @return the value of the component in xml
     * @throws Exception
     *//*
        public static String getFormRepeatableDataXml(String xmlContent, FormField containerFf, FormField childFormField, int index) throws Exception {
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        InputSource inStream = new InputSource();
        inStream.setCharacterStream(new StringReader(xmlContent));
        org.w3c.dom.Document xmlDoc = docBuilder.parse(inStream);
        xmlDoc.getDocumentElement().normalize();
        NodeList nodeList = xmlDoc.getElementsByTagName(containerFf.getName().trim() + "_" + containerFf.getPositionIndex());
        Node dataNode = nodeList.item(0);
        Element elem = (Element) dataNode;
        NodeList childNodeList = elem.getElementsByTagName(childFormField.getName().trim() + "_" + index);
        Node childNode = childNodeList.item(0);
        Element childEelem = (Element) childNode;
        if (childEelem.getFirstChild() == null)
        return null;
        return childEelem.getFirstChild().getNodeValue();
        }*/

    /**
     * Fabaris_a.zanchi Method to remove empty groups for outgoing messages so
     * that mobile tool doesn't crash
     *
     * @param content an xml document (just xml without any additional content)
     * @return xml document without empty groups with attribute
     * appearance="field-list"
     * @throws Exception
     */
    public static String removeEmptyGroups(String content) throws Exception {
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        InputSource inStream = new InputSource();
        inStream.setCharacterStream(new StringReader(content));
        org.w3c.dom.Document xmlDoc = docBuilder.parse(inStream);
        xmlDoc.getDocumentElement().normalize();
        NodeList groupList = xmlDoc.getElementsByTagName("group");
        int i = 0;
        while (i < groupList.getLength()) {
            Element group = (Element) groupList.item(i);
            if (group.getAttribute("appearance").equals("field-list")) {
                if (group.getChildNodes().getLength() == 0) {
                    groupList.item(i).getParentNode().removeChild(groupList.item(i));
                    i--;
                }
                if (group.getTextContent().equals(", ")) {
                    groupList.item(i).getParentNode().removeChild(groupList.item(i));
                    i--;
                }
            }
            i++;
        }
        TransformerFactory tFactory = TransformerFactory.newInstance();
        Transformer trans = tFactory.newTransformer();
        trans.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        StringWriter sWriter = new StringWriter();
        Result result = new StreamResult(sWriter);
        trans.transform(new DOMSource(xmlDoc), result);
        String result2 = sWriter.getBuffer().toString();
        System.out.println("---------- remove empty groups ---------");
        System.out.println(result2);
        return result2;
    }

    /**
     * Fabaris_a.zanchi Counts the actual repetitions of a repeatable section
     *
     * @param xmlContent xml message
     * @param repContainerName the name of the repeatables container
     * @return count of repetitions
     * @throws Exception
     */
    public static int countRepetitionOfRepeatable(String xmlContent, String repContainerName) throws Exception {
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        InputSource inStream = new InputSource();
        inStream.setCharacterStream(new StringReader(xmlContent));
        org.w3c.dom.Document xmlDoc = docBuilder.parse(inStream);
        xmlDoc.getDocumentElement().normalize();
        NodeList repetitionList = xmlDoc.getElementsByTagName(repContainerName);
        return repetitionList.getLength();
    }

    /**
     * Fabaris_a.zanchi Gets values of items in repeatable container for a given
     * repetition
     *
     * @param xmlContent xml message
     * @param repContainerName name of the repeatables container
     * @param repeatables List of FormField contained in the repetition
     * @param repetitionNumber the repetition instance (it starts from 0 not
     * from 1)
     * @return List of values for the given repetition
     * @throws Exception
     */
    public static List<String> getValuesForRepetition(String xmlContent, String repContainerName,
            List<FormField> repeatables, int repetitionNumber) throws Exception {
        List<String> ret = new ArrayList<String>();
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        InputSource inStream = new InputSource();
        inStream.setCharacterStream(new StringReader(xmlContent));
        org.w3c.dom.Document xmlDoc = docBuilder.parse(inStream);
        xmlDoc.getDocumentElement().normalize();
        NodeList repetitionList = xmlDoc.getElementsByTagName(repContainerName);
        Node givenRepetition = null;
        try {
            givenRepetition = repetitionList.item(repetitionNumber);
        } catch (Exception e) {
            for (FormField rep : repeatables) {
                ret.add("");
            }
            return ret;
        }
        Element repElement = (Element) givenRepetition;
        for (int i = 0; i < repeatables.size(); i++) {
            if (repeatables.get(i).getType() == FormFieldType.CURRENCY_FIELD) {
                String nodename = repeatables.get(i).getName() + "_curr";
                try {
                    String currency = repElement.getElementsByTagName(nodename).item(0).getTextContent();
                    ret.add(repElement.getElementsByTagName(repeatables.get(i).getName()).item(0).getTextContent()
                            + currency);
                } catch (Exception e) {
                    ret.add("");
                }

            } else {
                try {
                    String value = repElement.getElementsByTagName(repeatables.get(i).getName()).item(0)
                            .getTextContent();
                    if (repeatables.get(i).getType() == FormFieldType.CHECK_BOX && value.equals("")) {
                        ret.add("false");
                    } else {
                        ret.add(repElement.getElementsByTagName(repeatables.get(i).getName()).item(0)
                                .getTextContent());
                    }
                } catch (Exception e) {
                    ret.add("");
                }
            }
        }
        return ret;
    }

    /**
     * Fabaris_a.zanchi Gets values of items in repeatable container in a
     * certain survey value section
     *
     * @param xmlContent xml message
     * @param repContainerName name of the repeatables container
     * @param surveySection name of the current survey section
     * @param repeatables List of FormField contained in the repetition
     * @return List of values for the given repetition (identified by surver
     * section name)
     * @throws Exception
     */
    public static List<String> getValuesForRepetitionWithSurvey(String xmlContent, String repContainerName,
            String surveySection, List<FormField> repeatables) throws Exception {
        List<String> ret = new ArrayList<String>();
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        InputSource inStream = new InputSource();
        inStream.setCharacterStream(new StringReader(xmlContent));
        org.w3c.dom.Document xmlDoc = docBuilder.parse(inStream);
        xmlDoc.getDocumentElement().normalize();
        NodeList repetitionNodeList = xmlDoc.getElementsByTagName(repContainerName);
        if (repetitionNodeList.getLength() == 0) { // check if the repetition
            // exissts
            for (FormField ff : repeatables) {
                ret.add("");
            }
            return ret;
        }
        Element repetitionNode = (Element) xmlDoc.getElementsByTagName(repContainerName).item(0);
        Element surveyNode = (Element) repetitionNode.getElementsByTagName(surveySection).item(0);
        for (FormField ff : repeatables) {
            if (ff.getType() == FormFieldType.CURRENCY_FIELD) {
                String nodename = ff.getName() + "_curr";
                try {
                    String currency = surveyNode.getElementsByTagName(nodename).item(0).getTextContent();
                    ret.add(surveyNode.getElementsByTagName(ff.getName()).item(0).getTextContent() + currency);
                } catch (Exception e) {
                    ret.add("");
                }
            } else {
                try {
                    String value = surveyNode.getElementsByTagName(ff.getName()).item(0).getTextContent();
                    if (ff.getType() == FormFieldType.CHECK_BOX && value.equals("")) {
                        ret.add("false");
                    } else {
                        ret.add(surveyNode.getElementsByTagName(ff.getName()).item(0).getTextContent());
                    }
                } catch (Exception e) {
                    ret.add("");
                }
            }
        }
        return ret;

    }

    public static boolean isInList(List<String> list, String obj) {
        for (String item : list) {
            if (item.equals(obj)) {
                return true;
            }
        }
        return false;
    }

    public static boolean isAssignedToForm(String phone, Form f) {
        Contact c = FormsThinletTabController.getCurrentInstance().getPluginController().contactDao
                .getFromMsisdn(phone);
        if (c == null) {
            return false;
        }
        Group g = f.getPermittedGroup();
        if (g == null) {
            return false;
        }
        List<Contact> contacts = FormsThinletTabController.getCurrentInstance()
                .getPluginController().groupMembershipDao.getActiveMembers(g);
        for (Contact listContact : contacts) {
            if (listContact.equals(c)) {
                return true;
            }
        }
        return false;
    }

    public static String formToXForm(Form f) {
        String xform = new String();
        for (FormField ff : f.getFields()) {
            if (ff.getX_form() != null) {
                xform += ff.getX_form();
            }
        }

        return xform;
    }

    /**
     * Fabaris_a.zanchi method that checks if a contact and a form are
     * associated
     *
     * @param formId identificator of the form. Currently the id_idfsms of the
     * form
     * @param telephone the phone number of the sender
     * @throws ContactExistsException throw if the contact doesn't exist in the
     * database
     * @throws ContactFormOwnershipException throw if contact and form are not
     * associated
     */
    public void checkContactFormOwnership(String formId, String telephone)
            throws ContactExistsException, ContactFormOwnershipException {
        Contact c = contactDao.getFromMsisdn(telephone);
        if (c == null) {
            throw new ContactExistsException(
                    "The contact with phone number: " + telephone + " does not exists on local database");
        }
        Form incoming = formDao.getFromId_IdMac(formId);
        Group permittedGroup = incoming.getPermittedGroup();
        List<Contact> contacts = groupMembershipDao.getActiveMembers(permittedGroup);
        if (!contacts.contains(c)) {
            throw new ContactFormOwnershipException("The contact with phone number: " + telephone
                    + " is not associated with the incoming form with id_idMac: " + formId);
        }

    }

    private void convertByteImageToFile(byte[] imageByte, String path) throws Exception {
        System.out.println("path ...... convertByteImageToFile ......... " + path);

        ByteArrayInputStream bis = new ByteArrayInputStream(imageByte);
        Iterator<?> readers = ImageIO.getImageReadersByFormatName("jpg");

        ImageReader reader = (ImageReader) readers.next();
        Object source = bis;
        ImageInputStream iis = ImageIO.createImageInputStream(source);
        reader.setInput(iis, true);
        ImageReadParam param = reader.getDefaultReadParam();

        Image image = reader.read(0, param);
        //got an image file

        BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null),
                BufferedImage.TYPE_INT_RGB);
        //bufferedImage is the RenderedImage to be written

        Graphics2D g2 = bufferedImage.createGraphics();
        g2.drawImage(image, null, null);

        File imageFile = new File(path);
        ImageIO.write(bufferedImage, "jpg", imageFile);
        System.out.println(" end write image ");
    }
}