@@ -0,0 +1,1914 @@
+package org.akvo.gae.remoteapi;%0A%0Aimport java.util.ArrayList;%0Aimport java.util.HashMap;%0Aimport java.util.List;%0Aimport java.util.Map;%0A%0Aimport com.google.appengine.api.datastore.DatastoreService;%0Aimport com.google.appengine.api.datastore.Entity;%0Aimport com.google.appengine.api.datastore.FetchOptions;%0Aimport com.google.appengine.api.datastore.Query;%0A%0Apublic class CheckParentPath implements Process %7B%0A%0A    private static final String SURVEY_GROUP = %22SurveyGroup%22;%0A%0A    @Override%0A    public void execute(DatastoreService ds, String%5B%5D args) throws Exception %7B%0A%0A        final List%3CEntity%3E surveyGroups = ds.prepare(new Query(SURVEY_GROUP))%0A                .asList(FetchOptions.Builder.withDefaults());%0A%0A        Map%3CLong, Long%3E idToParentId = new HashMap%3C%3E();%0A%0A        for (Entity entity : surveyGroups) %7B%0A            Long parentId = (Long) entity.getProperty(%22parentId%22);%0A            parentId = parentId == null ? 0L : parentId;%0A            idToParentId.put(entity.getKey().getId(), parentId);%0A        %7D%0A%0A        for (Long id : idToParentId.keySet()) %7B%0A            List%3CLong%3E parentPath = new ArrayList%3C%3E();%0A            checkParentPath(idToParentId, parentPath, id);%0A        %7D%0A    %7D%0A%0A    private static final String MISSING_PARENT = %22Missing parent for #%25s (chain: %25s)%5Cn%22;%0A    private static final String PATH_LOOP = %22Path loop for #%25s with parentId #%25s and chain %25s%5Cn%22;%0A%0A    private static void checkParentPath(final Map%3CLong, Long%3E idToParentId,%0A            List%3CLong%3E parentPath, final Long id) %7B%0A        Long parentId = idToParentId.get(id);%0A        if (parentId == null) %7B%0A            System.out.printf(MISSING_PARENT, id, parentPath);%0A        %7D else if (parentPath.contains(parentId)) %7B%0A            System.out.printf(PATH_LOOP, id, parentId, parentPath);%0A        %7D else if (parentId != 0L) %7B%0A            parentPath.add(parentId);%0A            checkParentPath(idToParentId, parentPath, parentId);%0A        %7D%0A    %7D%0A%7D%0A

Check parent path loops datascript