Java tutorial
/* * Copyright (C) 2009 Google Inc. * Copyright (C) 2010 University of Washington. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.opendatakit.aggregate.submission; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.opendatakit.aggregate.constants.common.FormElementNamespace; import org.opendatakit.aggregate.datamodel.FormElementModel; import org.opendatakit.aggregate.datamodel.TopLevelDynamicBase; import org.opendatakit.aggregate.exception.ODKFormNotFoundException; import org.opendatakit.aggregate.form.FormFactory; import org.opendatakit.aggregate.form.IForm; import org.opendatakit.aggregate.format.Row; import org.opendatakit.aggregate.format.element.ElementFormatter; import org.opendatakit.aggregate.server.ServerPreferencesProperties; import org.opendatakit.common.datamodel.ODKEnumeratedElementException; import org.opendatakit.common.persistence.Datastore; import org.opendatakit.common.persistence.exception.ODKDatastoreException; import org.opendatakit.common.persistence.exception.ODKEntityNotFoundException; import org.opendatakit.common.security.User; import org.opendatakit.common.web.CallingContext; /** * Defines a form submission that can be converted into a datastore entity. * * @author wbrunette@gmail.com * @author mitchellsundt@gmail.com * */ public class Submission extends SubmissionSet { /** * Construct an empty submission for the given form definition. * * @param modelVersion * @param uiVersion * @param uriTopLevelGroup * -- override the primary key for the top level table. * @param formDefinition * @param submissionDate * @param cc * @throws ODKDatastoreException */ public Submission(Long modelVersion, Long uiVersion, String uriTopLevelGroup, IForm form, Date submissionDate, CallingContext cc) throws ODKDatastoreException { super(modelVersion, uiVersion, uriTopLevelGroup, form, cc); ((TopLevelDynamicBase) getGroupBackingObject()).setSubmissionDate(submissionDate); } /** * Construct a submission from an entity from the data store * * @param submission * - top level entity of the submission to restore * @param formDefinition * - the definition of the form * @param cc * - the CallingContext for this request * @throws ODKDatastoreException */ public Submission(TopLevelDynamicBase submission, IForm form, CallingContext cc) throws ODKDatastoreException { super(null, submission, form.getTopLevelGroupElement(), form, cc); } public Submission(String uri, IForm form, CallingContext cc) throws ODKEntityNotFoundException, ODKDatastoreException { super(null, (TopLevelDynamicBase) cc.getDatastore().getEntity( form.getTopLevelGroupElement().getFormDataModel().getBackingObjectPrototype(), uri, cc.getCurrentUser()), form.getTopLevelGroupElement(), form, cc); } /** * Get the time that the submission was created/received * * @return date of submission */ public Date getSubmissionDate() { return ((TopLevelDynamicBase) getGroupBackingObject()).getSubmissionDate(); } public Long getModelVersion() { return ((TopLevelDynamicBase) getGroupBackingObject()).getModelVersion(); } public Long getUiVersion() { return ((TopLevelDynamicBase) getGroupBackingObject()).getUiVersion(); } public void setIsComplete(Boolean value) { ((TopLevelDynamicBase) getGroupBackingObject()).setIsComplete(value); } public Boolean isComplete() { return ((TopLevelDynamicBase) getGroupBackingObject()).getIsComplete(); } public void setMarkedAsCompleteDate(Date value) { ((TopLevelDynamicBase) getGroupBackingObject()).setMarkedAsCompleteDate(value); } public Date getMarkedAsCompleteDate() { return ((TopLevelDynamicBase) getGroupBackingObject()).getMarkedAsCompleteDate(); } /** * This has 2 modes of operation. (1) If propertyNames is null, then the types * list of FormElementNamespace values is used to render the output. (2) * Otherwise, this works as a two-stage filter. The types list of * FormElementNamespace values is a filter against the list of propertyNames * specified. So if you have an arbitrary list of elements and want only the * metadata elements to be reported, you would pass [ METADATA ] in the types * list. The resulting subset is then rendered (and the resulting row might * have no columns). * * @param types * -- list of e.g., (METADATA, VALUES) to be rendered. * @param propertyNames * -- joint subset of property names to be rendered. * @param elemFormatter * @param includeParentUid * @param cc * @return rendered Row object * @throws ODKDatastoreException */ public Row getFormattedValuesAsRow(List<FormElementNamespace> types, List<FormElementModel> propertyNames, ElementFormatter elemFormatter, boolean includeParentUid, CallingContext cc) throws ODKDatastoreException { if (propertyNames == null) { Row row = new Row(constructSubmissionKey(null)); getFormattedNamespaceValuesForRow(row, types, elemFormatter, includeParentUid, cc); return row; } // otherwise, apply filtering... boolean hasMeta = false; boolean hasValues = false; for (FormElementNamespace type : types) { if (type == FormElementNamespace.METADATA) { hasMeta = true; } else if (type == FormElementNamespace.VALUES) { hasValues = true; } else { throw new IllegalStateException("unexpected FormElementNamespace value " + type.toString()); } } List<FormElementModel> reducedProperties = new ArrayList<FormElementModel>(); for (FormElementModel m : propertyNames) { if (m.isMetadata() && hasMeta) { reducedProperties.add(m); } else if (!m.isMetadata() && hasValues) { reducedProperties.add(m); } } return getFormattedValuesAsRow(reducedProperties, elemFormatter, includeParentUid, cc); } /** * Given the list of FormElementNamespaces to render, this renders the * namespaces in the order given. * * @param row * @param types * @param elemFormatter * @param includeParentUid * @param cc * @throws ODKDatastoreException */ public void getFormattedNamespaceValuesForRow(Row row, List<FormElementNamespace> types, ElementFormatter elemFormatter, boolean includeParentUid, CallingContext cc) throws ODKDatastoreException { List<FormElementModel> elementList = new ArrayList<FormElementModel>(); // get the in-order list of all flattened elements within this submission // set... List<FormElementModel> allElements = getFormElements(); // and now place them in the proper ordering according to the sequence of // types in the types list. for (FormElementNamespace type : types) { if (type == FormElementNamespace.METADATA) { for (FormElementModel m : allElements) { if (m.isMetadata()) { elementList.add(m); } } } else if (type == FormElementNamespace.VALUES) { for (FormElementModel m : allElements) { if (!m.isMetadata()) { elementList.add(m); } } } } populateFormattedValuesInRow(row, elementList, elemFormatter, cc); } public SubmissionElement resolveSubmissionKey(List<SubmissionKeyPart> parts) { if (parts == null || parts.size() == 0) { throw new IllegalArgumentException("submission key is empty"); } if (!parts.get(0).getElementName().equals(getFormId())) { throw new IllegalArgumentException("formId of submissionKey does not match FormId"); } return resolveSubmissionKeyBeginningAt(1, parts); } public static final Submission fetchSubmission(List<SubmissionKeyPart> parts, CallingContext cc) throws ODKFormNotFoundException, ODKDatastoreException { if (parts == null || parts.size() == 0) { throw new IllegalArgumentException("submission key is empty"); } IForm form = FormFactory.retrieveFormByFormId(parts.get(0).getElementName(), cc); if (!form.hasValidFormDefinition()) { throw new IllegalArgumentException("Form definition is ill-formed"); // ill-formed // definition } if (parts.size() < 2) { throw new IllegalArgumentException("submission key does not have a top level group"); } SubmissionKeyPart tlg = parts.get(1); if (!form.getTopLevelGroupElement().getElementName().equals(tlg.getElementName())) { throw new IllegalArgumentException("top level group name: " + tlg.getElementName() + " is not as expected: " + form.getTopLevelGroupElement().getElementName()); } if (tlg.getAuri() == null) { throw new IllegalArgumentException("submission key does not have top level auri"); } Datastore ds = cc.getDatastore(); User user = cc.getCurrentUser(); TopLevelDynamicBase tle = (TopLevelDynamicBase) ds.getEntity( form.getTopLevelGroupElement().getFormDataModel().getBackingObjectPrototype(), tlg.getAuri(), user); try { return new Submission(tle, form, cc); } catch (ODKDatastoreException e) { Log logger = LogFactory.getLog(Submission.class); e.printStackTrace(); logger.error("Unable to reconstruct submission for " + tle.getSchemaName() + "." + tle.getTableName() + " uri " + tle.getUri()); if ((e instanceof ODKEntityNotFoundException) || (e instanceof ODKEnumeratedElementException)) { // see if we should throw an error or skip processing... Boolean skip = ServerPreferencesProperties.getSkipMalformedSubmissions(cc); if (skip) { return null; } else { throw e; } } else { throw e; } } } public static final TopLevelDynamicBase fetchTopLevelSubmissionObject(List<SubmissionKeyPart> parts, CallingContext cc) throws ODKFormNotFoundException, ODKDatastoreException { if (parts == null || parts.size() == 0) { throw new IllegalArgumentException("submission key is empty"); } IForm form = FormFactory.retrieveFormByFormId(parts.get(0).getElementName(), cc); if (!form.hasValidFormDefinition()) { throw new IllegalArgumentException("Form definition is ill-formed"); // ill-formed // definition } if (parts.size() < 2) { throw new IllegalArgumentException("submission key does not have a top level group"); } SubmissionKeyPart tlg = parts.get(1); if (!form.getTopLevelGroupElement().getElementName().equals(tlg.getElementName())) { throw new IllegalArgumentException("top level group name: " + tlg.getElementName() + " is not as expected: " + form.getTopLevelGroupElement().getElementName()); } if (tlg.getAuri() == null) { throw new IllegalArgumentException("submission key does not have top level auri"); } Datastore ds = cc.getDatastore(); User user = cc.getCurrentUser(); TopLevelDynamicBase tle = (TopLevelDynamicBase) ds.getEntity( form.getTopLevelGroupElement().getFormDataModel().getBackingObjectPrototype(), tlg.getAuri(), user); return tle; } }