diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/messages/CreateBreakoutRoomRequest.java b/bbb-common-message/src/main/java/org/bigbluebutton/messages/CreateBreakoutRoomRequest.java index c5681a7767..4863a1fce1 100755 --- a/bbb-common-message/src/main/java/org/bigbluebutton/messages/CreateBreakoutRoomRequest.java +++ b/bbb-common-message/src/main/java/org/bigbluebutton/messages/CreateBreakoutRoomRequest.java @@ -13,7 +13,7 @@ public class CreateBreakoutRoomRequest implements IBigBlueButtonMessage { this.payload = payload; } - static class CreateBreakoutRoomRequestPayload { + public static class CreateBreakoutRoomRequestPayload { public final String meetingId; // The main meeting internal id public final String name; // The name of the breakout room public final String voiceConfId; // The voice conference id diff --git a/bigbluebutton-web/grails-app/conf/bigbluebutton.properties b/bigbluebutton-web/grails-app/conf/bigbluebutton.properties index 42faab9560..143f7bfa77 100755 --- a/bigbluebutton-web/grails-app/conf/bigbluebutton.properties +++ b/bigbluebutton-web/grails-app/conf/bigbluebutton.properties @@ -186,11 +186,12 @@ beans.presentationService.testUploadedPresentation=appkonference.txt # Default Uploaded presentation file beans.presentationService.defaultUploadedPresentation=${bigbluebutton.web.serverURL}/default.pdf +presentationBaseURL=${bigbluebutton.web.serverURL}/bigbluebutton/presentation + #---------------------------------------------------- # The URL where the presentations will be loaded from. #---------------------------------------------------- -beans.presentationService.presentationBaseUrl=${bigbluebutton.web.serverURL}/bigbluebutton/presentation - +beans.presentationService.presentationBaseUrl=${presentationBaseURL} #---------------------------------------------------- # Inject values into grails service beans beans.presentationService.presentationDir=${presentationDir} diff --git a/bigbluebutton-web/grails-app/conf/spring/resources.xml b/bigbluebutton-web/grails-app/conf/spring/resources.xml index 753a078f4e..d63ad90219 100755 --- a/bigbluebutton-web/grails-app/conf/spring/resources.xml +++ b/bigbluebutton-web/grails-app/conf/spring/resources.xml @@ -19,39 +19,42 @@ with BigBlueButton; if not, see . --> - - - - - - - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:util="http://www.springframework.org/schema/util" + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans-2.5.xsd + http://www.springframework.org/schema/util + http://www.springframework.org/schema/util/spring-util-2.0.xsd"> + + + + + + + - - - - - - - - + + + + + + + + - + + + + + diff --git a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy index 761c6faa9d..9e13108503 100755 --- a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy +++ b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy @@ -171,11 +171,7 @@ class ApiController { } Meeting newMeeting = paramsProcessorUtil.processCreateParams(params); - - if (! StringUtils.isEmpty(params.moderatorOnlyMessage)) { - newMeeting.setModeratorOnlyMessage(params.moderatorOnlyMessage); - } - + meetingService.createMeeting(newMeeting); // See if the request came with pre-uploading of presentation. @@ -1949,7 +1945,7 @@ class ApiController { requestBody = StringUtils.isEmpty(requestBody) ? null : requestBody; if (requestBody == null) { - downloadAndProcessDocument(presentationService.defaultUploadedPresentation, conf.getInternalId()); + presDownloadService.downloadAndProcessDocument(presentationService.defaultUploadedPresentation, conf.getInternalId()); } else { log.debug "Request body: \n" + requestBody; def xml = new XmlSlurper().parseText(requestBody); @@ -1960,7 +1956,7 @@ class ApiController { // need to iterate over presentation files and process them module.children().each { document -> if (!StringUtils.isEmpty(document.@url.toString())) { - downloadAndProcessDocument(document.@url.toString(), conf.getInternalId()); + presDownloadService.downloadAndProcessDocument(document.@url.toString(), conf.getInternalId()); } else if (!StringUtils.isEmpty(document.@name.toString())) { def b64 = new Base64() def decodedBytes = b64.decode(document.text().getBytes()) @@ -1989,40 +1985,11 @@ class ApiController { fos.flush() fos.close() - processUploadedFile(meetingId, presId, presFilename, pres); + presDownloadService.processUploadedFile(meetingId, presId, presFilename, pres); } } - def downloadAndProcessDocument(address, meetingId) { - log.debug("ApiController#downloadAndProcessDocument(${address}, ${meetingId})"); - String presFilename = address.tokenize("/")[-1]; - def filenameExt = presDownloadService.getFilenameExt(presFilename); - String presentationDir = presentationService.getPresentationDir() - - def presId = presDownloadService.generatePresentationId(presFilename) - File uploadDir = presDownloadService.createPresentationDirectory(meetingId, presentationDir, presId) - if (uploadDir != null) { - def newFilename = presDownloadService.createNewFilename(presId, filenameExt) - def newFilePath = uploadDir.absolutePath + File.separatorChar + newFilename - - if (presDownloadService.savePresentation(meetingId, newFilePath, address)) { - def pres = new File(newFilePath) - processUploadedFile(meetingId, presId, presFilename, pres); - } else { - log.error("Failed to download presentation=[${address}], meeting=[${meetingId}]") - } - } - } - - - def processUploadedFile(meetingId, presId, filename, presFile) { - def presentationBaseUrl = presentationService.presentationBaseUrl - UploadedPresentation uploadedPres = new UploadedPresentation(meetingId, presId, filename, presentationBaseUrl); - uploadedPres.setUploadedFile(presFile); - presentationService.processUploadedPresentation(uploadedPres); - } - def beforeInterceptor = { if (paramsProcessorUtil.isServiceEnabled() == false) { log.info("apiNotEnabled: The API service and/or controller is not enabled on this server. To use it, you must first enable it.") diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/MeetingService.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/MeetingService.java index 88e9618573..12742ecaec 100755 --- a/bigbluebutton-web/src/java/org/bigbluebutton/api/MeetingService.java +++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/MeetingService.java @@ -44,6 +44,7 @@ import org.bigbluebutton.api.domain.User; import org.bigbluebutton.api.domain.UserSession; import org.bigbluebutton.api.messaging.MessageListener; import org.bigbluebutton.api.messaging.MessagingService; +import org.bigbluebutton.api.messaging.messages.CreateBreakoutRoom; import org.bigbluebutton.api.messaging.messages.CreateMeeting; import org.bigbluebutton.api.messaging.messages.EndMeeting; import org.bigbluebutton.api.messaging.messages.IMessage; @@ -63,30 +64,31 @@ import org.bigbluebutton.api.messaging.messages.UserUnsharedWebcam; import org.bigbluebutton.web.services.ExpiredMeetingCleanupTimerTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import com.google.gson.Gson; public class MeetingService implements MessageListener { - private static Logger log = LoggerFactory.getLogger(MeetingService.class); + private static Logger log = LoggerFactory.getLogger(MeetingService.class); - private BlockingQueue receivedMessages = new LinkedBlockingQueue(); - private volatile boolean processMessage = false; - - private final Executor msgProcessorExec = Executors.newSingleThreadExecutor(); - private final Executor runExec = Executors.newSingleThreadExecutor(); - - /** - * http://ria101.wordpress.com/2011/12/12/concurrenthashmap-avoid-a-common-misuse/ - */ - private final ConcurrentMap meetings; - private final ConcurrentMap sessions; - - private int defaultMeetingExpireDuration = 1; - private int defaultMeetingCreateJoinDuration = 5; - private RecordingService recordingService; - private MessagingService messagingService; - private ExpiredMeetingCleanupTimerTask cleaner; - private boolean removeMeetingWhenEnded = false; + private BlockingQueue receivedMessages = new LinkedBlockingQueue(); + private volatile boolean processMessage = false; + private final Executor msgProcessorExec = Executors.newSingleThreadExecutor(); + private final Executor runExec = Executors.newSingleThreadExecutor(); + /** + * http://ria101.wordpress.com/2011/12/12/concurrenthashmap-avoid-a-common-misuse/ + */ + private final ConcurrentMap meetings; + private final ConcurrentMap sessions; + private int defaultMeetingExpireDuration = 1; + private int defaultMeetingCreateJoinDuration = 5; + private RecordingService recordingService; + private MessagingService messagingService; + private ExpiredMeetingCleanupTimerTask cleaner; + private boolean removeMeetingWhenEnded = false; + + private ParamsProcessorUtil paramsProcessorUtil; + public MeetingService() { meetings = new ConcurrentHashMap(8, 0.9f, 1); sessions = new ConcurrentHashMap(8, 0.9f, 1); @@ -437,6 +439,10 @@ public class MeetingService implements MessageListener { handle(new EndMeeting(meetingId)); } + private void processCreateBreakoutRoom(CreateBreakoutRoom message) { + + } + private void processEndMeeting(EndMeeting message) { messagingService.endMeeting(message.meetingId); @@ -682,7 +688,9 @@ public class MeetingService implements MessageListener { processEndMeeting((EndMeeting)message); } else if (message instanceof RegisterUser) { processRegisterUser((RegisterUser) message); - } + } else if (message instanceof CreateBreakoutRoom) { + processCreateBreakoutRoom((CreateBreakoutRoom) message); + } } }; @@ -750,4 +758,8 @@ public class MeetingService implements MessageListener { public void setRemoveMeetingWhenEnded(boolean s) { removeMeetingWhenEnded = s; } + + public void setParamsProcessorUtil(ParamsProcessorUtil util) { + this.paramsProcessorUtil = util; + } } diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/ParamsProcessorUtil.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/ParamsProcessorUtil.java index 1d6644752b..2b188e3a0f 100755 --- a/bigbluebutton-web/src/java/org/bigbluebutton/api/ParamsProcessorUtil.java +++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/ParamsProcessorUtil.java @@ -362,6 +362,11 @@ public class ParamsProcessorUtil { String configXML = getDefaultConfigXML(); meeting.storeConfig(true, configXML); + if (! StringUtils.isEmpty(params.get("moderatorOnlyMessage"))) { + String moderatorOnlyMessage = params.get("moderatorOnlyMessage"); + meeting.setModeratorOnlyMessage(moderatorOnlyMessage); + } + return meeting; } diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MeetingMessageHandler.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MeetingMessageHandler.java index af161005cc..fa3913c403 100755 --- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MeetingMessageHandler.java +++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MeetingMessageHandler.java @@ -2,6 +2,7 @@ package org.bigbluebutton.api.messaging; import java.util.Set; +import org.bigbluebutton.api.messaging.messages.CreateBreakoutRoom; import org.bigbluebutton.api.messaging.messages.IMessage; import org.bigbluebutton.api.messaging.messages.KeepAliveReply; import org.bigbluebutton.api.messaging.messages.MeetingDestroyed; @@ -67,6 +68,11 @@ public class MeetingMessageHandler implements MessageHandler { } else if (CreateBreakoutRoomRequest.NAME.equals(messageName)) { Gson gson = new Gson(); CreateBreakoutRoomRequest msg = gson.fromJson(message, CreateBreakoutRoomRequest.class); + for (MessageListener listener : listeners) { + listener.handle(new CreateBreakoutRoom(msg.payload.meetingId, + msg.payload.name, msg.payload.voiceConfId, msg.payload.viewerPassword, + msg.payload.moderatorPassword, msg.payload.durationInMinutes, msg.payload.defaultPresentationURL)); + } } } } diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/messages/CreateBreakoutRoom.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/messages/CreateBreakoutRoom.java new file mode 100755 index 0000000000..5c674c4223 --- /dev/null +++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/messages/CreateBreakoutRoom.java @@ -0,0 +1,25 @@ +package org.bigbluebutton.api.messaging.messages; + + +public class CreateBreakoutRoom implements IMessage { + + public final String meetingId; // The main meeting internal id + public final String name; // The name of the breakout room + public final String voiceConfId; // The voice conference id + public final String viewerPassword; + public final String moderatorPassword; + public final Integer durationInMinutes; // The duration of the breakout room + public final String defaultPresentationURL; + + public CreateBreakoutRoom(String meetingId, String name, + String voiceConfId, String viewerPassword, String moderatorPassword, + Integer duration, String defaultPresentationURL) { + this.meetingId = meetingId; + this.name = name; + this.voiceConfId = voiceConfId; + this.viewerPassword = viewerPassword; + this.moderatorPassword = moderatorPassword; + this.durationInMinutes = duration; + this.defaultPresentationURL = defaultPresentationURL; + } +} diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/presentation/PresentationUrlDownloadService.java b/bigbluebutton-web/src/java/org/bigbluebutton/presentation/PresentationUrlDownloadService.java old mode 100644 new mode 100755 index 697d8c188c..6a9b9d5e3d --- a/bigbluebutton-web/src/java/org/bigbluebutton/presentation/PresentationUrlDownloadService.java +++ b/bigbluebutton-web/src/java/org/bigbluebutton/presentation/PresentationUrlDownloadService.java @@ -5,6 +5,8 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; +import java.util.Timer; + import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; @@ -18,7 +20,42 @@ public class PresentationUrlDownloadService { private static Logger log = LoggerFactory.getLogger(PresentationUrlDownloadService.class); private final int maxRedirects = 5; + private DocumentConversionService documentConversionService; + private String presentationBaseURL; + private String presentationDir; + public void processUploadedPresentation(UploadedPresentation uploadedPres) { + documentConversionService.processDocument(uploadedPres); + } + + public void processUploadedFile(String meetingId, String presId, String filename, File presFile) { + UploadedPresentation uploadedPres = new UploadedPresentation(meetingId, presId, filename, presentationBaseURL); + uploadedPres.setUploadedFile(presFile); + processUploadedPresentation(uploadedPres); + } + + public void downloadAndProcessDocument(String address, String meetingId) { + log.debug("downloadAndProcessDocument [pres=" + address + ", meeting=" + meetingId + "]"); + + String presFilename = address.substring(address.lastIndexOf('/') + 1); + log.debug("downloadAndProcessDocument [filename=" + presFilename + "]"); + String filenameExt = getFilenameExt(presFilename); + + String presId = generatePresentationId(presFilename); + File uploadDir = createPresentationDirectory(meetingId, presentationDir, presId); + if (uploadDir != null) { + String newFilename = createNewFilename(presId, filenameExt); + String newFilePath = uploadDir.getAbsolutePath() + File.separatorChar + newFilename; + + if (savePresentation(meetingId, newFilePath, address)) { + File pres = new File(newFilePath); + processUploadedFile(meetingId, presId, presFilename, pres); + } else { + log.error("Failed to download presentation=[" + address + "], meeting=[" + meetingId + "]"); + } + } + } + public String generatePresentationId(String name) { long timestamp = System.currentTimeMillis(); return DigestUtils.shaHex(name) + "-" + timestamp; @@ -115,4 +152,18 @@ public class PresentationUrlDownloadService { return success; } + + public void setPresentationDir(String presDir) { + presentationDir = presDir; + } + + public void setPresentationBaseURL(String presentationBaseUrl) { + presentationBaseURL = presentationBaseUrl; + } + + public void setDocumentConversionService(DocumentConversionService documentConversionService) { + this.documentConversionService = documentConversionService; + } + + }