Skip to content

Commit d73493d

Browse files
committed
XCOMMONS-3451: Realtime editing doesn't support clustering
1 parent 5a5e8b2 commit d73493d

File tree

21 files changed

+718
-25
lines changed

21 files changed

+718
-25
lines changed

xwiki-platform-core/xwiki-platform-annotation/xwiki-platform-annotation-test/xwiki-platform-annotation-test-docker/src/test/it/org/xwiki/annotation/test/ui/AnnotationsIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ void addAnnotationTranslation(TestUtils setup, TestReference testReference,
9797
setup.createPage(referenceFR, "Un peu de contenu en français.", "Une page en français");
9898

9999
AnnotatableViewPage viewPage = new AnnotatableViewPage(setup.gotoPage(referenceEN));
100-
viewPage.addAnnotation("Some", "English word.");
100+
viewPage.addAnnotation("Some", "Engliesh word.");
101101

102102
viewPage = new AnnotatableViewPage(setup.gotoPage(referenceFR));
103103
// We cannot wait for success since the UI is in french...

xwiki-platform-core/xwiki-platform-netflux/xwiki-platform-netflux-api/src/main/java/org/xwiki/netflux/internal/DefaultEntityChannelStore.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ public class DefaultEntityChannelStore implements EntityChannelStore
4949
@Inject
5050
private ChannelStore channelStore;
5151

52-
private final Map<EntityReference, List<EntityChannel>> entityChannels = new ConcurrentHashMap<>();
52+
@Inject
53+
private EntityChannels entityChannels;
5354

5455
@Override
5556
public List<EntityChannel> getChannels(EntityReference entityReference)
@@ -84,6 +85,8 @@ public synchronized EntityChannel createChannel(EntityReference entityReference,
8485
this.entityChannels.computeIfAbsent(entityReference, key -> new CopyOnWriteArrayList<>());
8586
channels.add(channel);
8687

88+
TODO: event
89+
8790
// Ask again the bots to join the channel now that we have an entity channel.
8891
this.channelStore.askBotsToJoin(this.channelStore.get(channel.getKey()));
8992

@@ -101,7 +104,7 @@ private boolean hasRawChannel(EntityChannel channel)
101104
{
102105
Channel rawChannel = this.channelStore.get(channel.getKey());
103106
if (rawChannel != null) {
104-
channel.setUserCount(rawChannel.getConnectedUsers().size());
107+
channel.setUserCount(rawChannel.getUsers().size());
105108
return true;
106109
} else {
107110
return false;

xwiki-platform-core/xwiki-platform-netflux/xwiki-platform-netflux-api/src/main/java/org/xwiki/netflux/internal/EntityChange.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*/
2020
package org.xwiki.netflux.internal;
2121

22+
import java.io.Serializable;
2223
import java.util.Date;
2324

2425
import org.apache.commons.lang3.builder.EqualsBuilder;
@@ -35,8 +36,10 @@
3536
* @since 16.4.1
3637
* @since 16.6.0RC1
3738
*/
38-
public class EntityChange implements Comparable<EntityChange>
39+
public class EntityChange implements Serializable, Comparable<EntityChange>
3940
{
41+
private static final long serialVersionUID = 1L;
42+
4043
/**
4144
* The script level for a given entity change.
4245
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* See the NOTICE file distributed with this work for additional
3+
* information regarding copyright ownership.
4+
*
5+
* This is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU Lesser General Public License as
7+
* published by the Free Software Foundation; either version 2.1 of
8+
* the License, or (at your option) any later version.
9+
*
10+
* This software is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this software; if not, write to the Free
17+
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18+
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19+
*/
20+
package org.xwiki.netflux.internal;
21+
22+
/**
23+
*
24+
* @version $Id$
25+
*/
26+
public class EntityChannelCreatedEvent
27+
{
28+
29+
}

xwiki-platform-core/xwiki-platform-netflux/xwiki-platform-netflux-api/src/main/java/org/xwiki/netflux/internal/EntityChannelScriptAuthorBot.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@ public void onChannelMessage(Channel channel, User sender, String messageType, S
8484
{
8585
// We're interested only in messages that have content (we want to ignore for instance join, leave or ping
8686
// messages).
87-
if (MessageBuilder.COMMAND_MSG.equals(messageType)) {
87+
if (MessageBuilder.COMMAND_MSG.equals(messageType) && sender instanceof LocalUser localSender) {
8888
this.entityChannels.getChannel(channel.getKey())
89-
.ifPresent(entityChannel -> this.webSocketContext.run(sender.getSession(), () -> {
89+
.ifPresent(entityChannel -> this.webSocketContext.run(localSender.getSession(), () -> {
9090
UserReference senderUserReference = this.currentUserResolver.resolve(CurrentUserReference.INSTANCE);
9191
this.scriptAuthorTracker.maybeUpdateScriptAuthor(entityChannel, senderUserReference);
9292
}));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* See the NOTICE file distributed with this work for additional
3+
* information regarding copyright ownership.
4+
*
5+
* This is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU Lesser General Public License as
7+
* published by the Free Software Foundation; either version 2.1 of
8+
* the License, or (at your option) any later version.
9+
*
10+
* This software is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this software; if not, write to the Free
17+
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18+
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19+
*/
20+
package org.xwiki.netflux.internal;
21+
22+
import javax.inject.Named;
23+
import javax.inject.Singleton;
24+
25+
import jakarta.inject.Inject;
26+
27+
import org.slf4j.Logger;
28+
import org.xwiki.component.annotation.Component;
29+
import org.xwiki.netflux.EntityChannel;
30+
import org.xwiki.netflux.internal.event.EntityChannelScriptAuthorChangedEvent;
31+
import org.xwiki.observation.AbstractEventListener;
32+
import org.xwiki.observation.event.Event;
33+
34+
/**
35+
* Update the script author for a specific {@link EntityChannel}.
36+
*
37+
* @version $Id$
38+
* @since 17.10.0RC1
39+
*/
40+
@Component
41+
@Named(EntityChannelScriptAuthorListener.NAME)
42+
@Singleton
43+
public class EntityChannelScriptAuthorListener extends AbstractEventListener
44+
{
45+
/**
46+
* The name of this event listener (and its component hint at the same time).
47+
*/
48+
public static final String NAME = "org.xwiki.netflux.internal.EntityChannelScriptAuthorListener";
49+
50+
@Inject
51+
private EntityChannelScriptAuthorTracker tracker;
52+
53+
@Inject
54+
private Logger logger;
55+
56+
/**
57+
* Setup the listener.
58+
*/
59+
public EntityChannelScriptAuthorListener()
60+
{
61+
super(NAME, new EntityChannelScriptAuthorChangedEvent());
62+
}
63+
64+
@Override
65+
public void onEvent(Event event, Object source, Object data)
66+
{
67+
if (event instanceof EntityChannelScriptAuthorChangedEvent changedEvent) {
68+
EntityChange change = (EntityChange) source;
69+
70+
this.tracker.setScriptAuthor(changedEvent.getChannel(), change);
71+
72+
this.logger.debug("Updated the script author associated with the entity channel [{}] to [{}].",
73+
changedEvent.getChannel(), change);
74+
}
75+
}
76+
}

xwiki-platform-core/xwiki-platform-netflux/xwiki-platform-netflux-api/src/main/java/org/xwiki/netflux/internal/EntityChannelScriptAuthorTracker.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
import org.xwiki.netflux.EntityChannel;
3737
import org.xwiki.netflux.EntityChannelStore;
3838
import org.xwiki.netflux.internal.EntityChange.ScriptLevel;
39+
import org.xwiki.netflux.internal.event.EntityChannelScriptAuthorChangedEvent;
40+
import org.xwiki.observation.ObservationManager;
3941
import org.xwiki.security.authorization.DocumentAuthorizationManager;
4042
import org.xwiki.security.authorization.Right;
4143
import org.xwiki.user.CurrentUserReference;
@@ -76,6 +78,9 @@ public class EntityChannelScriptAuthorTracker
7678
@Named("explicit")
7779
private EntityReferenceResolver<String> explicitEntityReferenceResolver;
7880

81+
@Inject
82+
private ObservationManager observation;
83+
7984
private final Map<String, EntityChange> scriptAuthors = new ConcurrentHashMap<>();
8085

8186
/**
@@ -120,9 +125,10 @@ void maybeUpdateScriptAuthor(EntityChannel entityChannel, UserReference scriptAu
120125
// need to update the channel script level in order to prevent privilege escalation.
121126
EntityChange scriptAuthorChange =
122127
new EntityChange(entityChannel.getEntityReference(), scriptAuthor, userScriptLevel);
123-
this.scriptAuthors.put(entityChannel.getKey(), scriptAuthorChange);
124-
this.logger.debug("Updated the script author associated with the entity channel [{}] to [{}].",
125-
entityChannel, scriptAuthorChange);
128+
129+
// Modify the script author mapping through a listener to better cover clustering use case
130+
this.observation.notify(new EntityChannelScriptAuthorChangedEvent(entityChannel.getKey()),
131+
scriptAuthorChange);
126132
}
127133
}
128134

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* See the NOTICE file distributed with this work for additional
3+
* information regarding copyright ownership.
4+
*
5+
* This is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU Lesser General Public License as
7+
* published by the Free Software Foundation; either version 2.1 of
8+
* the License, or (at your option) any later version.
9+
*
10+
* This software is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this software; if not, write to the Free
17+
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18+
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19+
*/
20+
package org.xwiki.netflux.internal;
21+
22+
import java.util.List;
23+
import java.util.Map;
24+
import java.util.concurrent.ConcurrentHashMap;
25+
26+
import jakarta.inject.Singleton;
27+
28+
import org.xwiki.component.annotation.Component;
29+
import org.xwiki.model.reference.EntityReference;
30+
import org.xwiki.netflux.EntityChannel;
31+
32+
/**
33+
* The channels.
34+
*
35+
* @version $Id$
36+
*/
37+
@Component(roles = EntityChannels.class)
38+
@Singleton
39+
public class EntityChannels
40+
{
41+
private final Map<EntityReference, List<EntityChannel>> channels = new ConcurrentHashMap<>();
42+
43+
/**
44+
* @param entityReference the reference of the entity
45+
* @return the channels associated with the entity
46+
*/
47+
public List<EntityChannel> get(EntityReference entityReference)
48+
{
49+
return this.channels.get(entityReference);
50+
}
51+
52+
/**
53+
* @param entityReference the reference of the entity
54+
* @return the previous value associated with {@code key}, or {@code null} if there was no mapping for {@code key}
55+
*/
56+
public List<EntityChannel> remove(EntityReference entityReference)
57+
{
58+
return this.channels.remove(entityReference);
59+
}
60+
61+
/**
62+
* @param entityReference the reference of the entity
63+
* @param availableChannels the channels associated with the entity
64+
* @return the previous value associated with {@code key}, or {@code null} if there was no mapping for {@code key}.
65+
* (A {@code null} return can also indicate that the map previously associated {@code null} with
66+
* {@code key}, if the implementation supports {@code null} values.)
67+
*/
68+
public List<EntityChannel> put(EntityReference entityReference, List<EntityChannel> availableChannels)
69+
{
70+
return this.channels.put(entityReference, availableChannels);
71+
}
72+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* See the NOTICE file distributed with this work for additional
3+
* information regarding copyright ownership.
4+
*
5+
* This is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU Lesser General Public License as
7+
* published by the Free Software Foundation; either version 2.1 of
8+
* the License, or (at your option) any later version.
9+
*
10+
* This software is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this software; if not, write to the Free
17+
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18+
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19+
*/
20+
package org.xwiki.netflux.internal;
21+
22+
import javax.inject.Named;
23+
import javax.inject.Singleton;
24+
25+
import jakarta.inject.Inject;
26+
27+
import org.slf4j.Logger;
28+
import org.xwiki.component.annotation.Component;
29+
import org.xwiki.netflux.EntityChannel;
30+
import org.xwiki.netflux.internal.event.EntityChannelScriptAuthorChangedEvent;
31+
import org.xwiki.observation.AbstractEventListener;
32+
import org.xwiki.observation.event.Event;
33+
34+
/**
35+
* Update the script author for a specific {@link EntityChannel}.
36+
*
37+
* @version $Id$
38+
* @since 17.10.0RC1
39+
*/
40+
@Component
41+
@Named(EntityChannelsListener.NAME)
42+
@Singleton
43+
public class EntityChannelsListener extends AbstractEventListener
44+
{
45+
/**
46+
* The name of this event listener (and its component hint at the same time).
47+
*/
48+
public static final String NAME = "org.xwiki.netflux.internal.EntityChannelsListener";
49+
50+
@Inject
51+
private EntityChannelScriptAuthorTracker tracker;
52+
53+
@Inject
54+
private Logger logger;
55+
56+
/**
57+
* Setup the listener.
58+
*/
59+
public EntityChannelsListener()
60+
{
61+
super(NAME, new EntityChannelScriptAuthorChangedEvent(), new EntityChannelCreatedEvent());
62+
}
63+
64+
@Override
65+
public void onEvent(Event event, Object source, Object data)
66+
{
67+
if (event instanceof EntityChannelScriptAuthorChangedEvent changedEvent) {
68+
EntityChange change = (EntityChange) source;
69+
70+
this.tracker.setScriptAuthor(changedEvent.getChannel(), change);
71+
72+
this.logger.debug("Updated the script author associated with the entity channel [{}] to [{}].",
73+
changedEvent.getChannel(), change);
74+
} else if (event instanceof EntityChannelCreatedEvent entityEvent) {
75+
76+
}
77+
}
78+
}

0 commit comments

Comments
 (0)