diff --git a/pom.xml b/pom.xml
index 1b0abe5c24ef..a49e3621496c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -128,6 +128,7 @@
10.17.1
+ https://github.com/${xwiki.github.owner}/${xwiki.github.repository}/tree/master/
HEAD
diff --git a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/ExtensionStore.java b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/ExtensionStore.java
index 3c08accd77cb..353ade71e4e9 100644
--- a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/ExtensionStore.java
+++ b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/ExtensionStore.java
@@ -22,28 +22,56 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
+import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
+import org.xwiki.cache.Cache;
+import org.xwiki.cache.CacheException;
+import org.xwiki.cache.CacheManager;
+import org.xwiki.cache.config.CacheConfiguration;
+import org.xwiki.cache.eviction.LRUEvictionConfiguration;
import org.xwiki.component.annotation.Component;
+import org.xwiki.component.manager.ComponentLifecycleException;
+import org.xwiki.component.phase.Disposable;
+import org.xwiki.component.phase.Initializable;
+import org.xwiki.component.phase.InitializationException;
import org.xwiki.extension.DefaultExtensionSupportPlan;
import org.xwiki.extension.DefaultExtensionSupportPlans;
import org.xwiki.extension.DefaultExtensionSupporter;
+import org.xwiki.extension.Extension;
import org.xwiki.extension.ExtensionSupportPlan;
import org.xwiki.extension.ExtensionSupportPlans;
import org.xwiki.extension.ExtensionSupporter;
+import org.xwiki.extension.version.Version;
+import org.xwiki.extension.version.internal.DefaultVersion;
+import org.xwiki.model.EntityType;
+import org.xwiki.model.reference.DocumentReference;
+import org.xwiki.model.reference.DocumentReferenceResolver;
+import org.xwiki.model.reference.EntityReference;
+import org.xwiki.model.reference.PageReference;
+import org.xwiki.observation.EventListener;
+import org.xwiki.observation.ObservationManager;
+import org.xwiki.observation.event.Event;
+import org.xwiki.query.Query;
+import org.xwiki.query.QueryException;
+import org.xwiki.query.QueryManager;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.doc.XWikiDocument;
+import com.xpn.xwiki.internal.event.XObjectPropertyAddedEvent;
+import com.xpn.xwiki.internal.event.XObjectPropertyDeletedEvent;
+import com.xpn.xwiki.internal.event.XObjectPropertyUpdatedEvent;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.objects.BaseProperty;
import com.xpn.xwiki.objects.NumberProperty;
@@ -56,14 +84,95 @@
*/
@Component(roles = ExtensionStore.class)
@Singleton
-public class ExtensionStore
+@SuppressWarnings("checkstyle:ClassFanOutComplexity")
+public class ExtensionStore implements Initializable, Disposable
{
+ /**
+ * The reference to match property {@link XWikiRepositoryModel#PROP_EXTENSION_ID} of class
+ * {@link XWikiRepositoryModel#EXTENSION_CLASSNAME} on whatever wiki.
+ */
+ private static final EntityReference EXTENSIONID_PROPERTY_REFERENCE =
+ new EntityReference(XWikiRepositoryModel.PROP_EXTENSION_ID, EntityType.OBJECT_PROPERTY,
+ XWikiRepositoryModel.EXTENSION_OBJECTREFERENCE);
+
+ private static final List EVENTS =
+ Arrays.asList(new XObjectPropertyAddedEvent(EXTENSIONID_PROPERTY_REFERENCE),
+ new XObjectPropertyDeletedEvent(EXTENSIONID_PROPERTY_REFERENCE),
+ new XObjectPropertyUpdatedEvent(EXTENSIONID_PROPERTY_REFERENCE));
+
@Inject
private Provider xcontextProvider;
+ @Inject
+ private CacheManager cacheManager;
+
+ @Inject
+ private QueryManager queryManager;
+
+ @Inject
+ private ObservationManager observation;
+
+ @Inject
+ @Named("current")
+ private DocumentReferenceResolver currentStringResolver;
+
+ /**
+ * Link extension id to document reference. The tabe contains null if the id link to no extension.
+ */
+ private Cache documentReferenceCache;
+
@Inject
private Logger logger;
+ private EventListener listener = new EventListener()
+ {
+ @Override
+ public void onEvent(Event event, Object source, Object data)
+ {
+ // TODO: Improve a bit by removing only what's changed
+ documentReferenceCache.removeAll();
+ }
+
+ @Override
+ public String getName()
+ {
+ return "repository.DefaultRepositoryManager";
+ }
+
+ @Override
+ public List getEvents()
+ {
+ return EVENTS;
+ }
+ };
+
+ @Override
+ public void initialize() throws InitializationException
+ {
+ // Init cache
+ CacheConfiguration cacheConfiguration = new CacheConfiguration();
+ cacheConfiguration.setConfigurationId("repository.extensionid.documentreference");
+ LRUEvictionConfiguration lru = new LRUEvictionConfiguration();
+ lru.setMaxEntries(10000);
+ cacheConfiguration.put(LRUEvictionConfiguration.CONFIGURATIONID, lru);
+
+ try {
+ this.documentReferenceCache = this.cacheManager.createNewCache(cacheConfiguration);
+ } catch (CacheException e) {
+ throw new InitializationException("Failed to initialize cache", e);
+ }
+
+ // Listen to modifications
+ this.observation.addListener(listener, EventListener.CACHE_INVALIDATION_DEFAULT_PRIORITY);
+ }
+
+ @Override
+ public void dispose() throws ComponentLifecycleException
+ {
+ this.observation.removeListener(listener.getName());
+ this.documentReferenceCache.dispose();
+ }
+
/**
* @param the expected type of the value to return
* @param xobject the xobject
@@ -75,6 +184,18 @@ public T getValue(BaseObject xobject, String propertyName)
return getValue(xobject, propertyName, (T) null);
}
+ /**
+ * @param the expected type of the value to return
+ * @param xobjects the xobject to try
+ * @param propertyName the property of the xobject
+ * @return the value
+ * @since 17.9.0RC1
+ */
+ public T getValue(List xobjects, String propertyName)
+ {
+ return getValue(xobjects, propertyName, (T) null);
+ }
+
/**
* @param the expected type of the value to return
* @param xobject the xobject
@@ -89,7 +210,11 @@ public T getValue(BaseObject xobject, String propertyName, T def)
T value = def;
if (property != null) {
value = (T) property.getValue();
- if (value == null) {
+ if (value instanceof String stringValue) {
+ value = (T) StringUtils.defaultIfEmpty(stringValue, (String) def);
+ } else if (value instanceof Collection collectionValue) {
+ value = collectionValue.isEmpty() ? def : (T) collectionValue;
+ } else if (value == null) {
value = def;
}
}
@@ -97,6 +222,27 @@ public T getValue(BaseObject xobject, String propertyName, T def)
return value;
}
+ /**
+ * @param the expected type of the value to return
+ * @param xobjects the xobjects to try
+ * @param propertyName the property of the xobject
+ * @param def the value to return if the property is not set
+ * @return the value
+ * @since 17.9.0RC1
+ */
+ public T getValue(List xobjects, String propertyName, T def)
+ {
+ for (BaseObject xobject : xobjects) {
+ T result = getValue(xobject, propertyName, null);
+
+ if (result != null) {
+ return result;
+ }
+ }
+
+ return def;
+ }
+
private URL getURLValue(BaseProperty> property, boolean fallbackOnDocumentURL, XWikiContext xcontext)
{
URL url = null;
@@ -272,4 +418,283 @@ public BaseObject getExtensionSupporterObject(XWikiDocument extensionSupporterDo
return extensionSupporterDocument.getXObject(XWikiRepositoryModel.EXTENSIONSUPPORTER_CLASSREFERENCE);
}
+ /**
+ * Retrieve the extension version document for the given extension document and the given version.
+ *
+ * @param extensionDocument the document of the extension
+ * @param extensionVersion the version for which to retrieve the document
+ * @param xcontext the current context
+ * @return the version document or the given extension document
+ * @throws XWikiException in case of problem for loading the document
+ * @since 17.9.0RC1
+ */
+ public XWikiDocument getExtensionVersionDocument(XWikiDocument extensionDocument, Version extensionVersion,
+ XWikiContext xcontext) throws XWikiException
+ {
+ return getExtensionVersionDocument(extensionDocument, extensionVersion.getValue(), xcontext);
+ }
+
+ /**
+ * Retrieve the extension version document for the given extension document and the given version.
+ *
+ * @param extensionDocument the document of the extension
+ * @param extensionVersion the version for which to retrieve the document
+ * @param xcontext the current context
+ * @return the version document or the given extension document
+ * @throws XWikiException in case of problem for loading the document
+ * @since 17.9.0RC1
+ */
+ public XWikiDocument getExtensionVersionDocument(XWikiDocument extensionDocument, String extensionVersion,
+ XWikiContext xcontext) throws XWikiException
+ {
+ if (isVersionPageEnabled(extensionDocument)) {
+ return xcontext.getWiki()
+ .getDocument(
+ new PageReference(extensionVersion, new PageReference(
+ XWikiRepositoryModel.EXTENSIONVERSIONS_SPACENAME, extensionDocument.getPageReference())),
+ xcontext);
+ }
+
+ return extensionDocument;
+ }
+
+ /**
+ * Retrieve the xobject of the version for given extension.
+ *
+ * @param extensionVersionDocument the document that might contain the version object
+ * @param extensionVersion the version for which to retrieve the object
+ * @param create {@code true} to create the object if it doesn't exist
+ * @param xcontext the current context
+ * @return the version object or {@code null} if it doesn't exist and shouldn't be created
+ * @throws XWikiException in case of problem for loading the document
+ * @since 17.9.0RC1
+ */
+ public BaseObject getExtensionVersionObject(XWikiDocument extensionVersionDocument, Extension extensionVersion,
+ boolean create, XWikiContext xcontext) throws XWikiException
+ {
+ // Update version object
+ BaseObject versionObject =
+ getExtensionVersionObject(extensionVersionDocument, extensionVersion.getId().getVersion());
+ if (versionObject == null && create) {
+ versionObject =
+ extensionVersionDocument.newXObject(XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE, xcontext);
+
+ versionObject.set(XWikiRepositoryModel.PROP_VERSION_VERSION,
+ extensionVersion.getId().getVersion().getValue(), xcontext);
+ }
+
+ return versionObject;
+ }
+
+ /**
+ * Retrieve the xobject of the version from the given document.
+ *
+ * @param document the document where to retrieve the version object.
+ * @param version the version for which to retrieve the object
+ * @return the version object or {@code null} if it doesn't exist and shouldn't be created
+ * @since 17.9.0RC1
+ */
+ public BaseObject getExtensionVersionObject(XWikiDocument document, String version)
+ {
+ return getExtensionVersionObject(document, new DefaultVersion(version));
+ }
+
+ /**
+ * Retrieve the xobject of the version from the given document.
+ *
+ * @param document the document where to retrieve the version object.
+ * @param version the version for which to retrieve the object
+ * @return the version object or {@code null} if it doesn't exist and shouldn't be created
+ * @since 17.9.0RC1
+ */
+ public BaseObject getExtensionVersionObject(XWikiDocument document, Version version)
+ {
+ List objects = document.getXObjects(XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE);
+ if (objects != null) {
+ for (BaseObject versionObject : objects) {
+ if (versionObject != null) {
+ String versionString =
+ getValue(versionObject, XWikiRepositoryModel.PROP_VERSION_VERSION, (String) null);
+
+ if (StringUtils.isNotEmpty(versionString) && version.equals(new DefaultVersion(versionString))) {
+ return versionObject;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @param extensionDocument the document containing the extension metadata
+ * @return true if the passed extension document indicate that version should be proxied
+ * @since 17.9.0RC1
+ */
+ public boolean isVersionProxyingEnabled(XWikiDocument extensionDocument)
+ {
+ BaseObject extensionProxyObject =
+ extensionDocument.getXObject(XWikiRepositoryModel.EXTENSIONPROXY_CLASSREFERENCE);
+ if (extensionProxyObject == null) {
+ return false;
+ }
+
+ return XWikiRepositoryModel.PROP_PROXY_PROXYLEVEL_VALUE_VERSION
+ .equals(getValue(extensionProxyObject, XWikiRepositoryModel.PROP_PROXY_PROXYLEVEL, (String) null));
+ }
+
+ /**
+ * @param extensionId the identifier of the extension
+ * @return the main document holder the extension metadata, or null if none count be found
+ * @throws QueryException when failing to search for the extension document
+ * @throws XWikiException when failing to get the extension document
+ * @since 17.9.0RC1
+ */
+ public XWikiDocument getExistingExtensionDocumentById(String extensionId) throws QueryException, XWikiException
+ {
+ XWikiContext xcontext = this.xcontextProvider.get();
+
+ DocumentReference[] cachedDocumentReference = this.documentReferenceCache.get(extensionId);
+
+ if (cachedDocumentReference == null) {
+ Query query = this.queryManager.createQuery(
+ "select doc.fullName from Document doc, doc.object(" + XWikiRepositoryModel.EXTENSION_CLASSNAME
+ + ") as extension where extension." + XWikiRepositoryModel.PROP_EXTENSION_ID + " = :extensionId",
+ Query.XWQL);
+
+ query.bindValue("extensionId", extensionId);
+
+ List documentNames = query.execute();
+
+ if (!documentNames.isEmpty()) {
+ cachedDocumentReference =
+ new DocumentReference[] {this.currentStringResolver.resolve(documentNames.get(0))};
+ } else {
+ cachedDocumentReference = new DocumentReference[1];
+ }
+
+ this.documentReferenceCache.set(extensionId, cachedDocumentReference);
+ }
+
+ return cachedDocumentReference[0] != null ? xcontext.getWiki().getDocument(cachedDocumentReference[0], xcontext)
+ : null;
+ }
+
+ /**
+ * @param extensionId the identifier of the extension
+ * @return the latest version of the extension
+ * @throws QueryException when failing to search for the extension latest version
+ * @since 17.9.0RC1
+ */
+ public String getLastVersion(String extensionId) throws QueryException
+ {
+ Query query =
+ this.queryManager.createQuery("select version.version, version.index from Document doc, doc.object("
+ + XWikiRepositoryModel.EXTENSIONVERSION_CLASSNAME
+ + ") as version where version.id = :versionId and version.index is not null "
+ + "order by version.index desc", Query.XWQL);
+
+ query.bindValue("versionId", extensionId);
+ query.setLimit(1);
+
+ List results = query.execute();
+
+ if (results.isEmpty()) {
+ return null;
+ }
+
+ return (String) results.get(0)[0];
+ }
+
+ /**
+ * @param extensionDocument the document holder the extension metadata
+ * @return the object holding the main extension metadata
+ * @since 17.9.0RC1
+ */
+ public BaseObject getExtensionObject(XWikiDocument extensionDocument)
+ {
+ return extensionDocument.getXObject(XWikiRepositoryModel.EXTENSION_CLASSREFERENCE);
+ }
+
+ /**
+ * @param extensionId the identifier of the extension
+ * @return true if extension version should be stored in dedicated pages
+ * @throws QueryException when failing to search for the extension page
+ * @throws XWikiException when failing to get the extension page
+ * @since 17.9.0RC1
+ */
+ public boolean isVersionPageEnabled(String extensionId) throws QueryException, XWikiException
+ {
+ XWikiDocument document = getExistingExtensionDocumentById(extensionId);
+
+ return isVersionPageEnabled(document);
+ }
+
+ /**
+ * @param extensionDocument the main page holding extension metadata
+ * @return true if extension version should be stored in dedicated pages
+ * @since 17.9.0RC1
+ */
+ public boolean isVersionPageEnabled(XWikiDocument extensionDocument)
+ {
+ BaseObject extensionObject = getExtensionObject(extensionDocument);
+
+ return isVersionPageEnabled(extensionObject);
+ }
+
+ /**
+ * @param extensionOject the main object holding extension metadata
+ * @return true if extension version should be stored in dedicated pages
+ * @since 17.9.0RC1
+ */
+ public boolean isVersionPageEnabled(BaseObject extensionOject)
+ {
+ return getBooleanValue(extensionOject, XWikiRepositoryModel.PROP_EXTENSION_VERSIONPAGE, false);
+ }
+
+ /**
+ * @param extensionOject true if extension version should be stored in dedicated pages
+ * @return true if the object has been modified, false otherwise
+ * @since 17.9.0RC1
+ */
+ public boolean setVersionPageEnabled(BaseObject extensionOject)
+ {
+ if (!isVersionPageEnabled(extensionOject)) {
+ extensionOject.setIntValue(XWikiRepositoryModel.PROP_EXTENSION_VERSIONPAGE, 1);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param document the document holding the extension metadata
+ * @return the identifier of the extension
+ * @since 17.9.0RC1
+ */
+ public String getExtensionId(XWikiDocument document)
+ {
+ return document.getStringValue(XWikiRepositoryModel.PROP_EXTENSION_ID);
+ }
+
+ /**
+ * @param document the document holding the extension metadata
+ * @return the name of the extension
+ * @since 17.9.0RC1
+ */
+ public String getExtensionName(XWikiDocument document)
+ {
+ return document.getStringValue(XWikiRepositoryModel.PROP_EXTENSION_NAME);
+ }
+
+ /**
+ * @param document the document holding the extension metadata
+ * @return the type of the extension
+ * @since 17.9.0RC1
+ */
+ public String getExtensionType(XWikiDocument document)
+ {
+ return document.getStringValue(XWikiRepositoryModel.PROP_EXTENSION_TYPE);
+ }
}
diff --git a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/ExtensionUpdaterListener.java b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/ExtensionUpdaterListener.java
index b99d4228c028..7a997a467f36 100644
--- a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/ExtensionUpdaterListener.java
+++ b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/ExtensionUpdaterListener.java
@@ -34,7 +34,6 @@
import org.xwiki.observation.EventListener;
import org.xwiki.observation.event.Event;
-import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;
@@ -46,8 +45,8 @@ public class ExtensionUpdaterListener implements EventListener
/**
* Listened events.
*/
- private static final List EVENTS = Arrays. asList(new DocumentCreatingEvent(),
- new DocumentUpdatingEvent());
+ private static final List EVENTS =
+ Arrays.asList(new DocumentCreatingEvent(), new DocumentUpdatingEvent());
/**
* The logger to log.
@@ -80,7 +79,7 @@ public void onEvent(Event event, Object source, Object data)
if (extensionObject != null) {
try {
this.repositoryManagerProvider.get().validateExtension(document, false);
- } catch (XWikiException e) {
+ } catch (Exception e) {
this.logger.error("Failed to validate extension in document [{}]", document.getDocumentReference(), e);
}
}
diff --git a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/RepositoryManager.java b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/RepositoryManager.java
index 5c110720f1a6..432fa947245f 100644
--- a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/RepositoryManager.java
+++ b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/RepositoryManager.java
@@ -45,16 +45,7 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings;
import org.slf4j.Logger;
-import org.xwiki.cache.Cache;
-import org.xwiki.cache.CacheException;
-import org.xwiki.cache.CacheManager;
-import org.xwiki.cache.config.CacheConfiguration;
-import org.xwiki.cache.eviction.LRUEvictionConfiguration;
import org.xwiki.component.annotation.Component;
-import org.xwiki.component.manager.ComponentLifecycleException;
-import org.xwiki.component.phase.Disposable;
-import org.xwiki.component.phase.Initializable;
-import org.xwiki.component.phase.InitializationException;
import org.xwiki.extension.DefaultExtensionDependency;
import org.xwiki.extension.Extension;
import org.xwiki.extension.ExtensionAuthor;
@@ -84,10 +75,8 @@
import org.xwiki.model.reference.DocumentReferenceResolver;
import org.xwiki.model.reference.EntityReference;
import org.xwiki.model.reference.EntityReferenceSerializer;
+import org.xwiki.model.reference.PageReference;
import org.xwiki.model.reference.WikiReference;
-import org.xwiki.observation.EventListener;
-import org.xwiki.observation.ObservationManager;
-import org.xwiki.observation.event.Event;
import org.xwiki.query.Query;
import org.xwiki.query.QueryException;
import org.xwiki.query.QueryManager;
@@ -96,35 +85,27 @@
import org.xwiki.rendering.listener.reference.ResourceType;
import org.xwiki.rendering.parser.ResourceReferenceParser;
import org.xwiki.rendering.renderer.reference.ResourceReferenceTypeSerializer;
+import org.xwiki.rendering.syntax.Syntax;
import org.xwiki.repository.internal.reference.ExtensionResourceReference;
+import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.doc.XWikiAttachment;
import com.xpn.xwiki.doc.XWikiDocument;
-import com.xpn.xwiki.internal.event.XObjectPropertyAddedEvent;
-import com.xpn.xwiki.internal.event.XObjectPropertyDeletedEvent;
-import com.xpn.xwiki.internal.event.XObjectPropertyUpdatedEvent;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.objects.StringProperty;
+/**
+ * Expose various tools to manipulate extensions in the wiki.
+ *
+ * @version $Id$
+ */
@Component(roles = RepositoryManager.class)
@Singleton
-public class RepositoryManager implements Initializable, Disposable
+@SuppressWarnings("checkstyle:ClassFanOutComplexity")
+public class RepositoryManager
{
- /**
- * The reference to match property {@link XWikiRepositoryModel#PROP_EXTENSION_ID} of class
- * {@link XWikiRepositoryModel#EXTENSION_CLASSNAME} on whatever wiki.
- */
- private static final EntityReference EXTENSIONID_PROPERTY_REFERENCE =
- new EntityReference(XWikiRepositoryModel.PROP_EXTENSION_ID, EntityType.OBJECT_PROPERTY,
- XWikiRepositoryModel.EXTENSION_OBJECTREFERENCE);
-
- private static final List EVENTS =
- Arrays.asList(new XObjectPropertyAddedEvent(EXTENSIONID_PROPERTY_REFERENCE),
- new XObjectPropertyDeletedEvent(EXTENSIONID_PROPERTY_REFERENCE),
- new XObjectPropertyUpdatedEvent(EXTENSIONID_PROPERTY_REFERENCE));
-
private static final Pattern PATTERN_NEWLINE = Pattern.compile("[\n\r]");
/**
@@ -173,17 +154,11 @@ public class RepositoryManager implements Initializable, Disposable
@Inject
private RepositoryConfiguration configuration;
- @Inject
- private CacheManager cacheManager;
-
- @Inject
- private ObservationManager observation;
-
@Inject
private ExtensionFactory extensionFactory;
@Inject
- protected ExtensionStore extensionStore;
+ private ExtensionStore extensionStore;
@Inject
private Logger logger;
@@ -192,117 +167,7 @@ public class RepositoryManager implements Initializable, Disposable
private int maxStringPropertySize = -1;
- /**
- * Link extension id to document reference. The tabe contains null if the id link to no extension.
- */
- private Cache documentReferenceCache;
-
- private EventListener listener = new EventListener()
- {
- @Override
- public void onEvent(Event event, Object source, Object data)
- {
- // TODO: Improve a bit by removing only what's changed
- documentReferenceCache.removeAll();
- }
-
- @Override
- public String getName()
- {
- return "repository.DefaultRepositoryManager";
- }
-
- @Override
- public List getEvents()
- {
- return EVENTS;
- }
- };
-
- @Override
- public void initialize() throws InitializationException
- {
- // Init cache
- CacheConfiguration cacheConfiguration = new CacheConfiguration();
- cacheConfiguration.setConfigurationId("repository.extensionid.documentreference");
- LRUEvictionConfiguration lru = new LRUEvictionConfiguration();
- lru.setMaxEntries(10000);
- cacheConfiguration.put(LRUEvictionConfiguration.CONFIGURATIONID, lru);
-
- try {
- this.documentReferenceCache = this.cacheManager.createNewCache(cacheConfiguration);
- } catch (CacheException e) {
- throw new InitializationException("Failed to initialize cache", e);
- }
-
- // Listen to modifications
- this.observation.addListener(listener, EventListener.CACHE_INVALIDATION_DEFAULT_PRIORITY);
- }
-
- @Override
- public void dispose() throws ComponentLifecycleException
- {
- this.observation.removeListener(listener.getName());
- this.documentReferenceCache.dispose();
- }
-
- public XWikiDocument getDocument(String fullName) throws XWikiException
- {
- XWikiContext xcontext = this.xcontextProvider.get();
-
- return xcontext.getWiki().getDocument(this.currentStringResolver.resolve(fullName), xcontext);
- }
-
- public XWikiDocument getExistingExtensionDocumentById(String extensionId) throws QueryException, XWikiException
- {
- XWikiContext xcontext = this.xcontextProvider.get();
-
- DocumentReference[] cachedDocumentReference = this.documentReferenceCache.get(extensionId);
-
- if (cachedDocumentReference == null) {
- Query query = this.queryManager.createQuery(
- "select doc.fullName from Document doc, doc.object(" + XWikiRepositoryModel.EXTENSION_CLASSNAME
- + ") as extension where extension." + XWikiRepositoryModel.PROP_EXTENSION_ID + " = :extensionId",
- Query.XWQL);
-
- query.bindValue("extensionId", extensionId);
-
- List documentNames = query.execute();
-
- if (!documentNames.isEmpty()) {
- cachedDocumentReference =
- new DocumentReference[] {this.currentStringResolver.resolve(documentNames.get(0))};
- } else {
- cachedDocumentReference = new DocumentReference[1];
- }
-
- this.documentReferenceCache.set(extensionId, cachedDocumentReference);
- }
-
- return cachedDocumentReference[0] != null ? xcontext.getWiki().getDocument(cachedDocumentReference[0], xcontext)
- : null;
- }
-
- public BaseObject getExtensionVersion(XWikiDocument document, Version version)
- {
- List objects = document.getXObjects(XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE);
- if (objects != null) {
- for (BaseObject versionObject : objects) {
- if (versionObject != null) {
- String versionString = this.extensionStore.getValue(versionObject,
- XWikiRepositoryModel.PROP_VERSION_VERSION, (String) null);
-
- if (StringUtils.isNotEmpty(versionString) && version.equals(new DefaultVersion(versionString))) {
- return versionObject;
- }
- }
- }
- }
-
- return null;
- }
-
- public void validateExtension(XWikiDocument document, boolean save) throws XWikiException
+ public void validateExtension(XWikiDocument document, boolean save) throws XWikiException, QueryException
{
BaseObject extensionObject = document.getXObject(XWikiRepositoryModel.EXTENSION_CLASSREFERENCE);
@@ -360,7 +225,6 @@ public void validateExtension(XWikiDocument document, boolean save) throws XWiki
}
// Save document
-
if (save && needSave) {
xcontext.getWiki().saveDocument(document, "Validated extension", true, xcontext);
}
@@ -371,43 +235,43 @@ public void validateExtension(XWikiDocument document, boolean save) throws XWiki
*
* @param document the extension document
* @return the last version
+ * @throws QueryException when failing to resolve the last version
*/
- private String findLastVersion(XWikiDocument document)
+ private String findLastVersion(XWikiDocument document) throws QueryException
{
- String extensionId = getExtensionId(document);
-
- DocumentReference versionClassReference =
- getClassReference(document, XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE);
-
- List versionObjects = document.getXObjects(versionClassReference);
+ String extensionId = this.extensionStore.getExtensionId(document);
- DefaultVersion lastVersion = null;
- if (versionObjects != null) {
- for (BaseObject versionObject : versionObjects) {
- if (versionObject != null) {
- String versionId =
- this.extensionStore.getValue(versionObject, XWikiRepositoryModel.PROP_VERSION_ID);
-
- if (StringUtils.isEmpty(versionId) || Objects.equals(extensionId, versionId)) {
- String versionString =
- this.extensionStore.getValue(versionObject, XWikiRepositoryModel.PROP_VERSION_VERSION);
- if (versionString != null) {
- DefaultVersion version = new DefaultVersion(versionString);
- if (lastVersion == null || version.compareTo(lastVersion) > 0) {
- lastVersion = version;
+ if (this.extensionStore.isVersionPageEnabled(document)) {
+ return this.extensionStore.getLastVersion(extensionId);
+ } else {
+ DocumentReference versionClassReference =
+ getClassReference(document, XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE);
+
+ List versionObjects = document.getXObjects(versionClassReference);
+
+ DefaultVersion lastVersion = null;
+ if (versionObjects != null) {
+ for (BaseObject versionObject : versionObjects) {
+ if (versionObject != null) {
+ String versionId =
+ this.extensionStore.getValue(versionObject, XWikiRepositoryModel.PROP_VERSION_ID);
+
+ if (StringUtils.isEmpty(versionId) || Objects.equals(extensionId, versionId)) {
+ String versionString =
+ this.extensionStore.getValue(versionObject, XWikiRepositoryModel.PROP_VERSION_VERSION);
+ if (versionString != null) {
+ DefaultVersion version = new DefaultVersion(versionString);
+ if (lastVersion == null || version.compareTo(lastVersion) > 0) {
+ lastVersion = version;
+ }
}
}
}
}
}
- }
- return lastVersion != null ? lastVersion.getValue() : null;
- }
-
- private String getExtensionId(XWikiDocument document)
- {
- return document.getStringValue(XWikiRepositoryModel.PROP_EXTENSION_ID);
+ return lastVersion != null ? lastVersion.getValue() : null;
+ }
}
private DocumentReference getClassReference(XWikiDocument document, EntityReference localReference)
@@ -416,13 +280,13 @@ private DocumentReference getClassReference(XWikiDocument document, EntityRefere
}
/**
- * @param document the extension document
+ * @param extensionDocument the extension document
* @param extensionObject the extension object
- * @param context the XWiki context
+ * @param xcontext the XWiki context
* @return true if the extension is valid from Extension Manager point of view
* @throws XWikiException unknown issue when manipulating the model
*/
- private boolean isValid(XWikiDocument document, BaseObject extensionObject, XWikiContext context)
+ private boolean isValid(XWikiDocument extensionDocument, BaseObject extensionObject, XWikiContext xcontext)
throws XWikiException
{
String extensionId = this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_ID);
@@ -434,14 +298,15 @@ private boolean isValid(XWikiDocument document, BaseObject extensionObject, XWik
valid = this.configuration.isValidType(type);
if (valid) {
- // Versions
valid = false;
+
+ // Legacy Versions
List extensionVersions =
- document.getXObjects(XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE);
+ extensionDocument.getXObjects(XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE);
if (extensionVersions != null) {
for (BaseObject extensionVersionObject : extensionVersions) {
if (extensionVersionObject != null) {
- valid = isVersionValid(document, type, extensionVersionObject, context);
+ valid = isVersionValid(extensionDocument, type, extensionVersionObject, xcontext);
if (!valid) {
return false;
@@ -449,6 +314,20 @@ private boolean isValid(XWikiDocument document, BaseObject extensionObject, XWik
}
}
}
+
+ // New version storage
+ if (this.extensionStore.isVersionPageEnabled(extensionObject)) {
+ // Current version
+ String lastVersion =
+ extensionDocument.getStringValue(XWikiRepositoryModel.PROP_EXTENSION_LASTVERSION);
+ if (StringUtils.isNotBlank(lastVersion)) {
+ valid = isVersionValid(extensionDocument, type, lastVersion, xcontext);
+
+ if (!valid) {
+ return false;
+ }
+ }
+ }
}
}
@@ -456,11 +335,13 @@ private boolean isValid(XWikiDocument document, BaseObject extensionObject, XWik
}
private boolean isVersionValid(XWikiDocument document, String type, BaseObject extensionVersionObject,
- XWikiContext context)
+ XWikiContext xcontext)
{
// Has a version
String extensionVersion =
this.extensionStore.getValue(extensionVersionObject, XWikiRepositoryModel.PROP_VERSION_VERSION);
+
+ // Has a version
if (StringUtils.isBlank(extensionVersion)) {
this.logger.debug("No actual version provided for object [{}({})]",
XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE, extensionVersionObject.getNumber());
@@ -468,6 +349,19 @@ private boolean isVersionValid(XWikiDocument document, String type, BaseObject e
return false;
}
+ return isVersionValid(document, type, extensionVersion, xcontext);
+ }
+
+ private boolean isVersionValid(XWikiDocument document, String type, String extensionVersion, XWikiContext xcontext)
+ {
+ // Has a version
+ if (StringUtils.isBlank(extensionVersion)) {
+ this.logger.debug("No actual version provided for document [{}({})]",
+ XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE, document.getDocumentReference());
+
+ return false;
+ }
+
boolean valid;
if (StringUtils.isEmpty(type)) {
@@ -477,9 +371,9 @@ private boolean isVersionValid(XWikiDocument document, String type, BaseObject e
ResourceReference resourceReference = null;
try {
resourceReference = getDownloadReference(document, extensionVersion);
- } catch (ResolveException e) {
- logger.debug("Cannot obtain download source reference for object [{}({})]",
- XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE, extensionVersionObject.getNumber());
+ } catch (Exception e) {
+ logger.debug("Cannot obtain download source reference for version [({})]", extensionVersion);
+
return false;
}
@@ -494,7 +388,7 @@ private boolean isVersionValid(XWikiDocument document, String type, BaseObject e
attachmentDocument = document;
} else {
attachmentDocument =
- context.getWiki().getDocument(attachmentReference.getDocumentReference(), context);
+ xcontext.getWiki().getDocument(attachmentReference.getDocumentReference(), xcontext);
}
valid = attachmentDocument.getAttachment(attachmentReference.getName()) != null;
@@ -518,8 +412,7 @@ private boolean isVersionValid(XWikiDocument document, String type, BaseObject e
} else {
valid = false;
- this.logger.debug("No actual download provided for object [{}({})]",
- XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE, extensionVersionObject.getNumber());
+ this.logger.debug("No actual download provided for version [({})]", extensionVersion);
}
}
@@ -536,22 +429,31 @@ public void validateExtensions() throws QueryException, XWikiException
}
}
+ private XWikiDocument getDocument(String fullName) throws XWikiException
+ {
+ XWikiContext xcontext = this.xcontextProvider.get();
+
+ return xcontext.getWiki().getDocument(this.currentStringResolver.resolve(fullName), xcontext);
+ }
+
/**
- * @since 9.5RC1
+ * @param document the document holding the extension metadata
+ * @param extensionVersion the version for which to return the download reference
+ * @return the download reference
+ * @throws ResolveException when failing to resolve the download reference
+ * @throws XWikiException when failing to resolve the download reference
*/
public ResourceReference getDownloadReference(XWikiDocument document, String extensionVersion)
- throws ResolveException
+ throws ResolveException, XWikiException
{
-
String downloadURL = null;
- BaseObject extensionVersionObject = getExtensionVersionObject(document, extensionVersion, false); // this
- // 'false' is
- // important
+ BaseObject extensionVersionObject =
+ getExtensionVersionObject(document, extensionVersion, false, this.xcontextProvider.get());
if (extensionVersionObject != null) {
downloadURL =
this.extensionStore.getValue(extensionVersionObject, XWikiRepositoryModel.PROP_VERSION_DOWNLOAD);
- } else if (isVersionProxyingEnabled(document)) {
+ } else if (this.extensionStore.isVersionProxyingEnabled(document)) {
downloadURL = resolveExtensionDownloadURL(document, extensionVersion);
}
@@ -642,30 +544,33 @@ public DocumentReference importExtension(String extensionId, ExtensionRepository
boolean needSave = false;
- XWikiDocument document = getExistingExtensionDocumentById(extensionId);
+ XWikiDocument extensionDocument = this.extensionStore.getExistingExtensionDocumentById(extensionId);
- if (document == null) {
+ if (extensionDocument == null) {
// Create document
- document = xcontext.getWiki().getDocument(
+ extensionDocument = xcontext.getWiki().getDocument(
new DocumentReference(xcontext.getWikiId(), Arrays.asList("Extension", extension.getName()), "WebHome"),
xcontext);
- for (int i = 1; !document.isNew(); ++i) {
- document = xcontext.getWiki().getDocument(new DocumentReference(xcontext.getWikiId(),
+ for (int i = 1; !extensionDocument.isNew(); ++i) {
+ extensionDocument = xcontext.getWiki().getDocument(new DocumentReference(xcontext.getWikiId(),
Arrays.asList("Extension", extension.getName() + ' ' + i), "WebHome"), xcontext);
}
- document.readFromTemplate(this.currentResolver.resolve(XWikiRepositoryModel.EXTENSION_TEMPLATEREFERENCE),
- xcontext);
+ extensionDocument.readFromTemplate(
+ this.currentResolver.resolve(XWikiRepositoryModel.EXTENSION_TEMPLATEREFERENCE), xcontext);
needSave = true;
+ } else {
+ // Avoid modifying the cached document
+ extensionDocument = extensionDocument.clone();
}
// Update document
- BaseObject extensionObject = document.getXObject(XWikiRepositoryModel.EXTENSION_CLASSREFERENCE);
+ BaseObject extensionObject = this.extensionStore.getExtensionObject(extensionDocument);
if (extensionObject == null) {
- extensionObject = document.newXObject(XWikiRepositoryModel.EXTENSION_CLASSREFERENCE, xcontext);
+ extensionObject = extensionDocument.newXObject(XWikiRepositoryModel.EXTENSION_CLASSREFERENCE, xcontext);
needSave = true;
}
@@ -675,9 +580,14 @@ public DocumentReference importExtension(String extensionId, ExtensionRepository
needSave = true;
}
- // Update extension informations
+ // Make sure we use the dedicated version page mode
+ needSave |= this.extensionStore.setVersionPageEnabled(extensionObject);
+
+ // Update main extension page
needSave |= updateExtension(extension, extensionObject, xcontext);
+ needSave |= updateExtensionMain(extension, extensionObject, xcontext);
+ needSave |= updateExtensionVersionDependencies(extension, extensionDocument);
// Get former ids versions
TreeMap featureVersions = new TreeMap<>();
@@ -708,9 +618,11 @@ public DocumentReference importExtension(String extensionId, ExtensionRepository
// Proxy marker
- BaseObject extensionProxyObject = document.getXObject(XWikiRepositoryModel.EXTENSIONPROXY_CLASSREFERENCE);
+ BaseObject extensionProxyObject =
+ extensionDocument.getXObject(XWikiRepositoryModel.EXTENSIONPROXY_CLASSREFERENCE);
if (extensionProxyObject == null) {
- extensionProxyObject = document.newXObject(XWikiRepositoryModel.EXTENSIONPROXY_CLASSREFERENCE, xcontext);
+ extensionProxyObject =
+ extensionDocument.newXObject(XWikiRepositoryModel.EXTENSIONPROXY_CLASSREFERENCE, xcontext);
extensionProxyObject.setIntValue(XWikiRepositoryModel.PROP_PROXY_AUTOUPDATE, 1);
needSave = true;
}
@@ -722,29 +634,44 @@ public DocumentReference importExtension(String extensionId, ExtensionRepository
needSave |= update(extensionProxyObject, XWikiRepositoryModel.PROP_PROXY_REPOSITORYURI,
repository.getDescriptor().getURI().toString());
- // Remove unexisting versions
-
Set validVersions = new HashSet<>();
- List versionObjects = document.getXObjects(XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE);
+ // Check the versions storage and proxy mode
+ boolean versionPageEnabled = this.extensionStore.isVersionPageEnabled(extensionObject);
+ boolean versionProxyEnabled = this.extensionStore.isVersionProxyingEnabled(extensionDocument);
+
+ // Remove unexisting versions
+ List versionObjects =
+ extensionDocument.getXObjects(XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE);
if (versionObjects != null) {
for (BaseObject versionObject : versionObjects) {
if (versionObject != null) {
String version =
this.extensionStore.getValue(versionObject, XWikiRepositoryModel.PROP_VERSION_VERSION);
- if (StringUtils.isBlank(version) || (isVersionProxyingEnabled(document)
- && !new DefaultVersion(version).equals(extension.getId().getVersion()))) {
- // Empty version OR old versions should be proxied
- document.removeXObject(versionObject);
+ // 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);
+ }
} else {
if (!extensionVersions.containsKey(new DefaultVersion(version))
&& featureVersions.containsKey(new DefaultVersion(version))) {
+ // Version are stored on dedicated pages
// The version does not exist on remote repository
- if (!isVersionValid(document, extension.getType(), versionObject, xcontext)) {
+ if (!isVersionValid(extensionDocument, extension.getType(), versionObject, xcontext)) {
// The version is invalid, removing it to not make the whole extension invalid
- document.removeXObject(versionObject);
+ extensionDocument.removeXObject(versionObject);
needSave = true;
} else {
// The version is valid, lets keep it
@@ -758,8 +685,13 @@ public DocumentReference importExtension(String extensionId, ExtensionRepository
}
}
}
+
+ // Current version is valid
+ validVersions.add(extension.getId().getVersion().getValue());
+
+ // Cleanup dependencies not associated to valid versions
List dependencyObjects =
- document.getXObjects(XWikiRepositoryModel.EXTENSIONDEPENDENCY_CLASSREFERENCE);
+ extensionDocument.getXObjects(XWikiRepositoryModel.EXTENSIONDEPENDENCY_CLASSREFERENCE);
if (dependencyObjects != null) {
for (BaseObject dependencyObject : dependencyObjects) {
if (dependencyObject != null) {
@@ -768,66 +700,103 @@ public DocumentReference importExtension(String extensionId, ExtensionRepository
if (!validVersions.contains(version)) {
// The version is invalid, removing it to not make the whole extension invalid
- document.removeXObject(dependencyObject);
+ extensionDocument.removeXObject(dependencyObject);
needSave = true;
}
}
}
}
- // Update features versions
+ // Remove version pages corresponding to not existing versions
+ cleanNotExistingVersionPages(extensionDocument, extension.getId().getVersion(), extensionVersions,
+ featureVersions, versionProxyEnabled, xcontext);
+ // Update features versions
+ long index = 0;
for (Map.Entry entry : featureVersions.entrySet()) {
Version version = entry.getKey();
String id = entry.getValue();
// Give priority to extension version in case of conflict
if (!extensionVersions.containsKey(version)) {
- updateVersion(id, version, extension, repository, document);
+ updateVersion(id, version, extension, repository, index++, extensionDocument);
}
}
// Update extension versions
-
for (Map.Entry entry : extensionVersions.entrySet()) {
Version version = entry.getKey();
String id = entry.getValue();
- updateVersion(id, version, extension, repository, document);
+ updateVersion(id, version, extension, repository, index++, extensionDocument);
}
// Save
if (needSave) {
- document.setAuthorReference(xcontext.getUserReference());
- if (document.isNew()) {
- document.setContentAuthorReference(xcontext.getUserReference());
- document.setCreatorReference(xcontext.getUserReference());
+ saveDocument(extensionDocument,
+ "Imported extension [" + extensionId + "] from repository [" + repository.getDescriptor() + "]",
+ xcontext);
+ }
+
+ return extensionDocument.getDocumentReference();
+ }
+
+ private void cleanNotExistingVersionPages(XWikiDocument extensionDocument, Version currentVersion,
+ TreeMap extensionVersions, TreeMap featureVersions,
+ boolean versionProxyEnabled, XWikiContext xcontext) throws QueryException, XWikiException
+ {
+ EntityReference versionsSpaceReference = new EntityReference(XWikiRepositoryModel.EXTENSIONVERSIONS_SPACENAME,
+ EntityType.SPACE, extensionDocument.getDocumentReference().getLocalDocumentReference().getParent());
+ Query query = this.queryManager.createQuery(
+ "select doc.fullName, version.version from Document doc, doc.object("
+ + XWikiRepositoryModel.EXTENSIONVERSION_CLASSNAME + ") version where doc.space like :space",
+ Query.XWQL);
+ query.bindValue("space", this.entityReferenceSerializer.serialize(versionsSpaceReference) + ".%");
+ List results = query.execute();
+
+ XWiki xwiki = xcontext.getWiki();
+ for (Object[] result : results) {
+ Version version = new DefaultVersion((String) result[1]);
+
+ // Remove the document if:
+ // * the versions does not exist
+ // * versions should be proxied but it's not the current one
+ if (versionProxyEnabled || (!currentVersion.equals(version) && !extensionVersions.containsKey(version)
+ && !featureVersions.containsKey(version))) {
+ DocumentReference documentReference = this.currentStringResolver.resolve((String) result[0]);
+ XWikiDocument document = xwiki.getDocument(documentReference, xcontext);
+ xwiki.deleteDocument(document, xcontext);
}
+ }
+ }
- xcontext.getWiki().saveDocument(document,
- "Imported extension [" + extensionId + "] from repository [" + repository.getDescriptor() + "]", true,
- xcontext);
+ private void saveDocument(XWikiDocument document, String comment, XWikiContext xcontext) throws XWikiException
+ {
+ document.setAuthorReference(xcontext.getUserReference());
+ if (document.isNew()) {
+ document.setContentAuthorReference(xcontext.getUserReference());
+ document.setCreatorReference(xcontext.getUserReference());
}
- return document.getDocumentReference();
+ xcontext.getWiki().saveDocument(document, comment, xcontext);
}
private boolean updateVersion(String id, Version version, Extension extension, ExtensionRepository repository,
- XWikiDocument document)
+ long index, XWikiDocument extensionDocument)
{
try {
Extension versionExtension;
if (version.equals(extension.getId().getVersion())) {
versionExtension = extension;
- } else if (isVersionProxyingEnabled(document)) {
+ } else if (this.extensionStore.isVersionProxyingEnabled(extensionDocument)) {
return false;
} else {
versionExtension = repository.resolve(new ExtensionId(id, version));
}
// Update version related informations
- return updateExtensionVersion(document, versionExtension);
+ return updateExtensionVersion(versionExtension, extensionDocument, index, true);
} catch (Exception e) {
this.logger.error("Failed to resolve extension with id [" + id + "] and version [" + version
+ "] on repository [" + repository + "]", e);
@@ -837,17 +806,107 @@ private boolean updateVersion(String id, Version version, Extension extension, E
}
/**
- * @since 9.5RC1
+ * @param extensionDocument the document holder the main extension metadata
+ * @param version the version for which to return the object
+ * @param xcontext the XWiki Context
+ * @return the object holding the extension version metadata, or null if none could be found
+ * @throws XWikiException when failing to get the extension version object
+ * @since 17.9.0RC1
*/
- public boolean isVersionProxyingEnabled(XWikiDocument extensionDocument)
+ public BaseObject getExtensionVersionObject(XWikiDocument extensionDocument, String version, XWikiContext xcontext)
+ throws XWikiException
{
- BaseObject extensionProxyObject =
- extensionDocument.getXObject(XWikiRepositoryModel.EXTENSIONPROXY_CLASSREFERENCE);
- if (extensionProxyObject == null) {
- return false;
+ return getExtensionVersionObject(extensionDocument, version, true, xcontext);
+ }
+
+ /**
+ * @param extensionDocument the document holder the main extension metadata
+ * @param version the version for which to return the object
+ * @param allowProxying true if the method to follow the proxy when the version cannot be found locally
+ * @param xcontext the XWiki Context
+ * @return the object holding the extension version metadata, or null if none could be found
+ * @throws XWikiException when failing to get the extension version object
+ * @since 17.9.0RC1
+ */
+ public BaseObject getExtensionVersionObject(XWikiDocument extensionDocument, String version, boolean allowProxying,
+ XWikiContext xcontext) throws XWikiException
+ {
+ XWikiDocument extensionVersionDocument =
+ this.extensionStore.getExtensionVersionDocument(extensionDocument, version, xcontext);
+
+ if (version == null) {
+ List objects =
+ extensionVersionDocument.getXObjects(XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE);
+
+ if (objects == null || objects.isEmpty()) {
+ return null;
+ } else {
+ return objects.get(objects.size() - 1);
+ }
}
- return XWikiRepositoryModel.PROP_PROXY_PROXYLEVEL_VALUE_VERSION.equals(this.extensionStore
- .getValue(extensionProxyObject, XWikiRepositoryModel.PROP_PROXY_PROXYLEVEL, (String) null));
+
+ BaseObject extensionVersionObject = extensionVersionDocument
+ .getXObject(XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE, "version", version, false);
+
+ if (extensionVersionObject == null && allowProxying
+ && this.extensionStore.isVersionProxyingEnabled(extensionDocument)) {
+ // No ExtensionVersionClass object for the version, but proxy is enabled, so try to find remotely
+ Extension extension = null;
+ try {
+ extension = resolveExtensionVersion(extensionDocument, version);
+ } catch (ExtensionNotFoundException e) {
+ this.logger.debug("No extension could be found remotely with version [{}] for extension page [{}]",
+ version, extensionDocument.getDocumentReference());
+ } catch (ResolveException e) {
+ throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR);
+ }
+
+ // No extension could be found for the provided version
+ if (extension == null) {
+ return null;
+ }
+
+ // Create a "detached" xobject for that extension version
+ // FIXME: find a more elegant solution
+ try {
+ XWikiDocument extensionDocumentClone = extensionDocument.clone();
+ updateExtensionVersion(extension, extensionDocumentClone, 0, xcontext);
+ extensionVersionObject = extensionDocumentClone
+ .getXObject(XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE, "version", version, false);
+ } catch (XWikiException e) {
+ throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ return extensionVersionObject;
+ }
+
+ private boolean updateExtensionMain(Extension extension, BaseObject extensionObject, XWikiContext xcontext)
+ throws XWikiException
+ {
+ boolean needSave = false;
+
+ // Description
+ if (StringUtils.isEmpty(this.extensionStore.getValue(extensionObject,
+ XWikiRepositoryModel.PROP_EXTENSION_DESCRIPTION, (String) null))) {
+ extensionObject.set(XWikiRepositoryModel.PROP_EXTENSION_DESCRIPTION, getDescription(extension), xcontext);
+ needSave = true;
+ }
+
+ // Issue Management
+ ExtensionIssueManagement issueManagement = extension.getIssueManagement();
+ if (issueManagement != null) {
+ if (issueManagement.getSystem() != null) {
+ needSave |= update(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_ISSUEMANAGEMENT_SYSTEM,
+ issueManagement.getSystem());
+ }
+ if (issueManagement.getURL() != null) {
+ needSave |= update(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_ISSUEMANAGEMENT_URL,
+ issueManagement.getURL());
+ }
+ }
+
+ return needSave;
}
private boolean updateExtension(Extension extension, BaseObject extensionObject, XWikiContext xcontext)
@@ -878,13 +937,6 @@ private boolean updateExtension(Extension extension, BaseObject extensionObject,
* update(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_WEBSITE, extension.getWebSite());
*/
- // Description
- if (StringUtils.isEmpty(this.extensionStore.getValue(extensionObject,
- XWikiRepositoryModel.PROP_EXTENSION_DESCRIPTION, (String) null))) {
- extensionObject.set(XWikiRepositoryModel.PROP_EXTENSION_DESCRIPTION, getDescription(extension), xcontext);
- needSave = true;
- }
-
// License
if (!extension.getLicenses().isEmpty()
&& !Strings.CS.equals(extension.getLicenses().iterator().next().getName(), this.extensionStore
@@ -910,19 +962,6 @@ private boolean updateExtension(Extension extension, BaseObject extensionObject,
}
}
- // Issue Management
- ExtensionIssueManagement issueManagement = extension.getIssueManagement();
- if (issueManagement != null) {
- if (issueManagement.getSystem() != null) {
- needSave |= update(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_ISSUEMANAGEMENT_SYSTEM,
- issueManagement.getSystem());
- }
- if (issueManagement.getURL() != null) {
- needSave |= update(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_ISSUEMANAGEMENT_URL,
- issueManagement.getURL());
- }
- }
-
// Authors
needSave |= updateAuthors(extensionObject, extension.getAuthors());
@@ -1091,7 +1130,7 @@ private String resolveAuthorIdOnWiki(String wiki, String authorName, String[] au
return null;
}
- private boolean updateExtensionVersionDependencies(XWikiDocument document, Extension extension)
+ private boolean updateExtensionVersionDependencies(Extension extension, XWikiDocument document)
throws XWikiException
{
boolean needSave = false;
@@ -1189,6 +1228,27 @@ private boolean updateExtensionVersionDependencies(XWikiDocument document, Exten
*/
public Extension resolveExtensionVersion(XWikiDocument extensionDocument, String extensionVersion)
throws ResolveException
+ {
+ BaseObject extensionObject = extensionDocument.getXObject(XWikiRepositoryModel.EXTENSION_CLASSREFERENCE);
+ if (extensionObject == null) {
+ return null;
+ }
+ String extensionId =
+ this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_ID, (String) null);
+
+ if (extensionId == null) {
+ return null;
+ }
+
+ ExtensionRepository repository = getExtensionRepository(extensionDocument);
+ if (isGivenVersionOneOfExtensionVersions(repository, extensionId, extensionVersion)) {
+ return repository.resolve(new ExtensionId(extensionId, extensionVersion));
+ } else {
+ return tryToResolveExtensionFromExtensionFeatures(repository, extensionObject, extensionVersion);
+ }
+ }
+
+ public ExtensionRepository getExtensionRepository(XWikiDocument extensionDocument)
{
BaseObject extensionObject = extensionDocument.getXObject(XWikiRepositoryModel.EXTENSION_CLASSREFERENCE);
if (extensionObject == null) {
@@ -1209,12 +1269,7 @@ public Extension resolveExtensionVersion(XWikiDocument extensionDocument, String
return null;
}
- ExtensionRepository repository = this.extensionRepositoryManager.getRepository(repositoryId);
- if (isGivenVersionOneOfExtensionVersions(repository, extensionId, extensionVersion)) {
- return repository.resolve(new ExtensionId(extensionId, extensionVersion));
- } else {
- return tryToResolveExtensionFromExtensionFeatures(repository, extensionObject, extensionVersion);
- }
+ return this.extensionRepositoryManager.getRepository(repositoryId);
}
/**
@@ -1225,7 +1280,8 @@ private Extension tryToResolveExtensionFromExtensionFeatures(ExtensionRepository
{
List features =
(List) this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_FEATURES);
- return features.stream().map(feature -> {
+
+ return features == null ? null : features.stream().map(feature -> {
try {
String featureId = feature.split("/")[0];
return repository.resolve(new ExtensionId(featureId, extensionVersion));
@@ -1243,46 +1299,125 @@ private boolean isGivenVersionOneOfExtensionVersions(ExtensionRepository reposit
.anyMatch(version -> version.getValue().equals(extensionVersion));
}
- private boolean updateExtensionVersion(XWikiDocument document, Extension extension) throws XWikiException
+ private void moveLegacyVersion(XWikiDocument extensionDocument, BaseObject versionObject) throws XWikiException
{
- boolean needSave = false;
-
XWikiContext xcontext = this.xcontextProvider.get();
+ // Resolve the version
+ String version = versionObject.getStringValue(XWikiRepositoryModel.PROP_VERSION_VERSION);
+
+ // Resolve the version document
+ XWikiDocument extensionVersionDocument = this.extensionStore
+ .getExtensionVersionDocument(extensionDocument, new DefaultVersion(version), xcontext).clone();
+
+ extensionVersionDocument.addXObject(versionObject.clone());
+
+ // Save if dedicated version page
+ saveDocument(extensionVersionDocument, "Migrate the extension version", xcontext);
+ }
+
+ private boolean updateExtensionVersion(Extension extensionVersion, XWikiDocument extensionVersionDocument,
+ long index, XWikiContext xcontext) throws XWikiException
+ {
+ boolean needSave = false;
+
// Update version object
- BaseObject versionObject = getExtensionVersion(document, extension.getId().getVersion());
+ BaseObject versionObject = this.extensionStore.getExtensionVersionObject(extensionVersionDocument,
+ extensionVersion.getId().getVersion());
if (versionObject == null) {
- versionObject = document.newXObject(XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE, xcontext);
+ versionObject =
+ extensionVersionDocument.newXObject(XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE, xcontext);
- versionObject.set(XWikiRepositoryModel.PROP_VERSION_VERSION, extension.getId().getVersion().getValue(),
- xcontext);
+ versionObject.set(XWikiRepositoryModel.PROP_VERSION_VERSION,
+ extensionVersion.getId().getVersion().getValue(), xcontext);
needSave = true;
}
// Id
- needSave |= update(versionObject, XWikiRepositoryModel.PROP_VERSION_ID, extension.getId().getId());
+ needSave |= update(versionObject, XWikiRepositoryModel.PROP_VERSION_ID, extensionVersion.getId().getId());
// Features
- needSave |=
- updateFeatures(XWikiRepositoryModel.PROP_VERSION_FEATURES, versionObject, extension.getExtensionFeatures());
+ needSave |= updateFeatures(XWikiRepositoryModel.PROP_VERSION_FEATURES, versionObject,
+ extensionVersion.getExtensionFeatures());
// Repositories
- List repositories = XWikiRepositoryModel.toStringList(extension.getRepositories());
+ List repositories = XWikiRepositoryModel.toStringList(extensionVersion.getRepositories());
needSave |= update(versionObject, XWikiRepositoryModel.PROP_VERSION_REPOSITORIES, repositories);
// Update dependencies
- needSave |= updateExtensionVersionDependencies(document, extension);
+ needSave |= updateExtensionVersionDependencies(extensionVersion, extensionVersionDocument);
// Download
- if (!StringUtils.isEmpty(extension.getType())) {
- String download = getDownloadURL(extension);
+ if (!StringUtils.isEmpty(extensionVersion.getType())) {
+ String download = getDownloadURL(extensionVersion);
needSave |= update(versionObject, XWikiRepositoryModel.PROP_VERSION_DOWNLOAD, download);
}
+ // Common properties
+ needSave |= updateExtension(extensionVersion, versionObject, xcontext);
+
+ // index
+ needSave |= update(versionObject, XWikiRepositoryModel.PROP_VERSION_INDEX, index);
+
return needSave;
}
+ private boolean updateExtensionVersion(Extension extensionVersion, XWikiDocument extensiondocument, long index,
+ boolean save) throws XWikiException
+ {
+ boolean needSave = false;
+
+ XWikiContext xcontext = this.xcontextProvider.get();
+
+ // Resolve the version document
+ XWikiDocument extensionVersionDocument = this.extensionStore.getExtensionVersionDocument(extensiondocument,
+ extensionVersion.getId().getVersion(), xcontext);
+ if (extensionVersionDocument.isNew()) {
+ // New document version
+ needSave = true;
+ }
+
+ // Avoid modifying the cached document
+ if (save) {
+ extensionVersionDocument = extensionVersionDocument.clone();
+ }
+
+ needSave |= updateExtensionVersion(extensionVersion, extensionVersionDocument, index, xcontext);
+
+ // Save if dedicated version page
+ if (save) {
+ // Make sure the Versions home page exist
+ updateVersionHome(extensiondocument, xcontext);
+
+ if (needSave) {
+ boolean versionPageEnabled = this.extensionStore.isVersionPageEnabled(extensiondocument);
+ if (versionPageEnabled) {
+ // Save the version
+ saveDocument(extensionVersionDocument, "Update", xcontext);
+
+ // Since the data are saved, there is no point saving the extension document
+ return false;
+ }
+ }
+ }
+
+ return needSave;
+ }
+
+ private void updateVersionHome(XWikiDocument extensiondocument, XWikiContext xcontext) throws XWikiException
+ {
+ PageReference versionsReference = new PageReference("Versions", extensiondocument.getPageReference());
+
+ if (!xcontext.getWiki().exists(versionsReference, xcontext)) {
+ XWikiDocument versionsDocument = xcontext.getWiki().getDocument(versionsReference, xcontext);
+
+ versionsDocument.setContent("{{include reference=\"ExtensionCode.VersionsHome\"/}}", Syntax.XWIKI_2_1);
+
+ saveDocument(versionsDocument, "", xcontext);
+ }
+ }
+
private String getDownloadURL(Extension extension)
{
ExtensionResourceReference resource = new ExtensionResourceReference(extension.getId().getId(),
@@ -1353,63 +1488,4 @@ private boolean updateCollection(BaseObject extensionObject, String fieldName, C
return needSave;
}
-
- /**
- * @since 9.5RC1
- */
- public BaseObject getExtensionVersionObject(XWikiDocument extensionDocument, String version)
- {
- return getExtensionVersionObject(extensionDocument, version, true);
- }
-
- /**
- * @since 9.5RC1
- */
- public BaseObject getExtensionVersionObject(XWikiDocument extensionDocument, String version, boolean allowProxying)
- {
- if (version == null) {
- List objects =
- extensionDocument.getXObjects(XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE);
-
- if (objects == null || objects.isEmpty()) {
- return null;
- } else {
- return objects.get(objects.size() - 1);
- }
- }
-
- BaseObject extensionVersionObject = extensionDocument
- .getXObject(XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE, "version", version, false);
-
- if (extensionVersionObject == null && allowProxying && isVersionProxyingEnabled(extensionDocument)) {
- // No ExtensionVersionClass object for the version, but proxy is enabled, so try to find remotely
- Extension extension = null;
- try {
- extension = resolveExtensionVersion(extensionDocument, version);
- } catch (ExtensionNotFoundException e) {
- this.logger.debug("No extension could be found remotely with version [{}] for extension page [{}]",
- version, extensionDocument.getDocumentReference());
- } catch (ResolveException e) {
- throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR);
- }
-
- // No extension could be found for the provided version
- if (extension == null) {
- return null;
- }
-
- // Create a temporary xobject for that extension version
- // FIXME: find a more elegant solution
- try {
- XWikiDocument extensionDocumentClone = extensionDocument.clone();
- updateExtensionVersion(extensionDocumentClone, extension);
- extensionVersionObject = extensionDocumentClone
- .getXObject(XWikiRepositoryModel.EXTENSIONVERSION_CLASSREFERENCE, "version", version, false);
- } catch (XWikiException e) {
- throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR);
- }
- }
-
- return extensionVersionObject;
- }
}
diff --git a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/XWikiRepositoryModel.java b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/XWikiRepositoryModel.java
index 4cb012795261..c681940412cd 100644
--- a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/XWikiRepositoryModel.java
+++ b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/XWikiRepositoryModel.java
@@ -51,6 +51,11 @@ public class XWikiRepositoryModel
*/
public static final String EXTENSION_SPACENAME = "ExtensionCode";
+ /**
+ * @since 17.9.0RC1
+ */
+ public static final String EXTENSIONVERSIONS_SPACENAME = "Versions";
+
public static final String EXTENSION_CLASSNAME = EXTENSION_SPACENAME + ".ExtensionClass";
public static final String AVERAGERATING_CLASSNAME = "XWiki.AverageRatingsClass";
@@ -187,6 +192,11 @@ public class XWikiRepositoryModel
public static final String PROP_EXTENSION_PROPERTIES = "properties";
+ /**
+ * @since 17.9.0RC1
+ */
+ public static final String PROP_EXTENSION_VERSIONPAGE = "versionPage";
+
public static final String PROP_VERSION_ID = "id";
public static final String PROP_VERSION_VERSION = "version";
@@ -198,6 +208,11 @@ public class XWikiRepositoryModel
*/
public static final String PROP_VERSION_FEATURES = "features";
+ /**
+ * @since 17.9.0RC1
+ */
+ public static final String PROP_VERSION_INDEX = "index";
+
/**
* @since 7.3M1
*/
diff --git a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/resources/AbstractExtensionRESTResource.java b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/resources/AbstractExtensionRESTResource.java
index 802313f1e459..803ef2499e62 100644
--- a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/resources/AbstractExtensionRESTResource.java
+++ b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/resources/AbstractExtensionRESTResource.java
@@ -63,6 +63,7 @@
import org.xwiki.extension.repository.xwiki.model.jaxb.Namespaces;
import org.xwiki.extension.repository.xwiki.model.jaxb.ObjectFactory;
import org.xwiki.extension.repository.xwiki.model.jaxb.Property;
+import org.xwiki.extension.version.Version;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.DocumentReferenceResolver;
import org.xwiki.query.Query;
@@ -93,38 +94,28 @@
*/
public abstract class AbstractExtensionRESTResource extends XWikiResource implements Initializable
{
- public static final String[] EPROPERTIES_SUMMARY = new String[] {XWikiRepositoryModel.PROP_EXTENSION_ID,
- XWikiRepositoryModel.PROP_EXTENSION_TYPE, XWikiRepositoryModel.PROP_EXTENSION_NAME};
-
protected static final String DEFAULT_BOOST;
protected static final String DEFAULT_FL;
- protected static Map EPROPERTIES_INDEX = new HashMap();
-
- protected static String SELECT_EXTENSIONSUMMARY;
+ protected static final Map EPROPERTIES_INDEX =
+ Map.of(XWikiRepositoryModel.PROP_EXTENSION_ID, 0, XWikiRepositoryModel.PROP_EXTENSION_NAME, 1,
+ XWikiRepositoryModel.PROP_EXTENSION_TYPE, 2, XWikiRepositoryModel.PROP_VERSION_VERSION, 3);
- static {
- StringBuilder pattern = new StringBuilder();
+ // Note that the order of the retrieved information is stable and documented by EPROPERTIES_INDEX,
+ // therefore it shouldn't be changed or it would break some of the APIs relying on it.
+ protected static final String SELECT_EXTENSIONSUMMARY = String.format(
+ "doc.name, doc.space, " + "extension.%s, extension.%s, extension.%s", XWikiRepositoryModel.PROP_EXTENSION_ID,
+ XWikiRepositoryModel.PROP_EXTENSION_NAME, XWikiRepositoryModel.PROP_EXTENSION_TYPE);
- int j = 0;
-
- pattern.append("doc.name");
- EPROPERTIES_INDEX.put("doc.name", j++);
- pattern.append(", ");
- pattern.append("doc.space");
- EPROPERTIES_INDEX.put("doc.space", j++);
-
- // Extension summary
- for (int i = 0; i < EPROPERTIES_SUMMARY.length; ++i, ++j) {
- String value = EPROPERTIES_SUMMARY[i];
- pattern.append(", extension.");
- pattern.append(value);
- EPROPERTIES_INDEX.put(value, j);
- }
-
- SELECT_EXTENSIONSUMMARY = pattern.toString();
+ protected static final String SELECT_EXTENSION_VERSION = String.format(
+ "doc.name, doc.space, " + "extensionVersion.%s, extensionVersion.%s, extensionVersion.%s, "
+ + "extensionVersion.%s, extensionVersion.%s",
+ XWikiRepositoryModel.PROP_EXTENSION_ID, XWikiRepositoryModel.PROP_EXTENSION_NAME,
+ XWikiRepositoryModel.PROP_EXTENSION_TYPE, XWikiRepositoryModel.PROP_VERSION_VERSION,
+ XWikiRepositoryModel.PROP_VERSION_INDEX);
+ static {
// Solr
StringBuilder boostBuilder = new StringBuilder();
@@ -132,7 +123,7 @@ public abstract class AbstractExtensionRESTResource extends XWikiResource implem
for (SolrField field : XWikiRepositoryModel.SOLR_FIELDS.values()) {
// Boost
if (field.boostValue != null) {
- if (boostBuilder.length() > 0) {
+ if (!boostBuilder.isEmpty()) {
boostBuilder.append(' ');
}
boostBuilder.append(field.boostName);
@@ -142,7 +133,7 @@ public abstract class AbstractExtensionRESTResource extends XWikiResource implem
// Fields list
if (field.name != null) {
- if (flBuilder.length() > 0) {
+ if (!flBuilder.isEmpty()) {
flBuilder.append(',');
}
flBuilder.append(field.name);
@@ -188,7 +179,7 @@ public void initialize() throws InitializationException
public XWikiDocument getExistingExtensionDocumentById(String extensionId) throws QueryException, XWikiException
{
- XWikiDocument document = this.repositoryManager.getExistingExtensionDocumentById(extensionId);
+ XWikiDocument document = this.extensionStore.getExistingExtensionDocumentById(extensionId);
if (document == null) {
throw new WebApplicationException(Status.NOT_FOUND);
@@ -203,7 +194,7 @@ protected Query createExtensionsCountQuery(String from, String where) throws Que
String select = "count(extension." + XWikiRepositoryModel.PROP_EXTENSION_ID + ")";
- return createExtensionsQuery(select, from, where, 0, -1, false);
+ return createExtensionsQuery(select, from, where, 0, -1, false, false);
}
protected long getExtensionsCountResult(Query query) throws QueryException
@@ -211,31 +202,36 @@ protected long getExtensionsCountResult(Query query) throws QueryException
return ((Number) query.execute().get(0)).intValue();
}
- protected Query createExtensionsSummariesQuery(String from, String where, int offset, int number, boolean versions)
- throws QueryException
+ protected Query createExtensionsSummariesQuery(String from, String where, int offset, int number, boolean versions,
+ boolean pageVersion) throws QueryException
{
String select = SELECT_EXTENSIONSUMMARY;
- return createExtensionsQuery(select, from, where, offset, number, versions);
+ if (versions && pageVersion) {
+ select = SELECT_EXTENSION_VERSION;
+ }
+
+ return createExtensionsQuery(select, from, where, offset, number, versions, pageVersion);
}
private Query createExtensionsQuery(String select, String from, String where, int offset, int number,
- boolean versions) throws QueryException
+ boolean versions, boolean pageVersion) throws QueryException
{
// select
StringBuilder queryStr = new StringBuilder("select ");
queryStr.append(select);
- if (versions) {
+ if (versions && !pageVersion) {
queryStr.append(", extensionVersion." + XWikiRepositoryModel.PROP_VERSION_VERSION + "");
}
- // from
-
- queryStr
- .append(" from Document doc, doc.object(" + XWikiRepositoryModel.EXTENSION_CLASSNAME + ") as extension");
+ queryStr.append(" from Document doc");
+ // from
+ if (!pageVersion) {
+ queryStr.append(", doc.object(" + XWikiRepositoryModel.EXTENSION_CLASSNAME + ") as extension");
+ }
if (versions) {
queryStr
.append(", doc.object(" + XWikiRepositoryModel.EXTENSIONVERSION_CLASSNAME + ") as extensionVersion");
@@ -253,9 +249,15 @@ private Query createExtensionsQuery(String select, String from, String where, in
queryStr.append('(');
queryStr.append(where);
queryStr.append(')');
- queryStr.append(" and ");
}
- queryStr.append("extension." + XWikiRepositoryModel.PROP_EXTENSION_VALIDEXTENSION + " = 1");
+ if (versions && pageVersion) {
+ queryStr.append(" order by extensionVersion." + XWikiRepositoryModel.PROP_VERSION_INDEX);
+ } else {
+ if (where != null) {
+ queryStr.append(" and ");
+ }
+ queryStr.append("extension." + XWikiRepositoryModel.PROP_EXTENSION_VALIDEXTENSION + " = 1");
+ }
Query query = this.queryManager.createQuery(queryStr.toString(), Query.XWQL);
@@ -315,8 +317,11 @@ protected void addLicense(AbstractExtension extension, String licenseName)
}
protected E createExtension(XWikiDocument extensionDocument, String version)
+ throws XWikiException
{
BaseObject extensionObject = getExtensionObject(extensionDocument);
+ XWikiDocument versionDocument =
+ this.extensionStore.getExtensionVersionDocument(extensionDocument, version, getXWikiContext());
DocumentReference extensionDocumentReference = extensionDocument.getDocumentReference();
if (extensionObject == null) {
@@ -326,12 +331,15 @@ protected E createExtension(XWikiDocument extensio
AbstractExtension extension;
ExtensionVersion extensionVersion;
BaseObject extensionVersionObject;
+ List extensionVersionObjects;
if (version == null) {
extension = this.extensionObjectFactory.createExtension();
extensionVersion = null;
- extensionVersionObject = null;
+ extensionVersionObject = extensionObject;
+ extensionVersionObjects = List.of(extensionVersionObject);
} else {
- extensionVersionObject = repositoryManager.getExtensionVersionObject(extensionDocument, version);
+ extensionVersionObject =
+ this.repositoryManager.getExtensionVersionObject(extensionDocument, version, getXWikiContext());
if (extensionVersionObject == null) {
throw new WebApplicationException(Status.NOT_FOUND);
@@ -339,29 +347,31 @@ protected E createExtension(XWikiDocument extensio
extensionVersion = this.extensionObjectFactory.createExtensionVersion();
extension = extensionVersion;
- extensionVersion.setVersion((String) this.extensionStore.getValue(extensionVersionObject,
- XWikiRepositoryModel.PROP_VERSION_VERSION));
+ extensionVersion.setVersion(
+ this.extensionStore.getValue(extensionVersionObject, XWikiRepositoryModel.PROP_VERSION_VERSION));
+
+ extensionVersionObjects = List.of(extensionVersionObject, extensionObject);
}
- extension.setId((String) this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_ID));
+ extension.setId(this.extensionStore.getValue(extensionVersionObjects, XWikiRepositoryModel.PROP_EXTENSION_ID));
extension.setType(StringUtils.stripToNull(
- (String) this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_TYPE)));
+ this.extensionStore.getValue(extensionVersionObjects, XWikiRepositoryModel.PROP_EXTENSION_TYPE)));
extension.setRating(getExtensionRating(extensionDocumentReference));
extension.setSummary(
- (String) this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_SUMMARY));
+ this.extensionStore.getValue(extensionVersionObjects, XWikiRepositoryModel.PROP_EXTENSION_SUMMARY));
extension.setDescription(
- (String) this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_DESCRIPTION));
+ this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_DESCRIPTION));
extension
- .setName((String) this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_NAME));
+ .setName(this.extensionStore.getValue(extensionVersionObjects, XWikiRepositoryModel.PROP_EXTENSION_NAME));
extension.setCategory(
- (String) this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_CATEGORY));
+ this.extensionStore.getValue(extensionVersionObjects, XWikiRepositoryModel.PROP_EXTENSION_CATEGORY));
extension.setWebsite(StringUtils.defaultIfEmpty(
- (String) this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_WEBSITE),
+ this.extensionStore.getValue(extensionVersionObjects, XWikiRepositoryModel.PROP_EXTENSION_WEBSITE),
extensionDocument.getExternalURL("view", getXWikiContext())));
// Recommended
- extension.setRecommended(this.extensionStore.getBooleanValue(extensionVersionObject,
+ extension.setRecommended(this.extensionStore.getBooleanValue(extensionObject,
XWikiRepositoryModel.PROP_EXTENSION_RECOMMENDED, false));
// Support plans
@@ -370,18 +380,18 @@ protected E createExtension(XWikiDocument extensio
// SCM
ExtensionScm scm = new ExtensionScm();
- scm.setUrl((String) this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_SCMURL));
+ scm.setUrl(this.extensionStore.getValue(extensionVersionObjects, XWikiRepositoryModel.PROP_EXTENSION_SCMURL));
scm.setConnection(toScmConnection(
- (String) this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_SCMCONNECTION)));
- scm.setDeveloperConnection(toScmConnection((String) this.extensionStore.getValue(extensionObject,
+ this.extensionStore.getValue(extensionVersionObjects, XWikiRepositoryModel.PROP_EXTENSION_SCMCONNECTION)));
+ scm.setDeveloperConnection(toScmConnection(this.extensionStore.getValue(extensionVersionObjects,
XWikiRepositoryModel.PROP_EXTENSION_SCMDEVCONNECTION)));
extension.setScm(scm);
// Issue Management
ExtensionIssueManagement issueManagement = new ExtensionIssueManagement();
- issueManagement.setSystem((String) this.extensionStore.getValue(extensionObject,
+ issueManagement.setSystem(this.extensionStore.getValue(extensionVersionObjects,
XWikiRepositoryModel.PROP_EXTENSION_ISSUEMANAGEMENT_SYSTEM));
- issueManagement.setUrl((String) this.extensionStore.getValue(extensionObject,
+ issueManagement.setUrl(this.extensionStore.getValue(extensionVersionObjects,
XWikiRepositoryModel.PROP_EXTENSION_ISSUEMANAGEMENT_URL));
if (StringUtils.isNotEmpty(issueManagement.getSystem()) || StringUtils.isNotEmpty(issueManagement.getUrl())) {
extension.setIssueManagement(issueManagement);
@@ -389,37 +399,21 @@ protected E createExtension(XWikiDocument extensio
// Authors
addExtensionAuthors(extension,
- this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_AUTHORS));
+ this.extensionStore.getValue(extensionVersionObjects, XWikiRepositoryModel.PROP_EXTENSION_AUTHORS));
// Features
- List features;
- if (extensionVersionObject != null) {
- features = (List) this.extensionStore.getValue(extensionVersionObject,
- XWikiRepositoryModel.PROP_VERSION_FEATURES);
- } else {
- features = (List) this.extensionStore.getValue(extensionObject,
- XWikiRepositoryModel.PROP_EXTENSION_FEATURES);
- }
- if (features != null && !features.isEmpty()) {
- for (String feature : features) {
- org.xwiki.extension.ExtensionId extensionId = ExtensionIdConverter.toExtensionId(feature, null);
- ExtensionId extensionFeature = this.extensionObjectFactory.createExtensionId();
- extensionFeature.setId(extensionId.getId());
- if (extensionId.getVersion() != null) {
- extensionFeature.setVersion(extensionId.getVersion().getValue());
- }
- extension.getExtensionFeatures().add(extensionFeature);
- extension.getFeatures().add(extensionFeature.getId());
- }
- }
+ List features =
+ this.extensionStore.getValue(extensionVersionObject, XWikiRepositoryModel.PROP_VERSION_FEATURES);
+
+ extractFeatureInformation(features, extension);
// License
addLicense(extension,
this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_LICENSENAME));
// Allowed namespaces
- List namespaces = (List) this.extensionStore.getValue(extensionObject,
- XWikiRepositoryModel.PROP_EXTENSION_ALLOWEDNAMESPACES);
+ List namespaces =
+ this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_ALLOWEDNAMESPACES);
Integer namespacesEmpty = this.extensionStore.getValue(extensionObject,
XWikiRepositoryModel.PROP_EXTENSION_ALLOWEDNAMESPACES_EMPTY, 0);
if (namespaces != null && (!namespaces.isEmpty() || namespacesEmpty == 1)) {
@@ -429,35 +423,32 @@ protected E createExtension(XWikiDocument extensio
}
// Properties
- addProperties(extension, (List) this.extensionStore.getValue(extensionObject,
- XWikiRepositoryModel.PROP_EXTENSION_PROPERTIES));
+ addProperties(extension,
+ this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_PROPERTIES));
if (extensionVersion != null) {
- // Repositories
- if (extensionVersionObject != null) {
- List repositories = (List) this.extensionStore.getValue(extensionVersionObject,
- XWikiRepositoryModel.PROP_VERSION_REPOSITORIES);
- extensionVersion.withRepositories(toExtensionRepositories(repositories));
- }
+ List repositories =
+ this.extensionStore.getValue(extensionVersionObjects, XWikiRepositoryModel.PROP_VERSION_REPOSITORIES);
+ extensionVersion.withRepositories(toExtensionRepositories(repositories));
// Dependencies
List dependencies =
- extensionDocument.getXObjects(XWikiRepositoryModel.EXTENSIONDEPENDENCY_CLASSREFERENCE);
+ versionDocument.getXObjects(XWikiRepositoryModel.EXTENSIONDEPENDENCY_CLASSREFERENCE);
if (dependencies != null) {
for (BaseObject dependencyObject : dependencies) {
if (dependencyObject != null) {
if (Strings.CS.equals(this.extensionStore.getValue(dependencyObject,
- XWikiRepositoryModel.PROP_DEPENDENCY_EXTENSIONVERSION, (String) null), version)) {
+ XWikiRepositoryModel.PROP_DEPENDENCY_EXTENSIONVERSION, null), version)) {
ExtensionDependency dependency = extensionObjectFactory.createExtensionDependency();
- dependency.setId((String) this.extensionStore.getValue(dependencyObject,
+ dependency.setId(this.extensionStore.getValue(dependencyObject,
XWikiRepositoryModel.PROP_DEPENDENCY_ID));
- dependency.setConstraint((String) this.extensionStore.getValue(dependencyObject,
+ dependency.setConstraint(this.extensionStore.getValue(dependencyObject,
XWikiRepositoryModel.PROP_DEPENDENCY_CONSTRAINT));
dependency.setOptional(this.extensionStore.getBooleanValue(dependencyObject,
XWikiRepositoryModel.PROP_DEPENDENCY_OPTIONAL, false));
- List repositories = (List) this.extensionStore.getValue(dependencyObject,
+ List dependencyRepositories = this.extensionStore.getValue(dependencyObject,
XWikiRepositoryModel.PROP_DEPENDENCY_REPOSITORIES);
- dependency.withRepositories(toExtensionRepositories(repositories));
+ dependency.withRepositories(toExtensionRepositories(dependencyRepositories));
extensionVersion.getDependencies().add(dependency);
}
@@ -469,6 +460,22 @@ protected E createExtension(XWikiDocument extensio
return (E) extension;
}
+ private void extractFeatureInformation(Collection features, AbstractExtension extension)
+ {
+ if (features != null && !features.isEmpty()) {
+ for (String feature : features) {
+ org.xwiki.extension.ExtensionId extensionId = ExtensionIdConverter.toExtensionId(feature, null);
+ ExtensionId extensionFeature = this.extensionObjectFactory.createExtensionId();
+ extensionFeature.setId(extensionId.getId());
+ if (extensionId.getVersion() != null) {
+ extensionFeature.setVersion(extensionId.getVersion().getValue());
+ }
+ extension.getExtensionFeatures().add(extensionFeature);
+ extension.getFeatures().add(extensionFeature.getId());
+ }
+ }
+ }
+
protected ExtensionScmConnection toScmConnection(String connectionString)
{
if (connectionString != null) {
@@ -675,18 +682,7 @@ protected ExtensionVersion createExtensionVersionFromSolrDocument(SolrDocument d
// Features
Collection features = getSolrValues(document, Extension.FIELD_FEATURES);
- if (features != null && !features.isEmpty()) {
- for (String feature : features) {
- org.xwiki.extension.ExtensionId extensionId = ExtensionIdConverter.toExtensionId(feature, null);
- ExtensionId extensionFeature = this.extensionObjectFactory.createExtensionId();
- extensionFeature.setId(extensionId.getId());
- if (extensionId.getVersion() != null) {
- extensionFeature.setVersion(extensionId.getVersion().getValue());
- }
- extension.getExtensionFeatures().add(extensionFeature);
- extension.getFeatures().add(extensionFeature.getId());
- }
- }
+ extractFeatureInformation(features, extension);
// License
addLicense(extension, getSolrValue(document, Extension.FIELD_LICENSE, true));
@@ -751,6 +747,18 @@ protected ExtensionRating getExtensionRating(DocumentReference extensionDocument
return extensionRating;
}
+ protected ExtensionVersionSummary createExtensionVersionSummary(String extensionId, String type, String name,
+ Version version)
+ {
+ ExtensionVersionSummary extensionVersion = this.extensionObjectFactory.createExtensionVersionSummary();
+ extensionVersion.setVersion(version.getValue());
+ extensionVersion.setId(extensionId);
+ extensionVersion.setType(type);
+ extensionVersion.setName(name);
+
+ return extensionVersion;
+ }
+
protected void getExtensionSummaries(List extensions, Query query)
throws QueryException
{
@@ -764,7 +772,7 @@ protected void getExtensionSummaries(List extens
protected ExtensionSummary createExtensionSummaryFromQueryResult(Object[] entry)
{
ExtensionSummary extension;
- int versionIndex = EPROPERTIES_INDEX.get(EPROPERTIES_SUMMARY[EPROPERTIES_SUMMARY.length - 1]) + 1;
+ int versionIndex = EPROPERTIES_INDEX.get(XWikiRepositoryModel.PROP_VERSION_VERSION);
if (entry.length == versionIndex) {
// It's a extension summary without version
extension = this.extensionObjectFactory.createExtensionSummary();
diff --git a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/resources/ExtensionVersionFileRESTResource.java b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/resources/ExtensionVersionFileRESTResource.java
index c40cd6f6d1d7..f2d21554031f 100644
--- a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/resources/ExtensionVersionFileRESTResource.java
+++ b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/resources/ExtensionVersionFileRESTResource.java
@@ -115,7 +115,7 @@ private ResponseBuilder downloadLocalExtension(String extensionId, String extens
checkRights(extensionDocument);
ResourceReference resourceReference =
- repositoryManager.getDownloadReference(extensionDocument, extensionVersion);
+ this.repositoryManager.getDownloadReference(extensionDocument, extensionVersion);
ResponseBuilder response = null;
@@ -166,7 +166,8 @@ private ResponseBuilder downloadLocalExtension(String extensionId, String extens
response.type(type);
BaseObject extensionObject = getExtensionObject(extensionDocument);
- String extensionType = this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_TYPE);
+ String extensionType =
+ this.extensionStore.getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_TYPE);
response.entity(entity.getContent());
response.header("Content-Disposition",
"attachment; filename=\"" + extensionId + '-' + extensionVersion + '.' + extensionType + "\"");
diff --git a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/resources/ExtensionVersionsRESTResource.java b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/resources/ExtensionVersionsRESTResource.java
index ede02ee92eb5..d2ecbaf60b5c 100644
--- a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/resources/ExtensionVersionsRESTResource.java
+++ b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/resources/ExtensionVersionsRESTResource.java
@@ -21,12 +21,8 @@
package org.xwiki.repository.internal.resources;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import javax.inject.Named;
import javax.ws.rs.DefaultValue;
@@ -37,6 +33,9 @@
import org.apache.commons.lang3.StringUtils;
import org.xwiki.component.annotation.Component;
+import org.xwiki.extension.ResolveException;
+import org.xwiki.extension.repository.ExtensionRepository;
+import org.xwiki.extension.repository.result.IterableResult;
import org.xwiki.extension.repository.xwiki.model.jaxb.ExtensionVersionSummary;
import org.xwiki.extension.repository.xwiki.model.jaxb.ExtensionVersions;
import org.xwiki.extension.version.InvalidVersionRangeException;
@@ -47,6 +46,9 @@
import org.xwiki.query.QueryException;
import org.xwiki.repository.Resources;
+import com.xpn.xwiki.XWikiException;
+import com.xpn.xwiki.doc.XWikiDocument;
+
/**
* @version $Id$
* @since 3.2M3
@@ -60,15 +62,37 @@ public class ExtensionVersionsRESTResource extends AbstractExtensionRESTResource
public ExtensionVersions getExtensionVersions(@PathParam("extensionId") String extensionId,
@QueryParam(Resources.QPARAM_LIST_START) @DefaultValue("0") int offset,
@QueryParam(Resources.QPARAM_LIST_NUMBER) @DefaultValue("-1") int number,
- @QueryParam(Resources.QPARAM_VERSIONS_RANGES) String ranges) throws QueryException, InvalidVersionRangeException
+ @QueryParam(Resources.QPARAM_VERSIONS_RANGES) String ranges)
+ throws QueryException, InvalidVersionRangeException, XWikiException, ResolveException
{
- Query query = createExtensionsSummariesQuery(null, "extension.id = :extensionId", 0, -1, true);
+ XWikiDocument extensionDocument = getExistingExtensionDocumentById(extensionId);
- query.bindValue("extensionId", extensionId);
+ checkRights(extensionDocument);
ExtensionVersions extensions = this.extensionObjectFactory.createExtensionVersions();
- getExtensionSummaries(extensions.getExtensionVersionSummaries(), query);
+ if (this.extensionStore.isVersionProxyingEnabled(extensionDocument)) {
+ ExtensionRepository repository = this.repositoryManager.getExtensionRepository(extensionDocument);
+ if (repository != null) {
+ IterableResult versions = repository.resolveVersions(extensionId, 0, -1);
+
+ String extensionName = this.extensionStore.getExtensionName(extensionDocument);
+ String extensionType = this.extensionStore.getExtensionType(extensionDocument);;
+
+ for (Version version : versions) {
+ extensions.getExtensionVersionSummaries()
+ .add(createExtensionVersionSummary(extensionId, extensionType, extensionName, version));
+ }
+ }
+ } else {
+ boolean versionPageEnabled = this.extensionStore.isVersionPageEnabled(extensionDocument);
+ Query query = createExtensionsSummariesQuery(null, "extensionVersion.id = :extensionId", 0, -1, true,
+ versionPageEnabled);
+
+ query.bindValue("extensionId", extensionId);
+
+ getExtensionSummaries(extensions.getExtensionVersionSummaries(), query);
+ }
// Filter by ranges
if (StringUtils.isNotBlank(ranges)) {
@@ -86,29 +110,6 @@ public ExtensionVersions getExtensionVersions(@PathParam("extensionId") String e
}
}
- // Order by version
- final Map versionCache = new HashMap<>();
- Collections.sort(extensions.getExtensionVersionSummaries(), new Comparator()
- {
- @Override
- public int compare(ExtensionVersionSummary o1, ExtensionVersionSummary o2)
- {
- return toVersion(o1.getVersion()).compareTo(toVersion(o2.getVersion()));
- }
-
- private Version toVersion(String versionString)
- {
- Version version = versionCache.get(versionString);
-
- if (version == null) {
- version = extensionFactory.getVersion(versionString);
- versionCache.put(versionString, version);
- }
-
- return version;
- }
- });
-
extensions.setTotalHits(extensions.getExtensionVersionSummaries().size());
extensions.setOffset(offset);
diff --git a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/resources/ExtensionsRESTResource.java b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/resources/ExtensionsRESTResource.java
index 9649bce608fa..85faf98cadfb 100644
--- a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/resources/ExtensionsRESTResource.java
+++ b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/internal/resources/ExtensionsRESTResource.java
@@ -59,7 +59,7 @@ public Extensions getExtensions(@QueryParam(Resources.QPARAM_LIST_START) @Defaul
extensions.setOffset(offset);
- Query query = createExtensionsSummariesQuery(null, null, offset, number, false);
+ Query query = createExtensionsSummariesQuery(null, null, offset, number, false, false);
getExtensionSummaries(extensions.getExtensionSummaries(), query);
diff --git a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/script/RepositoryScriptService.java b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/script/RepositoryScriptService.java
index 55e78e4304da..e327285f4395 100644
--- a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/script/RepositoryScriptService.java
+++ b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-api/src/main/java/org/xwiki/repository/script/RepositoryScriptService.java
@@ -23,6 +23,7 @@
import javax.inject.Inject;
import javax.inject.Named;
+import javax.inject.Provider;
import javax.inject.Singleton;
import org.xwiki.component.annotation.Component;
@@ -33,10 +34,16 @@
import org.xwiki.extension.repository.ExtensionRepositoryManager;
import org.xwiki.extension.version.Version;
import org.xwiki.model.reference.DocumentReference;
+import org.xwiki.query.QueryException;
import org.xwiki.repository.internal.ExtensionStore;
import org.xwiki.repository.internal.RepositoryManager;
import org.xwiki.script.service.ScriptService;
+import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.XWikiException;
+import com.xpn.xwiki.api.Object;
+import com.xpn.xwiki.doc.XWikiDocument;
+
@Component
@Named("repository")
@Singleton
@@ -62,6 +69,9 @@ public class RepositoryScriptService implements ScriptService
@Inject
private Execution execution;
+ @Inject
+ private Provider contextProvider;
+
/**
* Store a caught exception in the context, so that it can be later retrieved using {@link #getLastError()}.
*
@@ -122,4 +132,23 @@ public ExtensionSupportPlans resolveExtensionSupportPlans(Collection sup
{
return this.extensionStore.resolveExtensionSupportPlans(supportPlanIds);
}
+
+ /**
+ * @param extensionId the identifier of the extension
+ * @param version the version for which to find the object
+ * @return the object holding the extension version metadata
+ * @throws QueryException when failing to get the version object
+ * @throws XWikiException when failing to get the version object
+ * @since 17.9.0RC1
+ */
+ public Object getVersionObject(String extensionId, String version) throws QueryException, XWikiException
+ {
+ XWikiDocument extensionDoc = this.extensionStore.getExistingExtensionDocumentById(extensionId);
+ XWikiContext context = contextProvider.get();
+ // FIXME: add some checks
+ XWikiDocument extensionVersionDocument =
+ this.extensionStore.getExtensionVersionDocument(extensionDoc, version, context);
+ return new Object(this.extensionStore.getExtensionVersionObject(extensionVersionDocument, version),
+ context);
+ }
}
diff --git a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/ExtensionSheet.xml b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/ExtensionSheet.xml
index b5f3effc5807..3d82840dea68 100644
--- a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/ExtensionSheet.xml
+++ b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/ExtensionSheet.xml
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-->
-
+
ExtensionCode
ExtensionSheet
@@ -176,7 +176,7 @@
##------- Download button ------
#set($lastVersion = $doc.getValue("lastVersion"))
#if ("$!lastVersion" != '')
- #set ($lastVersionObject = $doc.getObject("ExtensionCode.ExtensionVersionClass", 'version', $lastVersion))
+ #set ($lastVersionObject = $services.repository.getVersionObject($extension.getProperty('id').value, $lastVersion))
#set ($version = $lastVersionObject.getProperty('version').value)
#set ($download = $lastVersionObject.getProperty("download").value)
#if ("$!download" == '')
@@ -303,7 +303,12 @@
#end
## Only display release notes if there are downloads and release notes
- #if ($lastVersionObject)
+ #if ($doc.getValue('versionPage') == 1)
+ #set ($versionPageRef = $services.model.createEntityReference('Versions', 'page', $doc.pageReference))
+ = Versions =
+
+ {{include page="$services.rendering.escape($services.model.serialize($versionPageRef), 'xwiki/2.1')"/}}
+ #elseif ($lastVersionObject)
#set ($releaseNotes = [])
#set ($versions = $doc.getObjects("ExtensionCode.ExtensionVersionClass"))
#foreach ($versionObject in $versions)
@@ -322,23 +327,23 @@
$entry.get(1)
#end
#end
+ #end
- #set($extensionDependencies = $doc.getObjects('ExtensionCode.ExtensionDependencyClass', 'extensionVersion', $lastVersionObject.getValue('version')))
- #if ($extensionDependencies.size() > 0)
- = Dependencies =
+ #set($extensionDependencies = $doc.getObjects('ExtensionCode.ExtensionDependencyClass', 'extensionVersion', $lastVersionObject.getValue('version')))
+ #if ($extensionDependencies.size() > 0)
+ = Dependencies =
- Dependencies for this extension ($services.rendering.escape("${extension.getValue('id')} ${doc.getValue('lastVersion')}", 'xwiki/2.1')):
- #foreach($extensionDependency in $extensionDependencies)
- #set($dependencyDocumentName = $null)
- #set($dependencyDocumentNames = $services.query.xwql('from doc.object(ExtensionCode.ExtensionClass) as extension where extension.id = :id').bindValue("id", $extensionDependency.id).execute())
- #if (!$dependencyDocumentNames.isEmpty())
- #set($dependencyDocumentName = $dependencyDocumentNames.get(0))
- #end
- #if ($dependencyDocumentName)
- * [[$services.rendering.escape($services.rendering.escape($extensionDependency.getValue('id'), 'xwiki/2.1'), 'xwiki/2.1')>>$services.rendering.escape($dependencyDocumentName, 'xwiki/2.1')]] $services.rendering.escape($extensionDependency.getValue('constraint'), 'xwiki/2.1')
- #else
- * $services.rendering.escape("${extensionDependency.getValue('id')} ${extensionDependency.getValue('constraint')}", 'xwiki/2.1')
- #end
+ Dependencies for this extension ($services.rendering.escape("${extension.getValue('id')} ${doc.getValue('lastVersion')}", 'xwiki/2.1')):
+ #foreach($extensionDependency in $extensionDependencies)
+ #set($dependencyDocumentName = $null)
+ #set($dependencyDocumentNames = $services.query.xwql('from doc.object(ExtensionCode.ExtensionClass) as extension where extension.id = :id').bindValue("id", $extensionDependency.id).execute())
+ #if (!$dependencyDocumentNames.isEmpty())
+ #set($dependencyDocumentName = $dependencyDocumentNames.get(0))
+ #end
+ #if ($dependencyDocumentName)
+ * [[$services.rendering.escape($services.rendering.escape($extensionDependency.getValue('id'), 'xwiki/2.1'), 'xwiki/2.1')>>$services.rendering.escape($dependencyDocumentName, 'xwiki/2.1')]] $services.rendering.escape($extensionDependency.getValue('constraint'), 'xwiki/2.1')
+ #else
+ * $services.rendering.escape("${extensionDependency.getValue('id')} ${extensionDependency.getValue('constraint')}", 'xwiki/2.1')
#end
#end
#end
@@ -405,8 +410,11 @@
0
+ long
0
select
+ forbidden
+ 0
0
cache
5
@@ -426,6 +434,7 @@
code
2
Code
+ 0
20
50
0
@@ -435,6 +444,8 @@
0
0
select
+ forbidden
+ 0
0
contentType
6
@@ -470,6 +481,8 @@
0
0
select
+ forbidden
+ 0
0
use
3
@@ -545,8 +558,11 @@
0
+ long
0
select
+ forbidden
+ 0
0
cache
5
@@ -566,6 +582,7 @@
code
2
Code
+ 0
20
50
0
@@ -575,6 +592,8 @@
0
0
select
+ forbidden
+ 0
0
contentType
6
@@ -610,6 +629,8 @@
0
0
select
+ forbidden
+ 0
0
use
3
diff --git a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/ExtensionVersionClass.xml b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/ExtensionVersionClass.xml
index b1dec9d138f1..7868b0d86b9f 100644
--- a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/ExtensionVersionClass.xml
+++ b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/ExtensionVersionClass.xml
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-->
-
+
ExtensionCode
ExtensionVersionClass
@@ -46,6 +46,99 @@
+
+ 0
+
+
+ 0
+ input
+
+
+ 0
+ 1
+ allowednamespaces
+ 26
+ 0
+ Allowed namespaces
+ 1
+
+ |
+ 1
+ none
+ 0
+
+
+
+ com.xpn.xwiki.objects.classes.StaticListClass
+
+
+
+ 0
+ 0
+ checkbox
+
+
+ allowednamespaces_empty
+ 27
+ Is allowed namespaces empty
+ 0
+
+
+ com.xpn.xwiki.objects.classes.BooleanClass
+
+
+ 0
+ {{include reference="ExtensionCode.ExtensionAuthorsDisplayer"/}}
+
+ 0
+ input
+
+
+ 0
+ 1
+ authors
+ 7
+ 0
+ Authors
+ 0
+
+ ,|
+ 30
+ none
+ 0
+
+
+
+ com.xpn.xwiki.objects.classes.StaticListClass
+
+
+ 0
+ ExtensionCode.ExtensionCategoryClass
+
+
+ 0
+ select
+
+
+ id
+ 0
+ 0
+ category
+ 16
+ 0
+ Category
+ 0
+
+
+ 1
+ value
+
+ 0
+
+
+ name
+ com.xpn.xwiki.objects.classes.DBListClass
+
PureText
@@ -56,6 +149,7 @@
2
0
Download URL
+ 0
1
100
0
@@ -66,9 +160,12 @@
0
+
0
input
+
+ 0
1
features
5
@@ -99,6 +196,59 @@
com.xpn.xwiki.objects.classes.StringClass
+
+
+ 0
+
+ index
+ 20
+ long
+ index
+ 30
+ 0
+
+
+ com.xpn.xwiki.objects.classes.NumberClass
+
+
+ 0
+
+
+ 0
+ select
+
+
+ 0
+ 0
+ licenseName
+ 10
+ 0
+ License Name
+ 0
+
+ ,|
+ 1
+ none
+ 0
+
+
+ GNU General Public License 1|GNU General Public License 2|GNU General Public License 3|GNU Lesser General Public License 2|GNU Lesser General Public License 2.1|GNU Lesser General Public License 3|Apache License 2.0|BSD license|Modified BSD License|Simplified BSD License|GNU Affero General Public License 3|GNU Free Documentation License 1.1|GNU Free Documentation License 1.2|GNU Free Documentation License 1.3|Educational Community License 1.0|Educational Community License 2.0|Do What The Fuck You Want To Public License 2
+ com.xpn.xwiki.objects.classes.StaticListClass
+
+
+
+ 0
+
+ name
+ 3
+ 0
+ Name
+ 30
+ 0
+
+
+ com.xpn.xwiki.objects.classes.StringClass
+
---
@@ -109,6 +259,7 @@
1
0
Release Notes
+ 0
15
75
0
@@ -116,12 +267,40 @@
com.xpn.xwiki.objects.classes.TextAreaClass
+
+ 0
+
+
+ 0
+ input
+
+
+ 0
+ 1
+ properties
+ 17
+ 0
+ Properties
+ 1
+
+ |
+ 1
+ none
+ 0
+
+
+
+ com.xpn.xwiki.objects.classes.StaticListClass
+
0
+
0
input
+
+ 0
1
repositories
6
@@ -138,6 +317,102 @@
com.xpn.xwiki.objects.classes.StaticListClass
+
+ PureText
+
+ 0
+ ---
+
+ scmconnection
+ 25
+ 0
+ Sources connection
+ 0
+ 1
+ 100
+ 0
+
+
+ com.xpn.xwiki.objects.classes.TextAreaClass
+
+
+ PureText
+
+ 0
+ ---
+
+ scmdevconnection
+ 26
+ 0
+ Sources dev connection
+ 0
+ 1
+ 100
+ 0
+
+
+ com.xpn.xwiki.objects.classes.TextAreaClass
+
+
+ PureText
+
+ 0
+ ---
+
+ source
+ 24
+ 0
+ Source
+ 0
+ 1
+ 100
+ 0
+
+
+ com.xpn.xwiki.objects.classes.TextAreaClass
+
+
+
+ 0
+
+ summary
+ 4
+ 0
+ Summary
+ 75
+ 0
+
+
+ com.xpn.xwiki.objects.classes.StringClass
+
+
+ 0
+ ExtensionCode.ExtensionTypeClass
+
+
+ 0
+ select
+
+
+ id
+ 0
+ 0
+ type
+ 2
+ 0
+ Type
+ 0
+
+
+ 1
+ value
+
+ 0
+
+
+ name
+ com.xpn.xwiki.objects.classes.DBListClass
+
0
@@ -152,7 +427,69 @@
com.xpn.xwiki.objects.classes.StringClass
+
+ PureText
+
+ 0
+ ---
+
+ website
+ 6
+ 0
+ Website
+ 0
+ 1
+ 100
+ 0
+
+
+ com.xpn.xwiki.objects.classes.TextAreaClass
+
+
+ ExtensionCode.ExtensionVersionClass
+ 0
+ XWiki.ClassSheetBinding
+ 75bd5971-88a0-48b0-aa01-a817cbe3b4f9
+
+ XWiki.ClassSheetBinding
+
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+ input
+
+
+ 0
+ sheet
+ 1
+ 1
+ Sheet
+ 0
+
+
+ 30
+ none
+
+ 0
+
+
+
+ com.xpn.xwiki.objects.classes.PageClass
+
+
+
+ ExtensionCode.ExtensionVersionSheet
+
+
ExtensionCode.ExtensionVersionClass
0
@@ -180,10 +517,10 @@
1
1
Sheet
- 30
0
+ 30
none
0
diff --git a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/ExtensionVersionSheet.xml b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/ExtensionVersionSheet.xml
index a7e82ceffa6e..58004ad2c04e 100644
--- a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/ExtensionVersionSheet.xml
+++ b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/ExtensionVersionSheet.xml
@@ -20,7 +20,7 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-->
-
+
ExtensionCode
ExtensionVersionSheet
@@ -31,19 +31,151 @@
xwiki:XWiki.Admin
xwiki:XWiki.Admin
1.1
- ExtensionVersion Sheet
+ #if($doc.getObject('ExtensionCode.ExtensionVersionClass'))$doc.getObject('ExtensionCode.ExtensionVersionClass').getProperty('name').value $doc.getObject('ExtensionCode.ExtensionVersionClass').getProperty('version').value#{else}Extension version sheet#end
false
- xwiki/2.0
+ xwiki/2.1
true
- {{velocity}}
-## You can modify this page to customize the presentation of your object.
-## At first you should keep the default presentation and just save the document.
-
-#set($class = $doc.getObject('ExtensionCode.ExtensionVersionClass').xWikiClass)
-#foreach($prop in $class.properties)
- ; $prop.prettyName
- : $doc.display($prop.getName())
+ {{include reference="ExtensionCode.RepositoryCode"/}}
+
+{{template name="extension.vm"/}}
+
+{{velocity output="false"}}
+#if ($xcontext.action == 'edit')
+ #set($isEditMode = true)
+#else
+ #set($isViewMode = true)
+#end
+
+#set($extension = $doc.getObject("ExtensionCode.ExtensionClass"))
+#set($extensionVersion = $doc.getObject("ExtensionCode.ExtensionVersionClass"))
+{{/velocity}}
+
+{{velocity}}
+#if ($extensionVersion && !$extension)
+ #set($type = $extensionVersion.getProperty('type').value)
+ #set ($extensionTypeDocumentNames = $services.query.xwql('from doc.object(ExtensionCode.ExtensionTypeClass) as type where type.id = :id').bindValue("id", $type).execute())
+ #if ($extensionTypeDocumentNames.size() > 0)
+ #set ($extensionTypeDocumentName = $extensionTypeDocumentNames.get(0))
+ #set($extensionTypeObject = $xwiki.getDocument($extensionTypeDocumentName).getObject("ExtensionCode.ExtensionTypeClass"))
+ #end
+
+ $doc.use("ExtensionCode.ExtensionVersionClass")
+ ##------- Back button ----------------
+ [[$services.icon.render('left') Extension page>>$services.model.serialize($doc.getDocumentReference().getParent().getParent().getParent())||class="btn btn-primary"]]##
+
+ #if ($isViewMode)
+ ##------- Icon & Summary -----------------
+ (% class="extensionSummary" %)
+ **${services.rendering.escape($doc.getValue('summary'), 'xwiki/2.1')}**
+
+ ## Viewing
+ ##
+ {{box cssClass="floatinginfobox col-xs-12 col-sm-6 pull-right"}}
+ (% class="extensionInfo" %)
+ ##------- Type --------------
+ #set($typeDisplay = $extensionTypeObject.getProperty('name').value)
+ #if ("$!typeDisplay" == '')
+ #set($typeDisplay = $type)
+ #end
+ |(% class="label" width='30%' %)Type(%%)|$services.rendering.escape($typeDisplay, 'xwiki/2.1')
+ ##------- Category --------------
+ #set($categoryDisplay = $extensionVersion.getProperty('category').value)
+ #if ("$!categoryDisplay" == '')
+ #set($categoryDisplay = $category)
+ #end
+ #if ($categoryDisplay)
+ |(% class="label" width='30%' %)Category(%%)|$services.rendering.escape($categoryDisplay, 'xwiki/2.1')
+ #end
+ ##------- Developed By --------
+ #set($authors = $doc.getValue("authors"))
+ |(% class="label" %)Developed by(%%)|#if ($authors.isEmpty())
+ Unknown
+ #else
+ $doc.display('authors')
+ #end
+ ##------- Website --------------
+ #set($website = $extensionVersion.getProperty("website").value)
+ #if ("$!website" != '')
+ |(% class="label" %)Website(%%)|#if ($website.length() > 40)
+ [[$services.rendering.escape($services.rendering.escape($website.substring(0, 40), 'xwiki/2.1'), 'xwiki/2.1')...>>$services.rendering.escape($website, 'xwiki/2.1')]]
+ #else
+ [[$services.rendering.escape($website, 'xwiki/2.1')]]
+ #end
+ #end
+ ##------- License --------
+ #set($licenseName = $doc.getValue("licenseName"))
+ #if ("$!licenseName" != "")
+ |(% class="label" %)License(%%)|$services.rendering.escape($licenseName, 'xwiki/2.1')
+ #else
+ |(% class="label" %)License(%%)|Unknown
+ #end
+ ##---------------------------------
+ ##------- Sheet extensions --------
+ #if (!$sheetExtensions.isEmpty())
+
+ #foreach($sheetExtension in $sheetExtensions)
+ $doc.display('view_info', 'view', $sheetExtension)
+ #end
+ #end
+ ##-------------------------------------------
+ ##------- Extension Manager -----------------
+ #if ($doc.getValue('validExtension') == 1)
+
+ {{success}}**Installable with the Extension Manager**{{/success}}
+ #end
+ ##------------------------
+ (%class="btn-group pull-right"%)(((
+ ##------- Download button ------
+ #set ($version = $extensionVersion.getProperty('version').value)
+ #set ($download = $extensionVersion.getProperty('download').value)
+ #if ("$!download" == '')
+ #if ($doc.getAttachment("${id}-${version}.${type}"))
+ [[$services.icon.render('download') Download v$services.rendering.escape($services.rendering.escape($version, 'xwiki/2.1'), 'xwiki/2.1')>>$services.rendering.escape("attach:${id}-${version}.${type}")||class="btn btn-primary"]]##
+ #end
+ #else
+ [[$services.icon.render('download') Download v$services.rendering.escape($services.rendering.escape($version, 'xwiki/2.1'), 'xwiki/2.1')>>$services.rendering.escape($download, 'xwiki/2.1')||class="btn btn-primary"]]##
+ #end
+ ##------- Source --------
+ #set($source = $extensionVersion.getProperty("source").value)
+ #if ("$!source" != "")
+ [[Sources>>$services.rendering.escape($source, 'xwiki/2.1')||class="btn btn-default"]]##
+ #end
+ )))
+ {{/box}}
+
+ {{box cssClass="toc col-xs-12 col-sm-6"}}(% class="label" %)Table of contents(%%)((({{toc/}}))){{/box}}
+ (%class="clearfix"%)((()))
+ #end
+
+ ## Release notes
+ = Release Notes =
+ #set($releaseNotes = $doc.getValue("notes"))
+ $doc.display('notes')
+
+ #if ($isViewMode)
+ #set($extensionDependencies = $doc.getObjects('ExtensionCode.ExtensionDependencyClass', 'extensionVersion', $version))
+ #if ($extensionDependencies.size() > 0)
+ = Dependencies =
+
+ Dependencies for this extension ($services.rendering.escape("${extensionVersion.getValue('id')} ${version}", 'xwiki/2.1')):
+ #foreach($extensionDependency in $extensionDependencies)
+ #set($dependencyDocumentName = $null)
+ #set($dependencyDocumentNames = $services.query.xwql('from doc.object(ExtensionCode.ExtensionClass) as extension where extension.id = :id').bindValue("id", $extensionDependency.id).execute())
+ #if (!$dependencyDocumentNames.isEmpty())
+ #set($dependencyDocumentName = $dependencyDocumentNames.get(0))
+ #end
+ #if ($dependencyDocumentName)
+ * [[$services.rendering.escape($services.rendering.escape($extensionDependency.getValue('id'), 'xwiki/2.1'), 'xwiki/2.1')>>$services.rendering.escape($dependencyDocumentName, 'xwiki/2.1')]] $services.rendering.escape($extensionDependency.getValue('constraint'), 'xwiki/2.1')
+ #else
+ * $services.rendering.escape("${extensionDependency.getValue('id')} ${extensionDependency.getValue('constraint')}", 'xwiki/2.1')
+ #end
+ #end
+ #end
+ #end
+
+#else
+ This class sheet must be applied on a document containing an ExtensionCode.ExtensionVersionClass object
#end
{{/velocity}}
@@ -65,4 +197,309 @@
+
+ ExtensionCode.ExtensionVersionSheet
+ 0
+ XWiki.StyleSheetExtension
+ 6a915691-5ff6-4850-98ab-917595c2fc10
+
+ XWiki.StyleSheetExtension
+
+
+
+
+
+
+
+
+ 0
+ long
+ 0
+ select
+ forbidden
+ 0
+ 0
+ cache
+ 5
+ Caching policy
+ 0
+
+ |,
+ 1
+ 0
+ long|short|default|forbid
+ com.xpn.xwiki.objects.classes.StaticListClass
+
+
+ PureText
+ 0
+ PureText
+ code
+ 2
+ Code
+ 0
+ 20
+ 50
+ 0
+ com.xpn.xwiki.objects.classes.TextAreaClass
+
+
+ 0
+ 0
+ select
+ forbidden
+ 0
+ 0
+ contentType
+ 6
+ Content Type
+ 0
+
+ |,
+ 1
+ 0
+ CSS|LESS
+ com.xpn.xwiki.objects.classes.StaticListClass
+
+
+ 0
+ name
+ 1
+ Name
+ 30
+ 0
+ com.xpn.xwiki.objects.classes.StringClass
+
+
+ 0
+ select
+ yesno
+ parse
+ 4
+ Parse content
+ 0
+ com.xpn.xwiki.objects.classes.BooleanClass
+
+
+ 0
+ 0
+ select
+ forbidden
+ 0
+ 0
+ use
+ 3
+ Use this extension
+ 0
+
+ |,
+ 1
+ 0
+ currentPage|onDemand|always
+ com.xpn.xwiki.objects.classes.StaticListClass
+
+
+
+ long
+
+
+ #template('colorThemeInit.vm')
+
+.extensionSummary {
+ background-color: $theme.backgroundSecondaryColor;
+ border: 1px dotted $theme.borderColor;
+ padding: 5px;
+ display: block;
+}
+
+.main .extensionInfo {
+ margin: 0;
+}
+
+.extensionInfo .label {
+ font-size: 0.85em;
+ font-weight: bold;
+ text-transform: uppercase;
+}
+
+/*Rating*/
+.extensionInfo .rating-wrapper {
+ float: left;
+}
+
+.extensionInfo .rating-container > div {
+ float: left;
+ margin-right: 10px
+}
+
+
+ CSS
+
+
+ Extension CSS
+
+
+ 1
+
+
+ always
+
+
+
+ ExtensionCode.ExtensionVersionSheet
+ 1
+ XWiki.StyleSheetExtension
+ ac3e481a-5ec9-41eb-9a4d-9b109bcae4be
+
+ XWiki.StyleSheetExtension
+
+
+
+
+
+
+
+
+ 0
+ long
+ 0
+ select
+ forbidden
+ 0
+ 0
+ cache
+ 5
+ Caching policy
+ 0
+
+ |,
+ 1
+ 0
+ long|short|default|forbid
+ com.xpn.xwiki.objects.classes.StaticListClass
+
+
+ PureText
+ 0
+ PureText
+ code
+ 2
+ Code
+ 0
+ 20
+ 50
+ 0
+ com.xpn.xwiki.objects.classes.TextAreaClass
+
+
+ 0
+ 0
+ select
+ forbidden
+ 0
+ 0
+ contentType
+ 6
+ Content Type
+ 0
+
+ |,
+ 1
+ 0
+ CSS|LESS
+ com.xpn.xwiki.objects.classes.StaticListClass
+
+
+ 0
+ name
+ 1
+ Name
+ 30
+ 0
+ com.xpn.xwiki.objects.classes.StringClass
+
+
+ 0
+ select
+ yesno
+ parse
+ 4
+ Parse content
+ 0
+ com.xpn.xwiki.objects.classes.BooleanClass
+
+
+ 0
+ 0
+ select
+ forbidden
+ 0
+ 0
+ use
+ 3
+ Use this extension
+ 0
+
+ |,
+ 1
+ 0
+ currentPage|onDemand|always
+ com.xpn.xwiki.objects.classes.StaticListClass
+
+
+
+ long
+
+
+ .extensionSummary td, /* PROBLEM: General styling reset */
+.extensionInfo td {
+ border: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+@media (min-width: 768px) {
+ .box.floatinginfobox, .box.toc {
+ max-width: 49%;
+ }
+}
+
+.box .label { /* PROBLEM: Usage of a class with meaning inside Bootstrap */
+ color: inherit;
+ text-align: inherit;
+ display: table-cell;
+}
+
+.toc .label {
+ margin: 0;
+}
+
+/* Download and Source button alignment */
+.box > p {
+ margin-bottom: 0;
+}
+
+/* Spacing for repository info message */
+.box .extensionInfo {
+ margin-top: 10px;
+}
+
+/* XINFRA-134: Aligning table cell text */
+.floatinginfobox td {
+ vertical-align: baseline;
+}
+
+
+ CSS
+
+
+ Junco
+
+
+
+
+
+ currentPage
+
+
diff --git a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/ExtensionVersionTemplate.xml b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/ExtensionVersionTemplate.xml
index 1117e93abdff..f611b6a0a5ac 100644
--- a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/ExtensionVersionTemplate.xml
+++ b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/ExtensionVersionTemplate.xml
@@ -51,6 +51,99 @@
+
+ 0
+
+
+ 0
+ input
+
+
+ 0
+ 1
+ allowednamespaces
+ 26
+ 0
+ Allowed namespaces
+ 1
+
+ |
+ 1
+ none
+ 0
+
+
+
+ com.xpn.xwiki.objects.classes.StaticListClass
+
+
+
+ 0
+ 0
+ checkbox
+
+
+ allowednamespaces_empty
+ 27
+ Is allowed namespaces empty
+ 0
+
+
+ com.xpn.xwiki.objects.classes.BooleanClass
+
+
+ 0
+ {{include reference="ExtensionCode.ExtensionAuthorsDisplayer"/}}
+
+ 0
+ input
+
+
+ 0
+ 1
+ authors
+ 7
+ 0
+ Authors
+ 0
+
+ ,|
+ 30
+ none
+ 0
+
+
+
+ com.xpn.xwiki.objects.classes.StaticListClass
+
+
+ 0
+ ExtensionCode.ExtensionCategoryClass
+
+
+ 0
+ select
+
+
+ id
+ 0
+ 0
+ category
+ 16
+ 0
+ Category
+ 0
+
+
+ 1
+ value
+
+ 0
+
+
+ name
+ com.xpn.xwiki.objects.classes.DBListClass
+
PureText
@@ -104,11 +197,51 @@
com.xpn.xwiki.objects.classes.StringClass
+
+ 0
+
+
+ 0
+ select
+
+
+ 0
+ 0
+ licenseName
+ 10
+ 0
+ License Name
+ 0
+
+ ,|
+ 1
+ none
+ 0
+
+
+ GNU General Public License 1|GNU General Public License 2|GNU General Public License 3|GNU Lesser General Public License 2|GNU Lesser General Public License 2.1|GNU Lesser General Public License 3|Apache License 2.0|BSD license|Modified BSD License|Simplified BSD License|GNU Affero General Public License 3|GNU Free Documentation License 1.1|GNU Free Documentation License 1.2|GNU Free Documentation License 1.3|Educational Community License 1.0|Educational Community License 2.0|Do What The Fuck You Want To Public License 2
+ com.xpn.xwiki.objects.classes.StaticListClass
+
+
+
+ 0
+
+ name
+ 3
+ 0
+ Name
+ 30
+ 0
+
+
+ com.xpn.xwiki.objects.classes.StringClass
+
---
0
---
+
notes
1
0
@@ -120,11 +253,37 @@
com.xpn.xwiki.objects.classes.TextAreaClass
+
+ 0
+
+
+ 0
+ input
+
+
+ 0
+ 1
+ properties
+ 17
+ 0
+ Properties
+ 1
+
+ |
+ 1
+ none
+ 0
+
+
+
+ com.xpn.xwiki.objects.classes.StaticListClass
+
0
0
input
+
1
repositories
6
@@ -141,6 +300,102 @@
com.xpn.xwiki.objects.classes.StaticListClass
+
+ PureText
+
+ 0
+ ---
+
+ scmconnection
+ 25
+ 0
+ Sources connection
+ 0
+ 1
+ 100
+ 0
+
+
+ com.xpn.xwiki.objects.classes.TextAreaClass
+
+
+ PureText
+
+ 0
+ ---
+
+ scmdevconnection
+ 26
+ 0
+ Sources dev connection
+ 0
+ 1
+ 100
+ 0
+
+
+ com.xpn.xwiki.objects.classes.TextAreaClass
+
+
+ PureText
+
+ 0
+ ---
+
+ source
+ 24
+ 0
+ Source
+ 0
+ 1
+ 100
+ 0
+
+
+ com.xpn.xwiki.objects.classes.TextAreaClass
+
+
+
+ 0
+
+ summary
+ 4
+ 0
+ Summary
+ 75
+ 0
+
+
+ com.xpn.xwiki.objects.classes.StringClass
+
+
+ 0
+ ExtensionCode.ExtensionTypeClass
+
+
+ 0
+ select
+
+
+ id
+ 0
+ 0
+ type
+ 2
+ 0
+ Type
+ 0
+
+
+ 1
+ value
+
+ 0
+
+
+ name
+ com.xpn.xwiki.objects.classes.DBListClass
+
0
@@ -155,7 +410,37 @@
com.xpn.xwiki.objects.classes.StringClass
+
+ PureText
+
+ 0
+ ---
+
+ website
+ 6
+ 0
+ Website
+ 0
+ 1
+ 100
+ 0
+
+
+ com.xpn.xwiki.objects.classes.TextAreaClass
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -165,14 +450,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/VersionsHome.xml b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/VersionsHome.xml
new file mode 100644
index 000000000000..a42d633cf294
--- /dev/null
+++ b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/main/resources/ExtensionCode/VersionsHome.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+ ExtensionCode
+ VersionsHome
+
+
+ 0
+ xwiki:XWiki.Admin
+ xwiki:XWiki.Admin
+ xwiki:XWiki.Admin
+ 1.1
+
+
+ WebHome
+ false
+ xwiki/2.1
+ true
+ {{velocity}}
+#set($locationCriteria = $doc.space)
+#if(!$locationCriteria.endsWith('Versions'))
+ #set ($locationCriteria = "${locationCriteria}.Versions")
+#end
+
+#set ($optionsLD = {
+ 'className': 'ExtensionCode.ExtensionVersionClass',
+ 'location': "${locationCriteria}",
+ 'translationPrefix': 'extension.repository.'
+})
+
+{{liveData
+ id="versions"
+ properties="version,notes"
+ source="liveTable"
+ sort="version:desc"
+ limit="5"
+ sourceParameters="$services.rendering.escape($escapetool.url($optionsLD), 'xwiki/2.1')"
+}}{
+"meta": {
+ "propertyDescriptors": [
+ {
+ "id": "version",
+ "displayer": {"id": "link", "propertyHref": "doc.url"},
+ "editable": false
+ }
+ ]
+ }
+}
+{{/liveData}}
+
+{{/velocity}}
+
diff --git a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/test/java/org/xwiki/repository/server/ui/ExtensionSheetPageTest.java b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/test/java/org/xwiki/repository/server/ui/ExtensionSheetPageTest.java
index b1dc67cbb8f3..112fa302f851 100644
--- a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/test/java/org/xwiki/repository/server/ui/ExtensionSheetPageTest.java
+++ b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-server-ui/src/test/java/org/xwiki/repository/server/ui/ExtensionSheetPageTest.java
@@ -50,6 +50,7 @@
import org.xwiki.rendering.internal.macro.toc.TocMacro;
import org.xwiki.rendering.macro.script.MacroPermissionPolicy;
import org.xwiki.rendering.transformation.MacroTransformationContext;
+import org.xwiki.repository.script.RepositoryScriptService;
import org.xwiki.script.service.ScriptService;
import org.xwiki.test.annotation.ComponentList;
import org.xwiki.test.junit5.mockito.MockComponent;
@@ -58,6 +59,7 @@
import org.xwiki.test.page.TestNoScriptMacro;
import org.xwiki.test.page.XWikiSyntax21ComponentList;
+import com.xpn.xwiki.api.Object;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;
@@ -94,7 +96,7 @@
LoggingScriptService.class,
PermissionCheckerListener.class,
TestNoScriptMacro.class,
- TocMacro.class,
+ TocMacro.class
})
class ExtensionSheetPageTest extends PageTest
{
@@ -189,6 +191,13 @@ void setUp() throws Exception
// Mock restricted contexts.
when(this.groovyMacroPermissionPolicy.hasPermission(any(), any())).thenAnswer(i ->
!((MacroTransformationContext) i.getArgument(1)).getTransformationContext().isRestricted());
+
+ // Mock repository script service
+ RepositoryScriptService repositoryScriptService =
+ this.componentManager.registerMockComponent(ScriptService.class, "repository",
+ RepositoryScriptService.class, false);
+ when(repositoryScriptService.getVersionObject(any(), any())).thenReturn(new Object(extensionVersionObject,
+ null));
}
@Test
diff --git a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-test/xwiki-platform-repository-test-tests/src/test/it/org/xwiki/repository/test/ui/repository/RepositoryIT.java b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-test/xwiki-platform-repository-test-tests/src/test/it/org/xwiki/repository/test/ui/repository/RepositoryIT.java
index b14177e265a5..5a4880412d6e 100644
--- a/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-test/xwiki-platform-repository-test-tests/src/test/it/org/xwiki/repository/test/ui/repository/RepositoryIT.java
+++ b/xwiki-platform-core/xwiki-platform-repository/xwiki-platform-repository-test/xwiki-platform-repository-test-tests/src/test/it/org/xwiki/repository/test/ui/repository/RepositoryIT.java
@@ -39,7 +39,10 @@
import org.xwiki.extension.repository.xwiki.model.jaxb.ExtensionsSearchResult;
import org.xwiki.extension.repository.xwiki.model.jaxb.Property;
import org.xwiki.extension.version.internal.DefaultVersionConstraint;
+import org.xwiki.model.EntityType;
+import org.xwiki.model.reference.EntityReference;
import org.xwiki.model.reference.LocalDocumentReference;
+import org.xwiki.rendering.syntax.Syntax;
import org.xwiki.repository.Resources;
import org.xwiki.repository.internal.XWikiRepositoryModel;
import org.xwiki.repository.test.TestExtension;
@@ -56,11 +59,10 @@
import org.xwiki.repository.test.po.edit.ExtensionSupporterInlinePage;
import org.xwiki.repository.test.ui.AbstractExtensionAdminAuthenticatedIT;
import org.xwiki.rest.model.jaxb.Page;
-import org.xwiki.test.ui.po.editor.ObjectEditPage;
-import org.xwiki.test.ui.po.editor.ObjectEditPane;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -473,10 +475,10 @@ private void testRestAccessToImportedExtension() throws Exception
assertEquals("jar", extension.getType());
assertEquals("1.0", extension.getVersion());
assertEquals("name", extension.getName());
- assertEquals("summary2", extension.getSummary());
+ assertEquals("summary", extension.getSummary());
assertEquals("summary2\n some more details", extension.getDescription());
- assertEquals(this.baseAuthor.getName(), extension.getAuthors().get(0).getName());
- assertEquals(this.baseAuthor.getURL().toString(), extension.getAuthors().get(0).getUrl());
+ assertEquals("Previous Name", extension.getAuthors().get(0).getName());
+ assertNull(extension.getAuthors().get(0).getUrl());
assertEquals(Arrays.asList("maven:oldextension", "maven:oldversionnedextension"),
extension.getFeatures());
assertEquals("maven:oldextension", extension.getExtensionFeatures().get(0).getId());
@@ -492,14 +494,14 @@ private void testRestAccessToImportedExtension() throws Exception
extension = getUtil().rest().getResource(Resources.EXTENSION_VERSION, null, "maven:extension", "0.9");
- assertEquals("maven:extension", extension.getId());
+ assertEquals("maven:oldextension", extension.getId());
assertEquals("jar", extension.getType());
assertEquals("0.9", extension.getVersion());
assertEquals("name", extension.getName());
assertEquals("summary2", extension.getSummary());
assertEquals("summary2\n some more details", extension.getDescription());
- assertEquals(this.baseAuthor.getName(), extension.getAuthors().get(0).getName());
- assertEquals(this.baseAuthor.getURL().toString(), extension.getAuthors().get(0).getUrl());
+ assertEquals("Old Name", extension.getAuthors().get(0).getName());
+ assertNull(extension.getAuthors().get(0).getUrl());
assertEquals(Arrays.asList(), extension.getFeatures());
assertEquals(Arrays.asList(), extension.getExtensionFeatures());
assertEquals("GNU Lesser General Public License 2.1", extension.getLicenses().get(0).getName());
@@ -517,8 +519,7 @@ private void enableProxying(ExtensionPage extensionPage) throws Exception
new LocalDocumentReference(List.of("Extension", importedExtensionName), "WebHome");
// assert that this test is going to make sense at all
- assertTrue(getNumberOfExtensionVersionsObjects(importedExtensionName) > 1);
- assertTrue(getNumberOfExtensionVersionsDependenciesObjects(importedExtensionName) > 1);
+ assertTrue(getNumberOfExtensionVersionsPages(extensionPageReference) > 1);
// indicate that the history of the extension should be proxied
getUtil().updateObject(extensionPageReference, XWikiRepositoryModel.EXTENSIONPROXY_CLASSNAME, 0, "proxyLevel",
@@ -527,9 +528,8 @@ private void enableProxying(ExtensionPage extensionPage) throws Exception
// refresh extension
extensionPage.updateExtension();
- // assert that the object to be proxied are now absent
- assertEquals(1, getNumberOfExtensionVersionsObjects(importedExtensionName));
- assertEquals(1, getNumberOfExtensionVersionsDependenciesObjects(importedExtensionName));
+ // assert that the version to be proxied are now absent
+ assertEquals(1, getNumberOfExtensionVersionsPages(extensionPageReference));
// Remember the page version
Page restPage = getUtil().rest().get(extensionPageReference);
@@ -543,25 +543,16 @@ private void enableProxying(ExtensionPage extensionPage) throws Exception
assertEquals(extensionPageVersion, restPage.getVersion());
}
- private int getNumberOfExtensionVersionsObjects(String extensionName)
- {
- ObjectEditPage objectEditPage = goToObjectEditPage(extensionName);
- List versionObjects =
- objectEditPage.getObjectsOfClass(XWikiRepositoryModel.EXTENSIONVERSION_CLASSNAME);
- return versionObjects.size();
- }
-
- private int getNumberOfExtensionVersionsDependenciesObjects(String extensionName)
- {
- ObjectEditPage objectEditPage = goToObjectEditPage(extensionName);
- List dependenciesObjects =
- objectEditPage.getObjectsOfClass(XWikiRepositoryModel.EXTENSIONDEPENDENCY_CLASSNAME);
- return dependenciesObjects.size();
- }
-
- private ObjectEditPage goToObjectEditPage(String extensionName)
+ private int getNumberOfExtensionVersionsPages(LocalDocumentReference extensionPageReference) throws Exception
{
- return getRepositoryTestUtils().gotoExtensionObjectsEditPage(extensionName);
+ EntityReference versionReference = new EntityReference(XWikiRepositoryModel.EXTENSIONVERSIONS_SPACENAME,
+ EntityType.SPACE, extensionPageReference.getParent());
+ String result = getUtil().executeWikiPlain(
+ "{{velocity}}$services.query.xwql(\"select space.reference from Space space where space.parent='"
+ + getUtil().serializeLocalReference(versionReference) + "'\").execute().size(){{/velocity}}",
+ Syntax.XWIKI_2_1);
+
+ return Integer.parseInt(result);
}
private void validateSupport() throws Exception
diff --git a/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/TestUtils.java b/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/TestUtils.java
index 74898686019e..bdf3ad51847f 100644
--- a/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/TestUtils.java
+++ b/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/TestUtils.java
@@ -104,6 +104,7 @@
import org.xwiki.rest.resources.objects.ObjectsResource;
import org.xwiki.rest.resources.pages.PageResource;
import org.xwiki.rest.resources.pages.PageTranslationResource;
+import org.xwiki.rest.resources.pages.PagesResource;
import org.xwiki.test.integration.XWikiExecutor;
import org.xwiki.test.ui.po.BasePage;
import org.xwiki.test.ui.po.ViewPage;
@@ -2539,6 +2540,7 @@ public ResourceAPI(Class> api, Class> localeAPI)
throw new RuntimeException(e);
}
+ RESOURCES_MAP.put(EntityType.SPACE, new ResourceAPI(PagesResource.class, null));
RESOURCES_MAP.put(EntityType.DOCUMENT, new ResourceAPI(PageResource.class, PageTranslationResource.class));
RESOURCES_MAP.put(EntityType.OBJECT, new ResourceAPI(ObjectResource.class, null));
RESOURCES_MAP.put(EntityType.OBJECT_PROPERTY, new ResourceAPI(ObjectPropertyResource.class, null));
diff --git a/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/InlinePage.java b/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/InlinePage.java
index cd3e39a8b5be..b20cc9f3fea7 100644
--- a/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/InlinePage.java
+++ b/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/InlinePage.java
@@ -102,6 +102,8 @@ public T clickSaveAndView()
public void clickSaveAndView(boolean wait)
{
if (wait) {
+ // Increase the timeout as a page save can be slow
+ getDriver().setTimeout(30);
getDriver().addPageNotYetReloadedMarker();
}