Search in sources :

Example 1 with ExternalDataException

use of org.odk.collect.android.exception.ExternalDataException in project collect by opendatakit.

the class ExternalDataHandlerSearch method eval.

@Override
public Object eval(Object[] args, EvaluationContext ec) {
    if (args == null || (args.length != 1 && args.length != 4 && args.length != 6)) {
        // .getSearchXPathExpression(String appearance)
        throw new ExternalDataException(Collect.getInstance().getString(R.string.ext_search_wrong_arguments_error));
    }
    String searchType = null;
    String queriedColumnsParam = null;
    List<String> queriedColumns = null;
    String queriedValue = null;
    if (args.length >= 4) {
        searchType = XPathFuncExpr.toString(args[1]);
        queriedColumnsParam = XPathFuncExpr.toString(args[2]);
        queriedValue = XPathFuncExpr.toString(args[3]);
    }
    ExternalDataSearchType externalDataSearchType = ExternalDataSearchType.getByKeyword(searchType, ExternalDataSearchType.CONTAINS);
    boolean searchRows = false;
    boolean useFilter = false;
    if (queriedColumnsParam != null && queriedColumnsParam.trim().length() > 0) {
        searchRows = true;
        queriedColumns = ExternalDataUtil.createListOfColumns(queriedColumnsParam);
    }
    String filterColumn = null;
    String filterValue = null;
    if (args.length == 6) {
        filterColumn = XPathFuncExpr.toString(args[4]);
        filterValue = XPathFuncExpr.toString(args[5]);
        useFilter = true;
    }
    // SCTO-545
    String dataSetName = normalize(XPathFuncExpr.toString(args[0]));
    Cursor c = null;
    try {
        ExternalSQLiteOpenHelper sqLiteOpenHelper = getExternalDataManager().getDatabase(dataSetName, true);
        SQLiteDatabase db = sqLiteOpenHelper.getReadableDatabase();
        LinkedHashMap<String, String> selectColumnMap = ExternalDataUtil.createMapWithDisplayingColumns(getValueColumn(), getDisplayColumns());
        List<String> columnsToFetch = new ArrayList<String>(selectColumnMap.keySet());
        String safeImageColumn = null;
        if (getImageColumn() != null && getImageColumn().trim().length() > 0) {
            safeImageColumn = ExternalDataUtil.toSafeColumnName(getImageColumn());
            columnsToFetch.add(safeImageColumn);
        }
        String[] sqlColumns = columnsToFetch.toArray(new String[columnsToFetch.size()]);
        String selection;
        String[] selectionArgs;
        if (searchRows && useFilter) {
            selection = "( " + createLikeExpression(queriedColumns) + " ) AND " + ExternalDataUtil.toSafeColumnName(filterColumn) + "=? ";
            String[] likeArgs = externalDataSearchType.constructLikeArguments(queriedValue, queriedColumns.size());
            selectionArgs = new String[likeArgs.length + 1];
            System.arraycopy(likeArgs, 0, selectionArgs, 0, likeArgs.length);
            selectionArgs[selectionArgs.length - 1] = filterValue;
        } else if (searchRows) {
            selection = createLikeExpression(queriedColumns);
            selectionArgs = externalDataSearchType.constructLikeArguments(queriedValue, queriedColumns.size());
        } else if (useFilter) {
            selection = ExternalDataUtil.toSafeColumnName(filterColumn) + "=? ";
            selectionArgs = new String[] { filterValue };
        } else {
            selection = null;
            selectionArgs = null;
        }
        try {
            c = db.query(ExternalDataUtil.EXTERNAL_DATA_TABLE_NAME, sqlColumns, selection, selectionArgs, null, null, ExternalDataUtil.SORT_COLUMN_NAME);
        } catch (Exception e) {
            if (c != null) {
                c.close();
            }
            c = db.query(ExternalDataUtil.EXTERNAL_DATA_TABLE_NAME, sqlColumns, selection, selectionArgs, null, null, null);
        }
        return createDynamicSelectChoices(c, selectColumnMap, safeImageColumn);
    } finally {
        if (c != null) {
            c.close();
        }
    }
}
Also used : SQLiteDatabase(android.database.sqlite.SQLiteDatabase) ExternalSQLiteOpenHelper(org.odk.collect.android.external.ExternalSQLiteOpenHelper) ArrayList(java.util.ArrayList) ExternalDataException(org.odk.collect.android.exception.ExternalDataException) Cursor(android.database.Cursor) ExternalDataException(org.odk.collect.android.exception.ExternalDataException)

Example 2 with ExternalDataException

use of org.odk.collect.android.exception.ExternalDataException in project collect by opendatakit.

the class ExternalDataManagerImpl method getDatabase.

@Override
public ExternalSQLiteOpenHelper getDatabase(String dataSetName, boolean required) {
    ExternalSQLiteOpenHelper sqLiteOpenHelper = dbMap.get(dataSetName);
    if (sqLiteOpenHelper == null) {
        if (mediaFolder == null) {
            String msg = Collect.getInstance().getString(R.string.ext_not_initialized_error);
            Timber.e(msg);
            if (required) {
                throw new ExternalDataException(msg);
            } else {
                return null;
            }
        } else {
            File dbFile = new File(mediaFolder, dataSetName + ".db");
            if (!dbFile.exists()) {
                String msg = Collect.getInstance().getString(R.string.ext_import_csv_missing_error, dataSetName, dataSetName);
                Timber.e(msg);
                if (required) {
                    throw new ExternalDataException(msg);
                } else {
                    return null;
                }
            } else {
                sqLiteOpenHelper = new ExternalSQLiteOpenHelper(dbFile);
                dbMap.put(dataSetName, sqLiteOpenHelper);
            }
        }
    }
    return sqLiteOpenHelper;
}
Also used : ExternalDataException(org.odk.collect.android.exception.ExternalDataException) File(java.io.File)

Example 3 with ExternalDataException

use of org.odk.collect.android.exception.ExternalDataException in project collect by opendatakit.

the class ExternalDataUtil method populateExternalChoices.

public static ArrayList<SelectChoice> populateExternalChoices(FormEntryPrompt formEntryPrompt, XPathFuncExpr xpathfuncexpr) {
    try {
        List<SelectChoice> selectChoices = formEntryPrompt.getSelectChoices();
        ArrayList<SelectChoice> returnedChoices = new ArrayList<SelectChoice>();
        for (SelectChoice selectChoice : selectChoices) {
            String value = selectChoice.getValue();
            if (isAnInteger(value)) {
                // treat this as a static choice
                returnedChoices.add(selectChoice);
            } else {
                String displayColumns = formEntryPrompt.getSelectChoiceText(selectChoice);
                String imageColumn = formEntryPrompt.getSpecialFormSelectChoiceText(selectChoice, FormEntryCaption.TEXT_FORM_IMAGE);
                if (imageColumn != null && imageColumn.startsWith(JR_IMAGES_PREFIX)) {
                    imageColumn = imageColumn.substring(JR_IMAGES_PREFIX.length());
                }
                // if (displayColumns == null || displayColumns.trim().length() == 0) {
                // throw new InvalidSyntaxException("The label column in the choices sheet
                // appears to be empty (or has been calculated as empty).");
                // }
                ExternalDataManager externalDataManager = Collect.getInstance().getExternalDataManager();
                FormInstance formInstance = Collect.getInstance().getFormController().getFormDef().getInstance();
                EvaluationContext baseEvaluationContext = new EvaluationContext(formInstance);
                EvaluationContext evaluationContext = new EvaluationContext(baseEvaluationContext, formEntryPrompt.getIndex().getReference());
                // we can only add only the appropriate by querying the xPathFuncExpr.id.name
                evaluationContext.addFunctionHandler(new ExternalDataHandlerSearch(externalDataManager, displayColumns, value, imageColumn));
                Object eval = xpathfuncexpr.eval(formInstance, evaluationContext);
                if (eval.getClass().isAssignableFrom(ArrayList.class)) {
                    @SuppressWarnings("unchecked") List<SelectChoice> dynamicChoices = (ArrayList<SelectChoice>) eval;
                    for (SelectChoice dynamicChoice : dynamicChoices) {
                        returnedChoices.add(dynamicChoice);
                    }
                } else {
                    throw new ExternalDataException(Collect.getInstance().getString(R.string.ext_search_return_error, eval.getClass().getName()));
                }
            }
        }
        return returnedChoices;
    } catch (Exception e) {
        throw new ExternalDataException(e.getMessage(), e);
    }
}
Also used : SelectChoice(org.javarosa.core.model.SelectChoice) ArrayList(java.util.ArrayList) ExternalDataException(org.odk.collect.android.exception.ExternalDataException) ExternalDataHandlerSearch(org.odk.collect.android.external.handler.ExternalDataHandlerSearch) XPathSyntaxException(org.javarosa.xpath.parser.XPathSyntaxException) ExternalDataException(org.odk.collect.android.exception.ExternalDataException) EvaluationContext(org.javarosa.core.model.condition.EvaluationContext) FormInstance(org.javarosa.core.model.instance.FormInstance)

Example 4 with ExternalDataException

use of org.odk.collect.android.exception.ExternalDataException in project collect by opendatakit.

the class ExternalSQLiteOpenHelper method onCreateNamed.

private void onCreateNamed(SQLiteDatabase db, String tableName) throws Exception {
    Timber.w("Reading data from '%s", dataSetFile.toString());
    onProgress(Collect.getInstance().getString(R.string.ext_import_progress_message, dataSetFile.getName(), ""));
    CSVReader reader = null;
    try {
        reader = new CSVReader(new InputStreamReader(new FileInputStream(dataSetFile), "UTF-8"), DELIMITING_CHAR, QUOTE_CHAR, ESCAPE_CHAR);
        String[] headerRow = reader.readNext();
        if (!ExternalDataUtil.containsAnyData(headerRow)) {
            throw new ExternalDataException(Collect.getInstance().getString(R.string.ext_file_no_data_error));
        }
        List<String> conflictingColumns = ExternalDataUtil.findMatchingColumnsAfterSafeningNames(headerRow);
        if (conflictingColumns != null && conflictingColumns.size() > 0) {
            // so the create table query will fail with "duplicate column" error.
            throw new ExternalDataException(Collect.getInstance().getString(R.string.ext_conflicting_columns_error, conflictingColumns));
        }
        Map<String, String> columnNamesCache = new HashMap<String, String>();
        StringBuilder sb = new StringBuilder();
        boolean sortColumnAlreadyPresent = false;
        sb.append("CREATE TABLE ");
        sb.append(tableName);
        sb.append(" ( ");
        for (int i = 0; i < headerRow.length; i++) {
            String columnName = headerRow[i].trim();
            if (columnName.length() == 0) {
                continue;
            }
            if (i != 0) {
                sb.append(", ");
            }
            String safeColumnName = ExternalDataUtil.toSafeColumnName(columnName, columnNamesCache);
            if (safeColumnName.equals(ExternalDataUtil.SORT_COLUMN_NAME)) {
                sortColumnAlreadyPresent = true;
                sb.append(safeColumnName).append(" real ");
            } else {
                sb.append(safeColumnName).append(" text collate nocase ");
            }
        }
        if (!sortColumnAlreadyPresent) {
            sb.append(", ");
            sb.append(ExternalDataUtil.SORT_COLUMN_NAME).append(" real ");
        }
        sb.append(" );");
        String sql = sb.toString();
        Timber.w("Creating database for %s with query: %s", dataSetFile, sql);
        db.execSQL(sql);
        // create the indexes.
        // save the sql for later because inserts will be much faster if we don't have
        // indexes already.
        List<String> createIndexesCommands = new ArrayList<String>();
        for (String header : headerRow) {
            if (header.endsWith("_key")) {
                String indexSQL = "CREATE INDEX " + header + "_idx ON " + tableName + " (" + ExternalDataUtil.toSafeColumnName(header, columnNamesCache) + ");";
                createIndexesCommands.add(indexSQL);
                Timber.w("Will create an index on %s later.", header);
            }
        }
        // populate the database
        String[] row = reader.readNext();
        int rowCount = 0;
        while (row != null && !formLoaderTask.isCancelled()) {
            // SCTO-894 - first we should make sure that this is not an empty line
            if (!ExternalDataUtil.containsAnyData(row)) {
                // yes, that is an empty row, ignore it
                row = reader.readNext();
                continue;
            }
            // we will just fill up the rest with empty strings
            if (row.length < headerRow.length) {
                row = ExternalDataUtil.fillUpNullValues(row, headerRow);
            }
            ContentValues values = new ContentValues();
            if (!sortColumnAlreadyPresent) {
                values.put(ExternalDataUtil.SORT_COLUMN_NAME, rowCount + 1);
            }
            for (int i = 0; i < row.length && i < headerRow.length; i++) {
                String columnName = headerRow[i].trim();
                String columnValue = row[i];
                if (columnName.length() == 0) {
                    continue;
                }
                String safeColumnName = ExternalDataUtil.toSafeColumnName(columnName, columnNamesCache);
                if (safeColumnName.equals(ExternalDataUtil.SORT_COLUMN_NAME)) {
                    try {
                        values.put(safeColumnName, Double.parseDouble(columnValue));
                    } catch (NumberFormatException e) {
                        throw new ExternalDataException(Collect.getInstance().getString(R.string.ext_sortBy_numeric_error, columnValue));
                    }
                } else {
                    values.put(safeColumnName, columnValue);
                }
            }
            db.insertOrThrow(tableName, null, values);
            row = reader.readNext();
            rowCount++;
            if (rowCount % 100 == 0) {
                onProgress(Collect.getInstance().getString(R.string.ext_import_progress_message, dataSetFile.getName(), " (" + rowCount + " records so far)"));
            }
        }
        if (formLoaderTask.isCancelled()) {
            Timber.w("User canceled reading data from %s", dataSetFile.toString());
            onProgress(Collect.getInstance().getString(R.string.ext_import_cancelled_message));
        } else {
            onProgress(Collect.getInstance().getString(R.string.ext_import_finalizing_message));
            // now create the indexes
            for (String createIndexCommand : createIndexesCommands) {
                Timber.w(createIndexCommand);
                db.execSQL(createIndexCommand);
            }
            Timber.w("Read all data from %s", dataSetFile.toString());
            onProgress(Collect.getInstance().getString(R.string.ext_import_completed_message));
        }
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                Timber.e(e);
            }
        }
    }
}
Also used : ContentValues(android.content.ContentValues) InputStreamReader(java.io.InputStreamReader) CSVReader(au.com.bytecode.opencsv.CSVReader) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ExternalDataException(org.odk.collect.android.exception.ExternalDataException) IOException(java.io.IOException) FileInputStream(java.io.FileInputStream)

Aggregations

ExternalDataException (org.odk.collect.android.exception.ExternalDataException)4 ArrayList (java.util.ArrayList)3 ContentValues (android.content.ContentValues)1 Cursor (android.database.Cursor)1 SQLiteDatabase (android.database.sqlite.SQLiteDatabase)1 CSVReader (au.com.bytecode.opencsv.CSVReader)1 File (java.io.File)1 FileInputStream (java.io.FileInputStream)1 IOException (java.io.IOException)1 InputStreamReader (java.io.InputStreamReader)1 HashMap (java.util.HashMap)1 SelectChoice (org.javarosa.core.model.SelectChoice)1 EvaluationContext (org.javarosa.core.model.condition.EvaluationContext)1 FormInstance (org.javarosa.core.model.instance.FormInstance)1 XPathSyntaxException (org.javarosa.xpath.parser.XPathSyntaxException)1 ExternalSQLiteOpenHelper (org.odk.collect.android.external.ExternalSQLiteOpenHelper)1 ExternalDataHandlerSearch (org.odk.collect.android.external.handler.ExternalDataHandlerSearch)1