diff --git a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java index be4eec062f69331c8a3d577c174cff2d6f77060b..d760205de7ca017c3e2517a2d01bcccab84aa050 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java +++ b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java @@ -388,10 +388,10 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager, Initializ } Collections.sort(serversInfos, new ServerLoadComparator()); - double load = serversInfos.get(0).getLoad(); + long load = Math.round(serversInfos.get(0).getLoad()); List<BigBlueButtonServerInfos> sameLoadsServer = new ArrayList<>(); for(BigBlueButtonServerInfos serverInfos : serversInfos) { - if(serverInfos.getLoad() == load) { + if(Math.round(serverInfos.getLoad()) == load) { sameLoadsServer.add(serverInfos); } } @@ -433,9 +433,7 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager, Initializ private double calculateLoad(BigBlueButtonServer server, List<BigBlueButtonMeetingInfos> meetingsInfos) { double load = 0.0d; for(BigBlueButtonMeetingInfos meetingInfos:meetingsInfos) { - load += meetingInfos.getListenerCount() * 1.0d; - load += meetingInfos.getVideoCount() * 3.0d; - load += meetingInfos.getVoiceParticipantCount() * 2.0d; + load += calculateMeetingLoad(meetingInfos); } if(load > 0.0d && server.getCapacityFactory() != null @@ -445,6 +443,37 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager, Initializ return load; } + /** + * + * @param meetingInfos The meeting to calculate the load + * @return The load + */ + private double calculateMeetingLoad(BigBlueButtonMeetingInfos meetingInfos) { + double load = 0.0d; + Date now = new Date(); + + Date startTime = meetingInfos.getStartTime(); + // We assume that after 10 minutes that all users are in the room, + // before we take the max. users to better evaluate the load in the future + if(!meetingInfos.isBreakout() && (startTime != null && (now.getTime() - startTime.getTime()) < 10 * 60 * 1000)) { + long maxUsers = meetingInfos.getMaxUsers(); + if(maxUsers == 0) { + maxUsers = 1;// mathematical paranoia + } + load += maxUsers * 1.0d; + // count at least 3 + long videoCount = Math.max(meetingInfos.getVideoCount(), 3); + load += videoCount * 3.0d; + long voiceCount = Math.max(meetingInfos.getVoiceParticipantCount(), (maxUsers / 4)); + load += voiceCount * 2.0d; + } else { + load += meetingInfos.getListenerCount() * 1.0d; + load += meetingInfos.getVideoCount() * 3.0d; + load += meetingInfos.getVoiceParticipantCount() * 2.0d; + } + return load; + } + private List<BigBlueButtonMeetingInfos> getMeetingInfos(BigBlueButtonServer server, BigBlueButtonErrors errors) { if(!server.isEnabled()) { errors.append(new BigBlueButtonError(BigBlueButtonErrorCodes.serverDisabled)); diff --git a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonUtils.java b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonUtils.java index fa4579b9f1fbb0dea7e62cc843ab53fa7934b238..0b81a60d6d227522165b76aacfca5387a3fd05d8 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonUtils.java +++ b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonUtils.java @@ -139,8 +139,10 @@ public class BigBlueButtonUtils { Element meetingEl = (Element)meetingList.item(i); String meetingId = getFirstElementValue(meetingEl, "meetingID"); String running = getFirstElementValue(meetingEl, "running"); + String hasBeenForciblyEnded = getFirstElementValue(meetingEl, "hasBeenForciblyEnded"); - BigBlueButtonMeetingInfos meeting = new BigBlueButtonMeetingInfos(meetingId, "true".equals(running)); + BigBlueButtonMeetingInfos meeting = new BigBlueButtonMeetingInfos(meetingId, + "true".equals(running), "true".equals(hasBeenForciblyEnded)); meetings.add(meeting); String videoCount = getFirstElementValue(meetingEl, "videoCount"); @@ -162,6 +164,9 @@ public class BigBlueButtonUtils { String maxUsers = getFirstElementValue(meetingEl, "maxUsers"); meeting.setMaxUsers(toLong(maxUsers)); + + String startTime = getFirstElementValue(meetingEl, "startTime"); + meeting.setStartTime(toDate(startTime)); } return meetings; } @@ -173,7 +178,6 @@ public class BigBlueButtonUtils { } catch (NumberFormatException e) { log.error("Cannot parse this long: {0}", text, e); } - } return 0l; } @@ -183,7 +187,6 @@ public class BigBlueButtonUtils { Long time = Long.parseLong(val); return new Date(time.longValue()); } - return null; } diff --git a/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingInfos.java b/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingInfos.java index 7dd1ea3da0762f88a35f307a4faf6278c0939bbc..2e6c79a78c862970dabdfcb69f127787758d8711 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingInfos.java +++ b/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingInfos.java @@ -19,6 +19,8 @@ */ package org.olat.modules.bigbluebutton.model; +import java.util.Date; + /** * * Initial date: 8 avr. 2020<br> @@ -29,6 +31,9 @@ public class BigBlueButtonMeetingInfos { private final String meetingId; private final boolean running; + private final boolean hasBeenForciblyEnded; + + private Date startTime; private long videoCount; private long listenerCount; @@ -41,12 +46,13 @@ public class BigBlueButtonMeetingInfos { private boolean breakout; private long maxUsers; - + private double load; - public BigBlueButtonMeetingInfos(String meetingId, boolean running) { + public BigBlueButtonMeetingInfos(String meetingId, boolean running, boolean hasBeenForciblyEnded) { this.meetingId = meetingId; this.running = running; + this.hasBeenForciblyEnded = hasBeenForciblyEnded; } public String getMeetingId() { @@ -57,6 +63,18 @@ public class BigBlueButtonMeetingInfos { return running; } + public boolean isHasBeenForciblyEnded() { + return hasBeenForciblyEnded; + } + + public Date getStartTime() { + return startTime; + } + + public void setStartTime(Date startTime) { + this.startTime = startTime; + } + public long getVideoCount() { return videoCount; } diff --git a/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonServerInfos.java b/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonServerInfos.java index 57535d23bd7b38ee8d28319a10a55ec4cec5e47d..e9adf7beb426e0e0b476932c665587f6aa1d1fd0 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonServerInfos.java +++ b/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonServerInfos.java @@ -61,6 +61,10 @@ public class BigBlueButtonServerInfos { return server; } + public int getNumberOfMeetings() { + return meetingsInfos.size(); + } + public List<BigBlueButtonMeetingInfos> getMeetingsInfos() { return meetingsInfos; } diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonAdminMeetingsController.java b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonAdminMeetingsController.java index b7270325c89f07b0755325717113aea96a47f630..ecb777bb912d86cbcfedbde2e637ad255fafb53d 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonAdminMeetingsController.java +++ b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonAdminMeetingsController.java @@ -84,6 +84,7 @@ public class BigBlueButtonAdminMeetingsController extends FormBasicController { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BMeetingsCols.start)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BMeetingsCols.end)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BMeetingsCols.template)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BMeetingsCols.server, new ServerCellRenderer())); FlexiCellRenderer renderer = new StaticFlexiCellRenderer("resource", new TextFlexiCellRenderer()); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BMeetingsCols.resource.i18nHeaderKey(), BMeetingsCols.resource.ordinal(), "resource", true, BMeetingsCols.resource.name(), renderer)); diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonAdminServersController.java b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonAdminServersController.java index 4cdb7f704fb761a4261199034f57914ee532385a..75a2484264b76f88e9604a14dd71f09621af799c 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonAdminServersController.java +++ b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonAdminServersController.java @@ -66,8 +66,9 @@ public class BigBlueButtonAdminServersController extends FormBasicController { FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ServersCols.status, new StatusCellRenderer(getTranslator()))); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ServersCols.url)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ServersCols.url, new ServerCellRenderer())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ServersCols.capacityFactor, new CapacityFactorCellRenderer())); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ServersCols.numberMeetings)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ServersCols.moderatorCount)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ServersCols.participantCount)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ServersCols.listenerCount)); diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonAdminServersTableModel.java b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonAdminServersTableModel.java index f1c2ea7688aff7aa6916b72bd68d7dd56cb3aa17..aef7cdc58479f400e4399c3cc3e51507af940c6f 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonAdminServersTableModel.java +++ b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonAdminServersTableModel.java @@ -75,6 +75,8 @@ implements SortableFlexiTableDataModel<BigBlueButtonServerRow>, FilterableFlexiT case url: return row.getUrl(); case status: return row.isEnabled(); case capacityFactor: return row.getCapacityFactor(); + case numberMeetings:return allInstances + ? row.getAllInstancesServerInfos().getNumberOfMeetings() : row.getServerInfos().getNumberOfMeetings(); case moderatorCount: return allInstances ? row.getAllInstancesServerInfos().getModeratorCount() : row.getServerInfos().getModeratorCount(); case participantCount: return allInstances @@ -105,8 +107,9 @@ implements SortableFlexiTableDataModel<BigBlueButtonServerRow>, FilterableFlexiT public enum ServersCols implements FlexiSortableColumnDef { url("table.header.server.url"), - status("table.header.server.enabled"), + status("table.header.server.status"), capacityFactor("table.header.capacity.factor"), + numberMeetings("table.header.number.meetings"), moderatorCount("table.header.moderator.count"), participantCount("table.header.participant.count"), listenerCount("table.header.listener.count"), diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonEditMeetingsController.java b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonEditMeetingsController.java index d4e8f1fc56146e760b7beb0a975fba59cddbc733..b6c9d5ffc21800cd2209f1f1952874d88cca514c 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonEditMeetingsController.java +++ b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonEditMeetingsController.java @@ -138,6 +138,7 @@ public class BigBlueButtonEditMeetingsController extends FormBasicController { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BMeetingsCols.start)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BMeetingsCols.end)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BMeetingsCols.template)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, BMeetingsCols.server, new ServerCellRenderer())); if(!readOnly) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("edit", translate("edit"), "edit")); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("delete", translate("delete"), "delete")); diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonMeetingTableModel.java b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonMeetingTableModel.java index cb1f53b817478383e645a3483ac6b1b4ec936ec8..87ee0902d836f3c42177c849d378c32edfa771d4 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonMeetingTableModel.java +++ b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonMeetingTableModel.java @@ -30,6 +30,7 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFl import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate; import org.olat.modules.bigbluebutton.BigBlueButtonMeeting; import org.olat.modules.bigbluebutton.BigBlueButtonMeetingTemplate; +import org.olat.modules.bigbluebutton.BigBlueButtonServer; /** * @@ -71,13 +72,19 @@ implements SortableFlexiTableDataModel<BigBlueButtonMeeting> { case start: return row.getStartDate(); case end: return row.getEndDate(); case template: return getTemplate(row); + case server: return getServer(row); case resource: return getResourceName(row); default: return "ERROR"; } } - private String getTemplate(BigBlueButtonMeeting row) { - BigBlueButtonMeetingTemplate template = row.getTemplate(); + private String getServer(BigBlueButtonMeeting meeting) { + BigBlueButtonServer server = meeting.getServer(); + return server == null ? null : server.getUrl(); + } + + private String getTemplate(BigBlueButtonMeeting meeting) { + BigBlueButtonMeetingTemplate template = meeting.getTemplate(); return template == null ? null: template.getName(); } @@ -103,6 +110,7 @@ implements SortableFlexiTableDataModel<BigBlueButtonMeeting> { start("meeting.start"), end("meeting.end"), template("table.header.template"), + server("table.header.server"), resource("meeting.resource"); private final String i18nHeaderKey; diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonMeetingsController.java b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonMeetingsController.java index 0d9daf74c94fb3516e61b64d435c0f2fbf916df1..b18c4df951c487484ba11675ecf9750a5ac4e28d 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonMeetingsController.java +++ b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonMeetingsController.java @@ -91,6 +91,7 @@ public class BigBlueButtonMeetingsController extends FormBasicController { } columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BMeetingsCols.start)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BMeetingsCols.end)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, BMeetingsCols.server, new ServerCellRenderer())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select", translate("select"), "select")); upcomingTableModel = new BigBlueButtonMeetingTableModel(columnsModel, getLocale()); @@ -110,6 +111,7 @@ public class BigBlueButtonMeetingsController extends FormBasicController { } pastColumnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BMeetingsCols.start)); pastColumnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BMeetingsCols.end)); + pastColumnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, BMeetingsCols.server, new ServerCellRenderer())); pastColumnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select", translate("select"), "select")); pastTableModel = new BigBlueButtonMeetingTableModel(pastColumnsModel, getLocale()); diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/ServerCellRenderer.java b/src/main/java/org/olat/modules/bigbluebutton/ui/ServerCellRenderer.java new file mode 100644 index 0000000000000000000000000000000000000000..fa1e98d1fb3ea3d1989140b9a39a6d838733b2eb --- /dev/null +++ b/src/main/java/org/olat/modules/bigbluebutton/ui/ServerCellRenderer.java @@ -0,0 +1,53 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.bigbluebutton.ui; + +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent; +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.translator.Translator; + +/** + * + * Initial date: 15 avr. 2020<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class ServerCellRenderer implements FlexiCellRenderer { + + @Override + public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source, + URLBuilder ubu, Translator trans) { + if(cellValue instanceof String) { + String url = (String)cellValue; + int index = url.indexOf("://"); + if(index >= 0) { + url = url.substring(index + 3); + } + int slashIndex = url.indexOf('/'); + if(slashIndex >= 0) { + url = url.substring(0, slashIndex); + } + target.append("<span title=\"").append((String)cellValue).append("\">").append(url).append("</span>"); + } + } +} diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_de.properties index 44b254b9d6b085b48201f0dc405cbc8fff4a1257..34d950917894b442b8c5b32f497d5116525d2e9b 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_de.properties @@ -123,6 +123,7 @@ table.header.recording.name=Name table.header.recording.open=\u00D6ffnen table.header.recording.start=Beginn table.header.recording.type=Typ +table.header.server=Server table.header.server.enabled=Eingeschaltet table.header.server.status=Status table.header.server.recording=Aufzeichnungen URL diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_en.properties index 94b9c8756aacd75d6864816796cf58cc5b36597d..9fa0bcfa33ce58295d277145ddbde7c1802c00a2 100644 --- a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_en.properties @@ -123,6 +123,7 @@ table.header.recording.name=Name table.header.recording.open=Open table.header.recording.start=Start table.header.recording.type=Type +table.header.server=Server table.header.server.enabled=Enabled table.header.server.status=Status table.header.server.recording=Recording URL