Details
-
Bug
-
Resolution: Unresolved
-
Major
-
18.4.3, 17.9.0-rc-1
-
Unknown
-
Description
Importing an extension onto an existing extension page aborts with an
{{IllegalArgumentException}}
when that page carries a legacy
{ExtensionCode.ExtensionVersionClass}}
object whose
{{version}}
property is empty. Nothing is imported: the page keeps its old metadata and the extension stays unusable by the Extension Manager.
This affects old, hand-made extension pages created before the Repository Application managed them. They are precisely the pages that most need importing.
Steps to reproduce
1. Take an extension page whose ExtensionCode.ExtensionClass.id is set, and which has an ExtensionCode.ExtensionVersionClass object with an empty version property.
2. Go to ExtensionCode.ImportExtension and import that extension id from a Maven repository.
Reproduced on extensions.xwiki.org (XWiki 18.4.3) with Extension.Skin Extension Plugin, whose legacy version object had every property empty but download.
Actual result
Failed to import extension: java.lang.IllegalArgumentException: An Entity Reference name cannot be null or empty at org.xwiki.model.reference.EntityReference.setName(EntityReference.java:222) at org.xwiki.model.reference.EntityReference.<init>(EntityReference.java:164) at org.xwiki.model.reference.AbstractLocalizedEntityReference.<init>(AbstractLocalizedEntityReference.java:76) at org.xwiki.model.reference.PageReference.<init>(PageReference.java:113) at org.xwiki.model.reference.PageReference.<init>(PageReference.java:101) at org.xwiki.repository.internal.ExtensionStore.getVersionDocument(ExtensionStore.java:503) at org.xwiki.repository.internal.ExtensionStore.getExtensionVersionDocument(ExtensionStore.java:458) at org.xwiki.repository.internal.ExtensionStore.getExtensionVersionDocument(ExtensionStore.java:441) at org.xwiki.repository.internal.RepositoryManager.moveLegacyVersion(RepositoryManager.java:1925) at org.xwiki.repository.internal.RepositoryManager.updateExtensionVersions(RepositoryManager.java:1024)
Expected result
The import succeeds. A version object with a blank version carries no information and should simply be dropped, which is what the code already says it wants to do.
Cause
RepositoryManager.updateExtensionVersions (master, lines 859-872) decides to remove the object
for any of three reasons, one of them being a blank version, and then migrates it to a dedicated
version page whenever version-page mode is on – without re-checking that the version is non-blank:
// Remove the object if: // * versions should be stored in dedicated pages // * the version is blank // * versions should be proxied if (versionPageEnabled || StringUtils.isBlank(version) || (versionProxyEnabled && !new DefaultVersion(version).equals(extension.getId().getVersion()))) { extensionDocument.removeXObject(versionObject); needSave = true; // When moving from legacy storage to dedicated version page storage, we need to migrate the // object and not just deleted it if (versionPageEnabled) { moveLegacyVersion(extensionDocument, versionObject); }
moveLegacyVersion passes that blank version to
ExtensionStore.getVersionDocument, which builds new PageReference(version, ...) and throws.
The two conditions are always both true on a legacy page, because updateExtension calls
extensionStore.setVersionPageEnabled(extensionObject) earlier in the same import – so
versionPageEnabled is on by the time this loop runs, and every blank-version legacy object
hits the failing branch.
Suggested fix
Only migrate an object that has a version to migrate:
if (versionPageEnabled && StringUtils.isNotBlank(version)) {
moveLegacyVersion(extensionDocument, versionObject);
}
A unit test in RepositoryManagerTest covering an extension document that carries a
blank-version legacy version object would lock this in.