package org.activityinfo.server.endpoint.odk; import com.google.common.collect.Sets; import com.google.inject.Inject; import org.activityinfo.model.form.FormClass; import org.activityinfo.model.form.FormField; import org.activityinfo.model.legacy.CuidAdapter; import org.activityinfo.model.resource.ResourceId; import org.activityinfo.model.type.ReferenceType; import org.activityinfo.server.command.ResourceLocatorSync; import javax.inject.Provider; import javax.persistence.EntityManager; import javax.persistence.Tuple; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.StreamingOutput; import java.io.IOException; import java.io.OutputStream; import java.util.List; import java.util.Set; public class ItemSetBuilder { private final ResourceLocatorSync locator; private final Provider<EntityManager> entityManager; @Inject public ItemSetBuilder(ResourceLocatorSync locator, Provider<EntityManager> entityManager) { this.locator = locator; this.entityManager = entityManager; } public StreamingOutput build(ResourceId formClassId) throws IOException { final Set<ResourceId> rangeClassIds = findRanges(formClassId); return new StreamingOutput() { @Override public void write(OutputStream output) throws IOException, WebApplicationException { ItemSetWriter writer = new ItemSetWriter(output); // We need at least one item set or ODK will crash writer.writeItem("__dummy", "dummy", "dummy"); // Write out real item sets for(ResourceId formClassId : rangeClassIds) { writeInstances(formClassId, writer); } writer.flush(); } }; } private Set<ResourceId> findRanges(ResourceId formClassId) { FormClass formClass = locator.getFormClass(formClassId); Set<ResourceId> rangeClassIds = Sets.newHashSet(); for(FormField field : formClass.getFields()) { if(field.getType() instanceof ReferenceType) { rangeClassIds.addAll(((ReferenceType) field.getType()).getRange()); } } return rangeClassIds; } private void writeInstances(ResourceId formClassId, ItemSetWriter writer) throws IOException { String listName = formClassId.asString(); if(formClassId.getDomain() == CuidAdapter.LOCATION_TYPE_DOMAIN) { List<Tuple> instances = entityManager.get().createQuery( "select g.id, g.name from Location g where g.locationType.id = :id", Tuple.class) .setParameter("id", CuidAdapter.getLegacyIdFromCuid(formClassId)) .getResultList(); writer.writeItem(listName, "NEW", "[NEW]"); for(Tuple instance : instances) { String id = CuidAdapter.locationInstanceId(instance.get(0, Integer.class)).asString(); String label = instance.get(1, String.class); writer.writeItem(listName, id, label); } } } }