Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
064d9fd
[prepare-major] update to major version 7.0-SNAPSHOT
msladek Jan 1, 2026
d9b2fa0
[prepare-major] update to major version 7.0-SNAPSHOT
msladek Jan 1, 2026
3ec8fc4
[prepare-major] update to major version 7.0-SNAPSHOT
msladek Jan 1, 2026
883c6df
[prepare-major] update to major version 7.0-SNAPSHOT
msladek Jan 1, 2026
c701171
[prepare-major] update to major version 7.0-SNAPSHOT
msladek Jan 1, 2026
e41cff2
[prepare-major] update to major version 7.0-SNAPSHOT
msladek Jan 1, 2026
85eb796
[prepare-major] update to major version 7.0-SNAPSHOT
msladek Jan 1, 2026
d91f5ec
[prepare-major] update to major version 7.0-SNAPSHOT
msladek Jan 1, 2026
dbaf3a7
[prepare-major] update to major version 7.0-SNAPSHOT
msladek Jan 1, 2026
d85d637
[prepare-major] update to major version 7.0-SNAPSHOT
msladek Jan 1, 2026
944d1c9
[prepare-major] update to major version 7.0-SNAPSHOT
msladek Jan 1, 2026
403d12b
[prepare-major] update to major version 7.0-SNAPSHOT
msladek Jan 1, 2026
dbf6f7d
[prepare-major] update to major version 7.0-SNAPSHOT
msladek Jan 1, 2026
2a86364
fix DefaultDocumentCacheTest
msladek Jan 1, 2026
afd8475
remove illegal config
msladek Jan 2, 2026
a20d6fe
Merge remote-tracking branch 'origin/dev' into major-7
msladek Jan 2, 2026
05e8ee9
Merge remote-tracking branch 'origin/dev' into major-7
msladek Jan 4, 2026
812fe68
fix PluginManager
msladek Jan 4, 2026
c89ba6e
Merge branch 'dev' into major-7
fpichler Jan 8, 2026
6b6dedd
Merge branch 'dev' into major-7
msladek Jan 11, 2026
3660b9a
s3 test
msladek Jan 11, 2026
d7c9e6a
AttachmentContentStore
msladek Jan 11, 2026
f861364
Merge remote-tracking branch 'origin/dev' into major-7
msladek Jan 12, 2026
3c0c0df
Merge branch 'major-7' into s3
msladek Jan 12, 2026
e720575
fix archive/recyclebin for different content storage
msladek Jan 13, 2026
0c64794
remove xcontexts
msladek Jan 13, 2026
0548835
address PR comments
msladek Jan 15, 2026
99d7097
getRevision fix for current version
msladek Jan 15, 2026
6fcfc56
add logging
msladek Jan 16, 2026
580cb72
XWA throw out XWE
msladek Jan 16, 2026
c564b01
beginTransaction with db
msladek Jan 22, 2026
6e03b0a
deleteContent for XWikiAttachment
msladek Jan 22, 2026
b3a2288
move HibernateAttachmentContentStore
msladek Jan 22, 2026
f6a13a3
fix getAttachmentReference
msladek Jan 22, 2026
d9d543f
print xwiki cfg
msladek Jan 22, 2026
0be8876
don't delete from s3
msladek Feb 1, 2026
c26d413
add rebuildArchive
msladek Feb 2, 2026
78a4600
QueryExecutionService add wiki param
msladek Feb 2, 2026
500b1b5
Merge remote-tracking branch 'origin/dev' into store-att-content
msladek Feb 2, 2026
3013c1c
fix NPE XWikiAttachmentArchive.getVersions
msladek Feb 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion celements-model/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>celements-model</artifactId>
<version>7.0-SNAPSHOT</version>
<description>Celements XWiki</description>
<description>Celements Model</description>
<dependencies>
<dependency>
<groupId>com.celements</groupId>
<artifactId>celements-config-source</artifactId>
<version>7.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.celements</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,19 @@ public class QueryExecutionService implements IQueryExecutionServiceRole {

@Override
public List<List<String>> executeReadSql(String sql) throws XWikiException {
return executeReadSql(String.class, sql);
return executeReadSql(context.getWikiRef(), String.class, sql);
}

@Override
public <T> List<List<T>> executeReadSql(Class<T> type, String sql) throws XWikiException {
return executeReadSql(context.getWikiRef(), type, sql);
}

public <T> List<List<T>> executeReadSql(WikiReference wikiRef, Class<T> type, String sql)
throws XWikiException {
Session session = null;
try {
session = getNewHibSession();
session = getNewHibSession(wikiRef);
List<?> result = session.createSQLQuery(sql).list();
return harmoniseResult(type, result);
} catch (HibernateException | ClassCastException exc) {
Expand Down Expand Up @@ -95,9 +100,14 @@ public int executeWriteSQL(String sql) throws XWikiException {

@Override
public List<Integer> executeWriteSQLs(List<String> sqls) throws XWikiException {
return executeWriteSQLs(context.getWikiRef(), sqls);
}

public List<Integer> executeWriteSQLs(WikiReference wikiRef, List<String> sqls)
throws XWikiException {
Session session = null;
try {
session = getNewHibSession();
session = getNewHibSession(wikiRef);
return executeWriteSqlInTransaction(session, sqls);
} catch (HibernateException hibExc) {
throw new XWikiException(0, 0, "error while executing sql", hibExc);
Expand Down Expand Up @@ -130,10 +140,11 @@ private List<Integer> executeWriteSqlInTransaction(Session session, List<String>
return results;
}

private Session getNewHibSession() throws XWikiException, HibernateException {
private Session getNewHibSession(WikiReference wikiRef)
throws XWikiException, HibernateException {
Session session = getHibStore().getSessionFactory().openSession();
try {
getHibStore().setDatabase(session, context.getWikiRef());
getHibStore().setDatabase(session, wikiRef);
} catch (WikiMissingException wme) {
throw new XWikiException(XWikiException.MODULE_XWIKI_STORE,
XWikiException.ERROR_XWIKI_STORE_HIBERNATE_SWITCH_DATABASE,
Expand All @@ -157,12 +168,7 @@ public int executeWriteHQL(final String hql, final Map<String, Object> binds,

@Override
public DocumentReference executeAndGetDocRef(Query query) throws QueryException {
DocumentReference ret = null;
List<DocumentReference> list = executeAndGetDocRefs(query);
if (list.size() > 0) {
ret = list.get(0);
}
return ret;
return executeAndGetDocRefs(query).stream().findFirst().orElse(null);
}

@Override
Expand All @@ -172,11 +178,11 @@ public List<DocumentReference> executeAndGetDocRefs(Query query) throws QueryExc
if (!Strings.isNullOrEmpty(query.getWiki())) {
wikiRef = modelUtils.resolveRef(query.getWiki(), WikiReference.class);
}
for (Object fullName : query.execute()) {
if ((fullName instanceof String) && !Strings.isNullOrEmpty((String) fullName)) {
ret.add(modelUtils.resolveRef((String) fullName, DocumentReference.class, wikiRef));
for (Object fullNameObj : query.execute()) {
if ((fullNameObj instanceof String fullName) && !Strings.isNullOrEmpty(fullName)) {
ret.add(modelUtils.resolveRef(fullName, DocumentReference.class, wikiRef));
} else {
LOGGER.debug("executeAndGetDocRefs: received invalid fullName '{}'", fullName);
LOGGER.debug("executeAndGetDocRefs: received invalid fullName '{}'", fullNameObj);
}
}
LOGGER.info("executeAndGetDocRefs: {} results for query '{}' and wiki '{}'", ret.size(),
Expand All @@ -194,7 +200,7 @@ public boolean existsIndex(WikiReference wikiRef, String table, String name)
throws XWikiException {
String sql = getIndexExistSql(modelUtils.getDatabaseName(wikiRef), checkNotNull(emptyToNull(
table)), checkNotNull(emptyToNull(name)));
return executeReadSql(String.class, sql).size() > 0;
return !executeReadSql(wikiRef, String.class, sql).isEmpty();
}

private String getIndexExistSql(String database, String table, String name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static com.celements.common.lambda.LambdaExceptionUtil.*;
import static com.celements.execution.XWikiExecutionProp.*;
import static com.celements.logging.LogUtils.*;
import static com.celements.spring.context.SpringContextProvider.*;
import static com.google.common.base.Preconditions.*;

Expand Down Expand Up @@ -98,7 +99,7 @@ public void onApplicationEvent(CelementsStartedEvent event) {
XWiki xwiki = bootstrapXWiki();
// make XWiki available to all requests via servlet context, see {@link XWikiProvider}
xwikiFuture.complete(xwiki);
LOGGER.info("XWiki initialised");
LOGGER.info("XWiki initialised: {}", defer(xwiki::printConfig));
} catch (Exception exc) {
xwikiFuture.completeExceptionally(exc);
LOGGER.error("Celements bootstrap failed");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
package com.celements.store;

import static com.celements.spring.context.SpringContextProvider.*;

import java.util.Optional;

import org.xwiki.component.manager.ComponentLookupException;
import org.xwiki.component.manager.ComponentManager;
import org.xwiki.configuration.ConfigurationSource;

import com.google.common.primitives.Ints;
import com.xpn.xwiki.store.AttachmentContentStore;
import com.xpn.xwiki.store.AttachmentVersioningStore;
import com.xpn.xwiki.store.XWikiAttachmentStoreInterface;
import com.xpn.xwiki.store.XWikiRecycleBinStoreInterface;
import com.xpn.xwiki.store.XWikiStoreInterface;
import com.xpn.xwiki.store.hibernate.HibernateAttachmentContentStore;
import com.xpn.xwiki.web.Utils;

public final class StoreFactory {
Expand All @@ -28,6 +34,30 @@ public static Optional<XWikiRecycleBinStoreInterface> getRecycleBinStore() {
return getOptionalStore(XWikiRecycleBinStoreInterface.class, "celements.store.recyclebin");
}

public static XWikiAttachmentStoreInterface getAttachmentStore() {
try {
String hint = getConfigSource().getProperty("celements.store.attachment");
return getComponentManager().lookup(XWikiAttachmentStoreInterface.class, hint);
} catch (ComponentLookupException exc) {
throw new IllegalStateException("failed looking up attachment store", exc);
}
}

public static AttachmentContentStore getAttachmentContentStore() {
String beanName = getConfigSource().getProperty("celements.store.attachment.content",
HibernateAttachmentContentStore.STORE_NAME);
return getBeanFactory().getBean(beanName, AttachmentContentStore.class);
}

public static AttachmentVersioningStore getAttachmentVersioningStore() {
try {
return getComponentManager().lookup(AttachmentVersioningStore.class,
getConfigSource().getProperty("celements.store.attachment.versioning", "default"));
} catch (ComponentLookupException exc) {
throw new IllegalStateException("failed looking up attachment versioning store", exc);
}
}

private static <T> Optional<T> getOptionalStore(Class<T> type, String key) {
try {
String enabled = getConfigSource().getProperty(key + ".enabled", "false").toLowerCase();
Expand All @@ -42,8 +72,8 @@ private static <T> Optional<T> getOptionalStore(Class<T> type, String key) {
}
}

private static ConfigurationSource getConfigSource() throws ComponentLookupException {
return getComponentManager().lookup(ConfigurationSource.class, "allproperties");
private static ConfigurationSource getConfigSource() {
return Utils.getComponent(ConfigurationSource.class, "allproperties");
}

private static ComponentManager getComponentManager() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.celements.store.att;

import javax.inject.Inject;

import org.springframework.stereotype.Component;

import com.celements.init.XWikiProvider;
import com.xpn.xwiki.store.hibernate.HibernateAttachmentContentStore;

/**
* Policy component that decides whether attachment binary content should be embedded into
* XML-based structures produced by XWiki, namely the attachment archive (RCS/XML history) and the
* attachment recycle bin entry (deleted attachment XML snapshot).
* <p>
* The decision is based on the currently active {@code AttachmentContentStore} implementation.
* When the legacy Hibernate content store is used, attachment content is expected to be present in
* the serialized XML (RCS archive and recycle bin) because the Hibernate-based implementations
* historically persisted/consumed the bytes from there.
* <p>
* When an alternative content storage is used (for example object storage), embedding raw bytes
* into these XML payloads is typically undesirable (size, duplication) and may be incompatible with
* the alternative store's lookup strategy. In that case, content should be excluded and retrieved
* via the configured {@code AttachmentContentStore} instead.
*/
@Component
public class AttachmentContentPolicy {

private final XWikiProvider xwikiProvider;

@Inject
public AttachmentContentPolicy(XWikiProvider xwikiProvider) {
this.xwikiProvider = xwikiProvider;
}

/**
* Determines whether attachment content should be embedded into the attachment archive XML.
*/
public boolean includeInArchive() {
return isHibernateAttachmentContentStore();
}

/**
* Determines whether attachment content should be embedded into recycle bin XML.
*/
public boolean includeInRecycleBin() {
return isHibernateAttachmentContentStore();
}

private boolean isHibernateAttachmentContentStore() {
return xwikiProvider.get().orElseThrow(IllegalStateException::new)
.getAttachmentStore()
.getContentStore()
.getStoreName()
.equals(HibernateAttachmentContentStore.STORE_NAME);
}

}
39 changes: 23 additions & 16 deletions celements-xwiki-core/src/main/java/com/xpn/xwiki/XWiki.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.TimeZone;
Expand Down Expand Up @@ -184,9 +185,6 @@ public class XWiki implements EventListener {
/** The attachment storage (excluding attachment history). */
private XWikiAttachmentStoreInterface attachmentStore;

/** Store for attachment archives. */
private AttachmentVersioningStore attachmentVersioningStore;

/** Document versioning storage. */
private XWikiVersioningStoreInterface versioningStore;

Expand Down Expand Up @@ -377,18 +375,14 @@ protected void initXWiki() throws XWikiException {
"com.xpn.xwiki.criteria.impl.XWikiCriteriaServiceImpl", context));

LOGGER.trace("initialising AttachmentStore...");
setAttachmentStore(Utils.getComponent(XWikiAttachmentStoreInterface.class, Param(
"xwiki.store.attachment.hint")));
setAttachmentStore(StoreFactory.getAttachmentStore());
getAttachmentStore().getContentStore(); // force init
getAttachmentStore().getVersioningStore(); // force init

LOGGER.trace("initialising VersioningStore...");
setVersioningStore(Utils.getComponent(XWikiVersioningStoreInterface.class, Param(
"xwiki.store.versioning.hint")));

LOGGER.trace("initialising AttachmentVersioningStore...");
setAttachmentVersioningStore(Utils.getComponent(AttachmentVersioningStore.class,
hasAttachmentVersioning(context) ? Param("xwiki.store.attachment.versioning.hint")
: "void"));

LOGGER.trace("initialising RecycleBinStore...");
StoreFactory.getRecycleBinStore().ifPresent(this::setRecycleBinStore);

Expand All @@ -414,6 +408,23 @@ protected void initXWiki() throws XWikiException {
LOGGER.debug("XWiki init done");
}

public String printConfig() {
return "XWiki "
+ "[ mainStore=" + getStore().getClass().getName()
+ ", notCacheStore=" + getNotCacheStore().getClass().getName()
+ ", versioningStore=" + getVersioningStore().getClass().getName()
+ ", recycleBinStore=" + Optional.ofNullable(getRecycleBinStore())
.map(s -> s.getClass().getName()).orElse("none")
+ ", attachmentStore=" + getAttachmentStore().getClass().getName()
+ ", attachmentContentStore=" + getAttachmentStore().getContentStore().getClass().getName()
+ ", attachmentVersioningStore=" + getAttachmentStore().getVersioningStore()
.getClass().getName()
+ ", attachmentRecycleBinStore=" + Optional.ofNullable(getAttachmentRecycleBinStore())
.map(s -> s.getClass().getName()).orElse("none")
+ ", renderingEngine=" + getRenderingEngine().getClass().getName()
+ "]";
}

/**
* Ensure that mandatory classes (ie classes XWiki needs to work properly) exist and create them
* if they don't exist.
Expand Down Expand Up @@ -782,7 +793,7 @@ public XWikiAttachmentStoreInterface getAttachmentStore() {
}

public AttachmentVersioningStore getAttachmentVersioningStore() {
return this.attachmentVersioningStore;
return getAttachmentStore().getVersioningStore();
}

public XWikiVersioningStoreInterface getVersioningStore() {
Expand Down Expand Up @@ -2216,10 +2227,6 @@ public void setAttachmentStore(XWikiAttachmentStoreInterface attachmentStore) {
this.attachmentStore = attachmentStore;
}

public void setAttachmentVersioningStore(AttachmentVersioningStore avStore) {
this.attachmentVersioningStore = avStore;
}

public void setVersioningStore(XWikiVersioningStoreInterface versioningStore) {
this.versioningStore = versioningStore;
}
Expand Down Expand Up @@ -5150,7 +5157,7 @@ public boolean hasVersioning(String fullName, XWikiContext context) {

@Deprecated
public boolean hasAttachmentVersioning(XWikiContext context) {
return ("1".equals(Param("xwiki.store.attachment.versioning", "1")));
return getAttachmentStore().getVersioningStore().hasVersioning();
}

public String getExternalAttachmentURL(String fullName, String filename, XWikiContext context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public String getContentAsString(String charset) throws XWikiException {
}

public Version[] getVersions() throws XWikiException {
attachment.loadArchive(getXWikiContext());
attachment.loadArchive();
return attachment.getVersions();
}

Expand All @@ -150,7 +150,7 @@ public Version[] getVersions() throws XWikiException {
* @throws XWikiException
*/
public List<Version> getVersionList() throws XWikiException {
attachment.loadArchive(getXWikiContext());
attachment.loadArchive();
return attachment.getVersionList();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
import java.util.Calendar;
import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xpn.xwiki.XWikiConfig;
import com.xpn.xwiki.XWikiContext;
Expand All @@ -47,7 +47,7 @@
public class DeletedAttachment extends Api {

/** Logging helper object. */
private static final Log LOG = LogFactory.getLog(DeletedAttachment.class);
private static final Logger LOG = LoggerFactory.getLogger(DeletedAttachment.class);

/** The internal object wrapped by this API. */
private final com.xpn.xwiki.doc.DeletedAttachment deletedAttachment;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
import java.util.Calendar;
import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xpn.xwiki.XWikiConfig;
import com.xpn.xwiki.XWikiContext;
Expand All @@ -40,7 +40,7 @@
public class DeletedDocument extends Api {

/** Logging helper object. */
private static final Log LOG = LogFactory.getLog(DeletedDocument.class);
private static final Logger LOG = LoggerFactory.getLogger(DeletedDocument.class);

/**
* The internal object wrapped by this API.
Expand Down
Loading