Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,31 @@
*/
public class MissingMediaException extends Exception {
final Resource r;
final boolean userFacing;
String URI;
private final MissingMediaExceptionType type;
private String URI;

public MissingMediaException(Resource r, String message) {
this(r, message, message, false);
public enum MissingMediaExceptionType {
FILE_NOT_FOUND,
FILE_NOT_ACCESSIBLE,
INVALID_REFERENCE,
NONE
}

public MissingMediaException(Resource r, String message, String uri) {
this(r, message, uri, false);
public MissingMediaException(Resource r, String message, MissingMediaExceptionType mediaExceptionType) {
this(r, message, message, mediaExceptionType);
}

public MissingMediaException(Resource r, String message, boolean userFacing) {
public MissingMediaException(Resource r, String message, String uri, MissingMediaExceptionType mediaExceptionType) {
super(message);
this.r = r;
this.userFacing = userFacing;
}

public MissingMediaException(Resource r, String message, String uri, boolean userFacing) {
this(r, message, userFacing);
URI = uri;
this.r = r;
this.type = mediaExceptionType;
}

public Resource getResource() {
return r;
}

public boolean isMessageUseful() {
return userFacing;
}

public String getURI() {
return URI;
}
Expand All @@ -58,6 +53,9 @@ public boolean equals(Object obj) {

public String toString() {
return URI;
}

public MissingMediaExceptionType getType() {
return type;
}
}
40 changes: 31 additions & 9 deletions src/main/java/org/commcare/resources/model/Resource.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ public class Resource implements Persistable, IMetaData {
public static final String META_INDEX_RESOURCE_GUID = "RGUID";
public static final String META_INDEX_PARENT_GUID = "PGUID";
public static final String META_INDEX_VERSION = "VERSION";
public static final String META_INDEX_LAZY = "LAZY";

public static final String LAZY_VAL_TRUE = "true";
public static final String LAZY_VAL_FALSE = "false";

public static final int RESOURCE_AUTHORITY_LOCAL = 0;
public static final int RESOURCE_AUTHORITY_REMOTE = 1;
Expand Down Expand Up @@ -111,7 +115,8 @@ public class Resource implements Persistable, IMetaData {
// Not sure if we want this persisted just yet...
protected String parent;

private String descriptor;
protected String descriptor;
private String lazy;

/**
* For serialization only
Expand All @@ -124,19 +129,24 @@ public Resource() {
* Creates a resource record identifying where a specific version of a resource
* can be located.
*
* @param version The version of the resource being defined.
* @param id A unique string identifying the abstract resource
* @param locations A set of locations from which this resource's definition
* can be retrieved. Note that this vector is copied and should not be changed
* after being passed in here.
* @param version The version of the resource being defined.
* @param id A unique string identifying the abstract resource
* @param locations A set of locations from which this resource's definition
* can be retrieved. Note that this vector is copied and should not be changed
* after being passed in here.
*/
public Resource(int version, String id, Vector<ResourceLocation> locations, String descriptor) {
public Resource(int version, String id, Vector<ResourceLocation> locations, String descriptor, String lazy) {
this.version = version;
this.id = id;
this.locations = locations;
this.guid = PropertyUtils.genGUID(25);
this.status = RESOURCE_STATUS_UNINITIALIZED;
this.descriptor = descriptor;
this.lazy = lazy;
}

public Resource(int version, String id, Vector<ResourceLocation> locations, String descriptor) {
this(version, id, locations, descriptor, LAZY_VAL_FALSE);
}

/**
Expand Down Expand Up @@ -168,6 +178,10 @@ public String getRecordGuid() {
return guid;
}

public void setRecordGuid(String guid) {
this.guid = guid;
}

/**
* @param parent The GUID of the resource record which has made this resource relevant
* for installation. This method should only be called by a resource table committing
Expand Down Expand Up @@ -230,7 +244,7 @@ public ResourceInstaller getInstaller() {
* @param status The current status of this resource. Should only be called by the resource
* table.
*/
protected void setStatus(int status) {
public void setStatus(int status) {
this.status = status;
}

Expand All @@ -244,6 +258,10 @@ public void setID(int ID) {
recordId = ID;
}

public boolean isLazy() {
return lazy.contentEquals(LAZY_VAL_TRUE);
}

/**
* @param peer A resource record which defines the same resource as this record.
* @return True if this record defines a newer version of the same resource as
Expand Down Expand Up @@ -288,6 +306,7 @@ public void readExternal(DataInputStream in, PrototypeFactory pf) throws IOExcep
locations = (Vector<ResourceLocation>)ExtUtil.read(in, new ExtWrapList(ResourceLocation.class), pf);
this.initializer = (ResourceInstaller)ExtUtil.read(in, new ExtWrapTagged(), pf);
this.descriptor = ExtUtil.nullIfEmpty(ExtUtil.readString(in));
this.lazy = ExtUtil.readString(in);
}

@Override
Expand All @@ -302,6 +321,7 @@ public void writeExternal(DataOutputStream out) throws IOException {
ExtUtil.write(out, new ExtWrapList(locations));
ExtUtil.write(out, new ExtWrapTagged(initializer));
ExtUtil.writeString(out, ExtUtil.emptyIfNull(descriptor));
ExtUtil.writeString(out, lazy);
}

@Override
Expand All @@ -315,13 +335,15 @@ public Object getMetaData(String fieldName) {
return parent == null ? "" : parent;
case META_INDEX_VERSION:
return version;
case META_INDEX_LAZY:
return lazy;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little surprised to see this works with a boolean, btw. My intuition is that we should hard code an explicit string value here, and convert it to/from boolean. We've started making soft assumptions elsewhere that all metadata values are strings, and I'm worried that implicit conversions.

}
throw new IllegalArgumentException("No Field w/name " + fieldName + " is relevant for resources");
}

@Override
public String[] getMetaDataFields() {
return new String[]{META_INDEX_RESOURCE_ID, META_INDEX_RESOURCE_GUID, META_INDEX_PARENT_GUID, META_INDEX_VERSION};
return new String[]{META_INDEX_RESOURCE_ID, META_INDEX_RESOURCE_GUID, META_INDEX_PARENT_GUID, META_INDEX_VERSION, META_INDEX_LAZY};
}

public boolean isDirty() {
Expand Down
49 changes: 41 additions & 8 deletions src/main/java/org/commcare/resources/model/ResourceTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

import javax.annotation.Nullable;

import static org.commcare.resources.model.Resource.LAZY_VAL_TRUE;


/**
* A Resource Table maintains a set of Resource Records,
Expand Down Expand Up @@ -211,6 +213,14 @@ public Resource getResourceWithGuid(String guid) {
}
}

public Resource getResource(int rowId) {
try {
return (Resource)storage.read(rowId);
} catch (NoSuchElementException nsee) {
return null;
}
}

private Resource getParentResource(Resource resource) {
String parentId = resource.getParentId();
if (parentId != null && !"".equals(parentId)) {
Expand Down Expand Up @@ -1002,7 +1012,7 @@ private static Vector<Reference> gatherResourcesLocalRefs(Resource r,
private static Vector<Reference> gatherLocationsRefs(ResourceLocation location,
Resource r,
ResourceTable t,
ResourceTable m) {
@Nullable ResourceTable m) {
Vector<Reference> ret = new Vector<>();

if (r.hasParent()) {
Expand Down Expand Up @@ -1131,16 +1141,20 @@ public void setInstallStatsLogger(InstallStatsLogger logger) {
this.installStatsLogger = logger;
}

public boolean recoverResources(CommCarePlatform platform, String profileRef) throws InstallCancelledException, UnresolvedResourceException, UnfullfilledRequirementsException {
public boolean recoverResources(CommCarePlatform platform, String profileRef)
throws InstallCancelledException, UnresolvedResourceException, UnfullfilledRequirementsException {
return recoverResources(platform, profileRef, mMissingResources);
}

// Downloads and re-installs the missingResources into the table
public boolean recoverResources(CommCarePlatform platform, String profileRef, Vector<Resource> missingResources)
throws InstallCancelledException, UnresolvedResourceException, UnfullfilledRequirementsException {
int count = 0;
int total = mMissingResources.size();
for (Resource missingResource : mMissingResources) {
int total = missingResources.size();
for (Resource missingResource : missingResources) {

if (missingResource.id.contentEquals(CommCarePlatform.APP_PROFILE_RESOURCE_ID)) {
addRemoteLocationIfMissing(missingResource, profileRef);
}
recoverResource(missingResource, platform, profileRef);

findResourceLocationAndInstall(missingResource, new Vector<>(), false, platform, null, true);
count++;

if (stateListener != null) {
Expand All @@ -1154,6 +1168,17 @@ public boolean recoverResources(CommCarePlatform platform, String profileRef) th
return true;
}

// Downloads and re-installs a missing resource
public void recoverResource(Resource missingResource, CommCarePlatform platform, String profileRef)
throws InstallCancelledException, UnresolvedResourceException, UnfullfilledRequirementsException {

if (missingResource.id.contentEquals(CommCarePlatform.APP_PROFILE_RESOURCE_ID)) {
addRemoteLocationIfMissing(missingResource, profileRef);
}

findResourceLocationAndInstall(missingResource, new Vector<>(), false, platform, null, true);
}

private void addRemoteLocationIfMissing(Resource resource, String remoteLocation) {
Vector<ResourceLocation> locations = resource.getLocations();
boolean remoteLocationPresent = false;
Expand All @@ -1175,4 +1200,12 @@ public void setMissingResources(SizeBoundUniqueVector<Resource> missingResources
public SizeBoundUniqueVector<Resource> getMissingResources() {
return mMissingResources;
}

public Vector<Resource> getLazyResources() {
return storage.getRecordsForValues(new String[]{Resource.META_INDEX_LAZY}, new String[]{LAZY_VAL_TRUE});
}

public Vector<Integer> getLazyResourceIds() {
return storage.getIDsForValue(Resource.META_INDEX_LAZY, LAZY_VAL_TRUE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ public static void checkMedia(Resource r, String filePath, SizeBoundUniqueVector
boolean successfulAdd;
try {
if (!ref.doesBinaryExist()) {
successfulAdd = problems.add(new MissingMediaException(r, "Missing external media: " + localName, filePath));
successfulAdd = problems.add(new MissingMediaException(r, "Missing external media: " + localName, filePath,
MissingMediaException.MissingMediaExceptionType.FILE_NOT_FOUND));
if (successfulAdd) {

switch (mt) {
Expand All @@ -44,7 +45,8 @@ public static void checkMedia(Resource r, String filePath, SizeBoundUniqueVector
}
}
} catch (IOException e) {
problems.addElement(new MissingMediaException(r, "Problem reading external media: " + localName, filePath));
problems.addElement(new MissingMediaException(r, "Problem reading external media: " + localName, filePath,
MissingMediaException.MissingMediaExceptionType.FILE_NOT_ACCESSIBLE));
}
} catch (InvalidReferenceException e) {
//So the problem is that this might be a valid entry that depends on context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,20 +282,24 @@ public void writeExternal(DataOutputStream out) throws IOException {
public boolean verifyInstallation(Resource r, Vector<MissingMediaException> problems, CommCarePlatform platform) {
try {
if (locale == null) {
problems.addElement(new MissingMediaException(r, "Bad metadata, no locale"));
problems.addElement(new MissingMediaException(r, "Bad metadata, no locale",
MissingMediaException.MissingMediaExceptionType.NONE));
return true;
}
if (cache != null) {
//If we've gotten the cache into memory, we're fine
} else {
try {
if (!ReferenceManager.instance().DeriveReference(localReference).doesBinaryExist()) {
throw new MissingMediaException(r, "Locale data does note exist at: " + localReference);
throw new MissingMediaException(r, "Locale data does note exist at: " + localReference, localReference,
MissingMediaException.MissingMediaExceptionType.FILE_NOT_FOUND);
}
} catch (IOException e) {
throw new MissingMediaException(r, "Problem reading locale data from: " + localReference);
throw new MissingMediaException(r, "Problem reading locale data from: " + localReference, localReference,
MissingMediaException.MissingMediaExceptionType.FILE_NOT_ACCESSIBLE);
} catch (InvalidReferenceException e) {
throw new MissingMediaException(r, "Locale reference is invalid: " + localReference);
throw new MissingMediaException(r, "Locale reference is invalid: " + localReference, localReference,
MissingMediaException.MissingMediaExceptionType.INVALID_REFERENCE);
}
}
} catch (MissingMediaException ure) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import org.commcare.suite.model.Suite;
import org.commcare.util.CommCarePlatform;
import org.commcare.xml.SuiteParser;
import org.javarosa.core.model.instance.FormInstance;
import org.javarosa.core.reference.InvalidReferenceException;
import org.javarosa.core.reference.Reference;
import org.javarosa.core.services.locale.Localization;
Expand Down Expand Up @@ -102,7 +101,8 @@ public boolean verifyInstallation(Resource r, Vector<MissingMediaException> prob
suite = storage(platform).read(cacheLocation);
} catch (Exception e) {
e.printStackTrace();
sizeBoundProblems.addElement(new MissingMediaException(r, "Suite did not properly save into persistent storage"));
sizeBoundProblems.addElement(new MissingMediaException(r, "Suite did not properly save into persistent storage",
MissingMediaException.MissingMediaExceptionType.NONE));
return true;
}
//Otherwise, we want to figure out if the form has media, and we need to see whether it's properly
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ public boolean verifyInstallation(Resource r, Vector<MissingMediaException> prob
try {
formDef = storage(platform).read(cacheLocation);
} catch (Exception e) {
sizeBoundProblems.addElement(new MissingMediaException(r, "Form did not properly save into persistent storage"));
sizeBoundProblems.addElement(new MissingMediaException(r, "Form did not properly save into persistent storage",
MissingMediaException.MissingMediaExceptionType.NONE));
return true;
}
//Otherwise, we want to figure out if the form has media, and we need to see whether it's properly
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/org/commcare/xml/ResourceParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import java.io.IOException;
import java.util.Vector;

import static org.commcare.resources.model.Resource.LAZY_VAL_FALSE;

public class ResourceParser extends ElementParser<Resource> {

final int maximumAuthority;
Expand All @@ -27,6 +29,7 @@ public Resource parse() throws InvalidStructureException, IOException, XmlPullPa
int version = parseInt(parser.getAttributeValue(null, "version"));

String descriptor = parser.getAttributeValue(null, "descriptor");
String lazy = parser.getAttributeValue(null, "lazy");

Vector<ResourceLocation> locations = new Vector<>();

Expand All @@ -46,6 +49,6 @@ public Resource parse() throws InvalidStructureException, IOException, XmlPullPa
}
}

return new Resource(version, id, locations, descriptor);
return new Resource(version, id, locations, descriptor, lazy == null ? LAZY_VAL_FALSE : lazy);
}
}
Loading