org.motechproject.mobile.imp.serivce.oxd.FormDefinitionServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.motechproject.mobile.imp.serivce.oxd.FormDefinitionServiceImpl.java

Source

/**
 * MOTECH PLATFORM OPENSOURCE LICENSE AGREEMENT
 *
 * Copyright (c) 2010-11 The Trustees of Columbia University in the City of
 * New York and Grameen Foundation USA.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of Grameen Foundation USA, Columbia University, or
 * their respective contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY GRAMEEN FOUNDATION USA, COLUMBIA UNIVERSITY
 * AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GRAMEEN FOUNDATION
 * USA, COLUMBIA UNIVERSITY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.motechproject.mobile.imp.serivce.oxd;

import org.springframework.core.io.ClassPathResource;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Henry Sampson (henry@dreamoval.com) and Brent Atkinson
 *         Date Created: Mar 3, 2010
 */
public class FormDefinitionServiceImpl
        implements FormDefinitionService, StudyDefinitionService, UserDefinitionService {

    private List<Object[]> users;
    private PasswordEncoder encoder;
    private List<String> studies;
    private Map<String, List<Integer>> studyForms;
    private Map<Integer, String> formMap;
    private Set<String> oxdFormDefResources;

    public FormDefinitionServiceImpl() {
        studies = new ArrayList<String>();
        studyForms = new LinkedHashMap<String, List<Integer>>();
        formMap = new HashMap<Integer, String>();
    }

    public void init() throws Exception {

        for (String resource : getOxdFormDefResources()) {
            int index = resource.lastIndexOf("/");
            String studyName = resource.substring(index + 1);
            List<File> fileList = getFileList(resource);
            if (fileList == null || fileList.isEmpty())
                throw new FileNotFoundException(" No files in the directory " + resource);
            List<Integer> formIdList = new ArrayList<Integer>();
            for (File fileName : fileList) {
                String formDefinition = getFileContent(fileName.getAbsolutePath());
                Integer extractedFormId = extractFormId(formDefinition);
                formMap.put(extractedFormId, formDefinition);
                formIdList.add(extractedFormId);
            }

            studyForms.put(studyName, formIdList);
            studies.add(studyName);
        }

    }

    private Integer extractFormId(String formDefinition) {
        Matcher matcher = Pattern.compile("<xf:xforms.*?id=\"(.*?)\"", Pattern.CASE_INSENSITIVE)
                .matcher(formDefinition);
        Integer formId = null;
        if (matcher.find()) {
            String formIdString = matcher.group(1);
            formId = Integer.valueOf(formIdString);
        }
        return formId;
    }

    private String getFileContent(String fileName) {
        StringBuilder builder = new StringBuilder();
        Scanner scanner;
        try {
            scanner = new Scanner(new File(fileName));
            scanner.useDelimiter("\n");
            while (scanner.hasNextLine()) {
                builder.append(scanner.nextLine() + "\n");
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return builder.toString();
    }

    public List<File> getFileList(String directorySource) throws IOException {

        File directory = new ClassPathResource(directorySource).getFile();
        if (directory == null)
            throw new RuntimeException(new FileNotFoundException(" resource not found" + directorySource));

        if (!directory.exists())
            return Collections.emptyList();

        List<File> fileList = Arrays.asList(directory.listFiles(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                if (name.endsWith(".xml"))
                    return true;
                return false;
            }
        }));
        Collections.sort(fileList, new Comparator<File>() {
            public int compare(File o1, File o2) {
                return o1.getName().compareToIgnoreCase(o2.getName());
            }
        });
        return fileList;
    }

    private XmlPullParserFactory getXMLPullParserFactory() throws XmlPullParserException {
        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
        factory.setNamespaceAware(true);
        return factory;
    }

    /**
     * @return a map of xml xforms definitions, keyed on their definition ids
     */
    public Map<Integer, String> getXForms() throws Exception {
        return formMap;
    }

    /**
     * @return the oxdFormDefResources
     */
    public Set<String> getOxdFormDefResources() {
        return oxdFormDefResources;
    }

    /**
     * <p>Sets the resource names for the Exported OXD Form definitions</p>
     *
     * @param oxdFormDefResources the oxdFormDefResourceNames to set
     */
    public void setOxdFormDefResources(Set<String> oxdFormDefResources) {
        this.oxdFormDefResources = oxdFormDefResources;
    }

    /**
     * <p>Sets the resource names for the Exported OXD Form definitions</p>
     *
     * @param oxdFormDefResource the oxdFormDefResourceName to set
     */
    public void addOxdFormDefResources(String oxdFormDefResource) {
        if (oxdFormDefResources == null) {
            oxdFormDefResources = new HashSet<String>();
        }
        oxdFormDefResources.add(oxdFormDefResource);
    }

    /**
     * Returns the list of studies. The studies are stored in the same order
     * that they are read in. This means you should be able to use the list to
     * get the proper study based on the numerical index of the study.
     */
    public List<Object[]> getStudies() {
        List<Object[]> result = new ArrayList<Object[]>();
        if (studies == null) {
            return Collections.emptyList();
        }
        for (int studyidx = 0; studyidx < studies.size(); studyidx++) {
            result.add(new Object[] { studyidx, studies.get(studyidx) });
        }
        return result;
    }

    /**
     * Used to set the password encoder implementation.
     *
     * @param encoder
     */
    public void setPasswordEncoder(PasswordEncoder encoder) {
        this.encoder = encoder;
    }

    /**
     * Returns the list of openxdata users.
     */
    public List<Object[]> getUsers() {
        return users;
    }

    /**
     * Sets the list of openxdata users.
     *
     * @return
     */
    public void setUsers(List<String[]> users) {

        this.users = new ArrayList<Object[]>();

        int i = 0;
        for (Object[] user : users) {
            Integer userId = ++i;
            String name = (String) user[0];
            String password = (String) user[1];
            String salt = (String) user[2];
            String encodedPassword = encoder.encodePassword(password, salt);
            Object[] completeUser = { userId, name, encodedPassword, salt };
            this.users.add(completeUser);
        }
    }

    /**
     * Returns the name of the study for the given id
     */
    public String getStudyName(int id) {
        return studies.get(id);
    }

    /**
     * Returns the list of forms for the specified study.
     */
    public List<String> getStudyForms(int studyId) {
        String studyName = studies.get(studyId);
        List<Integer> forms = studyForms.get(studyName);
        List<String> result = new ArrayList<String>();

        for (Integer formId : forms) {
            result.add(formMap.get(formId));
        }

        return result;
    }

    private class StudyFormsParser {
        private XmlPullParserFactory xmlPullParserFactory;
        private XmlPullParser xmlPullParser;
        private String resource;
        private String studyName;
        private String currentXFormDefinition;
        private static final String xFormTag = "xform";
        private static final String versionTextTag = "versionText";
        private static final String studyTag = "study";
        private boolean isXform;
        private boolean isVersionText;

        public StudyFormsParser(XmlPullParserFactory xmlPullParserFactory, XmlPullParser xmlPullParser,
                String resource) {
            this.xmlPullParserFactory = xmlPullParserFactory;
            this.xmlPullParser = xmlPullParser;
            this.resource = resource;
        }

        public void invoke() throws XmlPullParserException, IOException {
            xmlPullParser.setInput(new InputStreamReader(getClass().getResourceAsStream(resource)));
            for (int eventType = xmlPullParser
                    .getEventType(); eventType != XmlPullParser.END_DOCUMENT; eventType = xmlPullParser.next()) {

                if (eventType == XmlPullParser.START_TAG) {
                    handleStartTag();
                } else if (eventType == XmlPullParser.END_TAG) {
                    handleEndTag();
                } else if (eventType == XmlPullParser.TEXT) {
                    if (isXform) {
                        processXForm();
                    }
                }
            }
        }

        private void processXForm() throws XmlPullParserException, IOException {
            if (isVersionText) {
                Integer formId = extractFormIdFromVersionText(xmlPullParserFactory, xmlPullParser.getText());
                saveFormDetails(formId);
            } else {
                extractXFormDefinition();
            }
        }

        private void extractXFormDefinition() {
            currentXFormDefinition = xmlPullParser.getText();
        }

        private void saveFormDetails(Integer formId) throws XmlPullParserException, IOException {

            if (formId != null && formMap.get(formId) == null) {
                formMap.put(formId, currentXFormDefinition);
                addFormToStudy(formId, studyName);
            }
        }

        private void handleEndTag() {
            if (xFormTag.equals(xmlPullParser.getName())) {
                endXFormTag();
            } else if (versionTextTag.equals(xmlPullParser.getName())) {
                endVersionTextTag();
            }
        }

        private void handleStartTag() {
            if (studyTag.equals(xmlPullParser.getName())) {
                captureStudyDetails(xmlPullParser);
            } else if (xFormTag.equals(xmlPullParser.getName())) {
                startXFormTag();
            } else if (versionTextTag.equals(xmlPullParser.getName())) {
                startVersionTextTag();
            }
        }

        public void startXFormTag() {
            isXform = true;
        }

        public void endXFormTag() {
            isXform = false;
        }

        public void startVersionTextTag() {
            isVersionText = true;
        }

        public void endVersionTextTag() {
            isVersionText = false;
        }

        private void addFormToStudy(Integer formId, String studyName) {
            if (studyForms.get(studyName) != null) {
                studyForms.get(studyName).add(formId);
            }
        }

        private void captureStudyDetails(XmlPullParser xmlPullParser) {
            studyName = getAttributeValue(xmlPullParser, "name");
            studies.add(studyName);
            studyForms.put(studyName, new ArrayList<Integer>());
        }

        private Integer extractFormIdFromVersionText(XmlPullParserFactory xmlPullParserFactory,
                String versionTextXform) throws XmlPullParserException, IOException {
            Integer formId = null;
            XmlPullParser xFormXmlPullParser = xmlPullParserFactory.newPullParser();
            xFormXmlPullParser.setInput(new StringReader(versionTextXform));
            for (int formEvent = xFormXmlPullParser
                    .getEventType(); formEvent != XmlPullParser.END_DOCUMENT; formEvent = xFormXmlPullParser
                            .next()) {
                if (formEvent == XmlPullParser.START_TAG && xFormTag.equals(xFormXmlPullParser.getName())) {
                    String formIdString = getAttributeValue(xFormXmlPullParser, "id");
                    formId = Integer.valueOf(formIdString);
                }
            }
            return formId;
        }

        private String getAttributeValue(XmlPullParser xmlPullParser, String attributeName) {
            return xmlPullParser.getAttributeValue(null, attributeName);
        }
    }
}