You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openmeetings.apache.org by so...@apache.org on 2017/05/01 06:08:50 UTC

[04/50] [abbrv] openmeetings git commit: [OPENMEETINGS-1601] drop recordings to WB seems to work

[OPENMEETINGS-1601] drop recordings to WB seems to work


Project: http://git-wip-us.apache.org/repos/asf/openmeetings/repo
Commit: http://git-wip-us.apache.org/repos/asf/openmeetings/commit/a5d2b138
Tree: http://git-wip-us.apache.org/repos/asf/openmeetings/tree/a5d2b138
Diff: http://git-wip-us.apache.org/repos/asf/openmeetings/diff/a5d2b138

Branch: refs/heads/3.2.x
Commit: a5d2b1384c16a46e6e6b56a0ab9cf06df7267ae8
Parents: ad627cc
Author: Maxim Solodovnik <so...@apache.org>
Authored: Tue Mar 14 16:52:27 2017 +0000
Committer: Maxim Solodovnik <so...@apache.org>
Committed: Tue Mar 14 16:52:27 2017 +0000

----------------------------------------------------------------------
 .../WhiteBoardObjectListManagerById.java        |  81 ---
 .../whiteboard/WhiteBoardObjectSyncManager.java |  98 ----
 .../core/data/whiteboard/WhiteboardCache.java   |  86 +++
 .../core/data/whiteboard/WhiteboardManager.java |  58 +-
 .../whiteboard/WhiteboardObjectSyncManager.java |  98 ++++
 .../core/remote/ConferenceLibrary.java          |  72 +--
 .../core/remote/WhiteBoardService.java          | 560 -------------------
 .../core/remote/WhiteboardService.java          | 560 +++++++++++++++++++
 .../remote/red5/ScopeApplicationAdapter.java    |  50 +-
 .../openmeetings/db/dto/room/Whiteboard.java    | 189 +++++++
 .../db/dto/room/WhiteboardObject.java           | 189 -------
 .../db/dto/room/WhiteboardObjectList.java       |  45 --
 .../openmeetings/db/dto/room/Whiteboards.java   |  51 ++
 .../whiteboard/base/baseDrawObject.lzx          | 118 ++--
 .../whiteboard/base/whiteboardVideoPlayer.lzx   | 146 +++--
 .../service/quartz/scheduler/CleanupJob.java    |  12 +-
 .../web/admin/labels/LangPanel.html             |   1 -
 .../apache/openmeetings/web/room/RoomPanel.java |  21 +-
 .../web/room/RoomResourceReference.java         |  19 +-
 .../web/room/sidebar/UploadDialog.java          |   4 +-
 .../user/record/RecordingResourceReference.java |  31 +-
 .../classes/openmeetings-applicationContext.xml |  10 +-
 .../openmeetings/webservice/FileWebService.java |  42 --
 23 files changed, 1241 insertions(+), 1300 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/openmeetings/blob/a5d2b138/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteBoardObjectListManagerById.java
----------------------------------------------------------------------
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteBoardObjectListManagerById.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteBoardObjectListManagerById.java
deleted file mode 100644
index f348178..0000000
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteBoardObjectListManagerById.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License") +  you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.openmeetings.core.data.whiteboard;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.apache.openmeetings.db.dto.room.WhiteboardObject;
-import org.apache.openmeetings.db.dto.room.WhiteboardObjectList;
-
-/**
- * Memory based cache, configured as singleton in spring configuration
- *
- * @author sebawagner
- *
- */
-public class WhiteBoardObjectListManagerById {
-	private Map<Long, WhiteboardObjectList> whiteBoardObjectList = new ConcurrentHashMap<>();
-
-	private volatile AtomicLong whiteboardId = new AtomicLong(0);
-
-	public long getNewWhiteboardId(Long roomId, String name) {
-		long wbId = whiteboardId.getAndIncrement();
-		setWhiteBoardObjectListRoomObjAndWhiteboardId(roomId, new WhiteboardObject(name), wbId);
-		return wbId;
-	}
-
-	/*
-	 * Room items a Whiteboard
-	 */
-	public WhiteboardObjectList getWhiteBoardObjectListByRoomId(Long roomId) {
-		if (whiteBoardObjectList.containsKey(roomId)) {
-			return whiteBoardObjectList.get(roomId);
-		} else {
-			WhiteboardObjectList whiteboardObjectList = new WhiteboardObjectList();
-			whiteboardObjectList.setRoomId(roomId);
-			return whiteboardObjectList;
-		}
-	}
-
-	public WhiteboardObject getWhiteBoardObjectListByRoomIdAndWhiteboard(Long roomId, Long whiteBoardId){
-		WhiteboardObjectList whiteboardObjectList = getWhiteBoardObjectListByRoomId(roomId);
-		WhiteboardObject whiteboardObjects = whiteboardObjectList.getWhiteboardObjects().get(whiteBoardId);
-		if (whiteboardObjects == null) {
-			whiteboardObjects = new WhiteboardObject();
-		}
-		return whiteboardObjects;
-	}
-
-	/*
-	 * Whiteboard Object List
-	 *
-	 */
-	public void setWhiteBoardObjectListRoomObj(Long roomId, WhiteboardObjectList whiteboardObjectList){
-		whiteBoardObjectList.put(roomId, whiteboardObjectList);
-	}
-
-	public void setWhiteBoardObjectListRoomObjAndWhiteboardId(Long roomId, WhiteboardObject whiteboardObjects, long whiteBoardId) {
-		WhiteboardObjectList whiteboardObjectList = getWhiteBoardObjectListByRoomId(roomId);
-		whiteboardObjects.setWhiteBoardId(whiteBoardId);
-		whiteboardObjectList.getWhiteboardObjects().put(whiteBoardId, whiteboardObjects);
-		whiteBoardObjectList.put(roomId, whiteboardObjectList);
-	}
-}

http://git-wip-us.apache.org/repos/asf/openmeetings/blob/a5d2b138/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteBoardObjectSyncManager.java
----------------------------------------------------------------------
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteBoardObjectSyncManager.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteBoardObjectSyncManager.java
deleted file mode 100644
index cd2f0b6..0000000
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteBoardObjectSyncManager.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License") +  you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.openmeetings.core.data.whiteboard;
-
-import static org.apache.openmeetings.util.OpenmeetingsVariables.webAppRootKey;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.openmeetings.db.dto.room.WhiteboardSyncLockObject;
-import org.red5.logging.Red5LoggerFactory;
-import org.slf4j.Logger;
-
-/**
- * Memory based, configured as singleton in spring configuration
- *
- * @author sebawagner
- *
- */
-public class WhiteBoardObjectSyncManager {
-	private Map<Long, Map<String, WhiteboardSyncLockObject>> whiteBoardSyncList = new ConcurrentHashMap<>();
-	private Map<Long, Map<String, Map<String, WhiteboardSyncLockObject>>> whiteBoardObjectSyncList = new ConcurrentHashMap<>();
-
-	private static final Logger log = Red5LoggerFactory.getLogger(WhiteBoardObjectSyncManager.class, webAppRootKey);
-
-	/*
-	 * Initial Sync Process
-	 */
-	public void setWhiteBoardSyncListByRoomid(Long roomId, Map<String, WhiteboardSyncLockObject> mapObject) {
-		whiteBoardSyncList.put(roomId, mapObject);
-	}
-
-	public Map<String, WhiteboardSyncLockObject> getWhiteBoardSyncListByRoomid(Long roomId) {
-		if (whiteBoardSyncList.containsKey(roomId)) {
-			return whiteBoardSyncList.get(roomId);
-		} else {
-			return new ConcurrentHashMap<>();
-		}
-	}
-
-	/*
-	 * Image Sync Process
-	 */
-	public void setWhiteBoardImagesSyncListByRoomid(Long roomId, Map<String, Map<String, WhiteboardSyncLockObject>> mapObject) {
-		whiteBoardObjectSyncList.put(roomId, mapObject);
-	}
-
-	public void setWhiteBoardImagesSyncListByRoomAndObjectId(Long roomId, String objectId, Map<String, WhiteboardSyncLockObject> imageSyncList) {
-		Map<String, Map<String, WhiteboardSyncLockObject>> roomList = getWhiteBoardObjectSyncListByRoomid(roomId);
-		if (imageSyncList.isEmpty()) {
-			roomList.remove(objectId);
-		} else {
-			roomList.put(objectId, imageSyncList);
-		}
-		setWhiteBoardImagesSyncListByRoomid(roomId, roomList);
-	}
-
-	public Map<String, Map<String, WhiteboardSyncLockObject>> getWhiteBoardObjectSyncListByRoomid(Long roomId) {
-		if (whiteBoardObjectSyncList.containsKey(roomId)) {
-			return whiteBoardObjectSyncList.get(roomId);
-		} else {
-			return new ConcurrentHashMap<>();
-		}
-	}
-
-	public Map<String, WhiteboardSyncLockObject> getWhiteBoardObjectSyncListByRoomAndObjectId(Long roomId, String objectId) {
-		log.debug("getWhiteBoardImagesSyncListByRoomAndImageid roomId: " + roomId);
-		Map<String, Map<String, WhiteboardSyncLockObject>> roomList = getWhiteBoardObjectSyncListByRoomid(roomId);
-		if (log.isDebugEnabled()) {
-			log.debug("getWhiteBoardImagesSyncListByRoomAndImageid roomList: " + roomList);
-			log.debug("getWhiteBoardImagesSyncListByRoomAndImageid objectId: " + objectId);
-			if (roomList.size() == 1) {
-				log.debug("getWhiteBoardImagesSyncListByRoomAndImageid roomList Key imageId: " + roomList.keySet().iterator().next());
-			}
-		}
-		Map<String, WhiteboardSyncLockObject> imageSyncList = roomList.get(objectId);
-		if (imageSyncList == null) {
-			imageSyncList = new ConcurrentHashMap<>();
-		}
-		return imageSyncList;
-	}
-}

http://git-wip-us.apache.org/repos/asf/openmeetings/blob/a5d2b138/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardCache.java
----------------------------------------------------------------------
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardCache.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardCache.java
new file mode 100644
index 0000000..0dd12ba
--- /dev/null
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardCache.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.core.data.whiteboard;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.openmeetings.db.dto.room.Whiteboard;
+import org.apache.openmeetings.db.dto.room.Whiteboards;
+
+/**
+ * Memory based cache, configured as singleton in spring configuration
+ *
+ * @author sebawagner
+ *
+ */
+public class WhiteboardCache {
+	private Map<Long, Whiteboards> cache = new ConcurrentHashMap<>();
+
+	private volatile AtomicLong whiteboardId = new AtomicLong(0);
+
+	public long getNewWhiteboardId(Long roomId, String name) {
+		long wbId = whiteboardId.getAndIncrement();
+		set(roomId, new Whiteboard(name), wbId);
+		return wbId;
+	}
+
+	/*
+	 * Room items a Whiteboard
+	 */
+	public Whiteboards get(Long roomId) {
+		if (roomId == null) {
+			return null;
+		}
+		if (cache.containsKey(roomId)) {
+			return cache.get(roomId);
+		} else {
+			Whiteboards whiteboards = new Whiteboards();
+			whiteboards.setRoomId(roomId);
+			set(roomId, whiteboards);
+			return whiteboards;
+		}
+	}
+
+	public Whiteboard get(Long roomId, Long whiteBoardId) {
+		Whiteboards whiteboards = get(roomId);
+		Whiteboard wb = whiteboards.getWhiteboards().get(whiteBoardId);
+		if (wb == null) {
+			wb = new Whiteboard();
+			set(roomId, wb, whiteBoardId);
+		}
+		return wb;
+	}
+
+	/*
+	 * Whiteboard Object List
+	 *
+	 */
+	public void set(Long roomId, Whiteboards whiteboards) {
+		cache.put(roomId, whiteboards);
+	}
+
+	public void set(Long roomId, Whiteboard wb, long whiteBoardId) {
+		Whiteboards whiteboards = get(roomId);
+		wb.setWhiteBoardId(whiteBoardId);
+		whiteboards.getWhiteboards().put(whiteBoardId, wb);
+		cache.put(roomId, whiteboards);
+	}
+}

http://git-wip-us.apache.org/repos/asf/openmeetings/blob/a5d2b138/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardManager.java
----------------------------------------------------------------------
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardManager.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardManager.java
index fc89b27..be488fc 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardManager.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardManager.java
@@ -24,21 +24,21 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
-import org.apache.openmeetings.db.dto.room.WhiteboardObject;
+import org.apache.openmeetings.db.dto.room.Whiteboard;
 import org.red5.logging.Red5LoggerFactory;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 
 public class WhiteboardManager {
 	private static final Logger log = Red5LoggerFactory.getLogger(WhiteboardManager.class, webAppRootKey);
-	
+
 	@Autowired
-	private WhiteBoardObjectListManagerById wbListManagerById;
+	private WhiteboardCache whitebardCache;
 
 	@SuppressWarnings("unchecked")
-	public void addWhiteBoardObjectById(Long roomId, Map<Integer, Object> whiteboardObj, Long whiteBoardId) {
+	public void add(Long roomId, Map<Integer, Object> whiteboardObj, Long whiteBoardId) {
 		try {
-			log.debug("addWhiteBoardObjectById: ", whiteboardObj);
+			log.debug("add: ", whiteboardObj);
 
 			String action = whiteboardObj.get(2).toString();
 
@@ -47,16 +47,11 @@ public class WhiteboardManager {
 
 			List<Object> actionObject = (List<Object>) whiteboardObj.get(3);
 
+			Whiteboard wb = whitebardCache.get(roomId, whiteBoardId);
 			if (action.equals("moveMap")) {
-				WhiteboardObject whiteboardObject = wbListManagerById.getWhiteBoardObjectListByRoomIdAndWhiteboard(roomId, whiteBoardId);
-
-				whiteboardObject.setX(Integer.valueOf(actionObject.get(1).toString()));
-				whiteboardObject.setY(Integer.valueOf(actionObject.get(2).toString()));
-
-				wbListManagerById.setWhiteBoardObjectListRoomObjAndWhiteboardId(roomId, whiteboardObject, whiteBoardId);
+				wb.setX(Integer.valueOf(actionObject.get(1).toString()));
+				wb.setY(Integer.valueOf(actionObject.get(2).toString()));
 			} else if (action.equals("draw") || action.equals("redo")) {
-				WhiteboardObject whiteboardObject = wbListManagerById.getWhiteBoardObjectListByRoomIdAndWhiteboard(roomId, whiteBoardId);
-
 				// log.debug(actionObject);
 				// log.debug(actionObject.size()-1);
 				// log.debug(actionObject.get(actionObject.size()-1));
@@ -65,33 +60,26 @@ public class WhiteboardManager {
 					if (!objectType.equals("pointerWhiteBoard")) {
 						String objectOID = actionObject.get(actionObject.size() - 1).toString();
 						log.debug("objectOID: " + objectOID);
-						whiteboardObject.add(objectOID, actionObject);
-						wbListManagerById.setWhiteBoardObjectListRoomObjAndWhiteboardId(roomId, whiteboardObject, whiteBoardId);
+						wb.add(objectOID, actionObject);
 					}
 				}
 			} else if (action.equals("clear")) {
-				WhiteboardObject whiteboardObject = wbListManagerById.getWhiteBoardObjectListByRoomIdAndWhiteboard(roomId, whiteBoardId);
-				whiteboardObject.clear();
-				wbListManagerById.setWhiteBoardObjectListRoomObjAndWhiteboardId(roomId, whiteboardObject, whiteBoardId);
+				wb.clear();
 			} else if (action.equals("delete") || action.equals("undo")) {
-				WhiteboardObject whiteboardObject = wbListManagerById.getWhiteBoardObjectListByRoomIdAndWhiteboard(roomId, whiteBoardId);
-				whiteboardObject.remove(actionObject);
-
-				wbListManagerById.setWhiteBoardObjectListRoomObjAndWhiteboardId(roomId, whiteboardObject, whiteBoardId);
+				wb.remove(actionObject);
 			} else if (action.equals("size") || action.equals("editProp")
 					|| action.equals("editTextMindMapNode")
 					|| action.equals("editText") || action.equals("swf")
 					|| action.equals("flv")
 					|| action.equals("editTextMindMapColor")
 					|| action.equals("editTextMindMapFontColor")) {
-				WhiteboardObject whiteboardObject = wbListManagerById.getWhiteBoardObjectListByRoomIdAndWhiteboard(roomId, whiteBoardId);
 				String objectOID = actionObject.get(actionObject.size() - 1).toString();
 				// List roomItem = roomList.get(objectOID);
-				List<Object> currentObject = whiteboardObject.get(objectOID);
+				List<Object> currentObject = wb.get(objectOID);
 				if ("paint".equals(actionObject.get(0))) {
 					actionObject.set(1, currentObject.get(1));
 				}
-				whiteboardObject.add(objectOID, actionObject);
+				wb.add(objectOID, actionObject);
 
 				if (action.equals("swf")) {
 					log.debug("actionObject " + actionObject);
@@ -102,7 +90,7 @@ public class WhiteboardManager {
 
 							log.debug("updateObjectsToSlideNumber :: " + baseObjectName + "," + slidesNumber);
 
-							for (Entry<String, List<Object>> me : whiteboardObject.entrySet()) {
+							for (Entry<String, List<Object>> me : wb.entrySet()) {
 								List<Object> actionObjectStored = me.getValue();
 
 								if (actionObjectStored.get(0).equals("ellipse")
@@ -131,28 +119,18 @@ public class WhiteboardManager {
 						}
 					}
 				}
-
-				wbListManagerById.setWhiteBoardObjectListRoomObjAndWhiteboardId(roomId, whiteboardObject, whiteBoardId);
 			} else if (action.equals("clearSlide")) {
-				WhiteboardObject whiteboardObject = wbListManagerById.getWhiteBoardObjectListByRoomIdAndWhiteboard(roomId, whiteBoardId);
-
 				for (Object objectName : actionObject) {
-					whiteboardObject.remove(objectName);
+					wb.remove(objectName);
 				}
-
-				wbListManagerById.setWhiteBoardObjectListRoomObjAndWhiteboardId(roomId, whiteboardObject, whiteBoardId);
 			} else if (action.equals("whiteboardObj")) {
-				WhiteboardObject whiteboardObject = wbListManagerById.getWhiteBoardObjectListByRoomIdAndWhiteboard(roomId, whiteBoardId);
-
-				whiteboardObject.setFullFit((Boolean) actionObject.get(1));
-				whiteboardObject.setZoom((Integer) actionObject.get(2));
-
-				wbListManagerById.setWhiteBoardObjectListRoomObjAndWhiteboardId(roomId, whiteboardObject, whiteBoardId);
+				wb.setFullFit((Boolean) actionObject.get(1));
+				wb.setZoom((Integer) actionObject.get(2));
 			} else {
 				log.warn("Unkown Type: " + action + " actionObject: " + actionObject);
 			}
 		} catch (Exception err) {
-			log.error("[addWhiteBoardObject]", err);
+			log.error("[add]", err);
 		}
 	}
 }

http://git-wip-us.apache.org/repos/asf/openmeetings/blob/a5d2b138/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardObjectSyncManager.java
----------------------------------------------------------------------
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardObjectSyncManager.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardObjectSyncManager.java
new file mode 100644
index 0000000..6998a2b
--- /dev/null
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardObjectSyncManager.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.core.data.whiteboard;
+
+import static org.apache.openmeetings.util.OpenmeetingsVariables.webAppRootKey;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.openmeetings.db.dto.room.WhiteboardSyncLockObject;
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+
+/**
+ * Memory based, configured as singleton in spring configuration
+ *
+ * @author sebawagner
+ *
+ */
+public class WhiteboardObjectSyncManager {
+	private Map<Long, Map<String, WhiteboardSyncLockObject>> whiteBoardSyncList = new ConcurrentHashMap<>();
+	private Map<Long, Map<String, Map<String, WhiteboardSyncLockObject>>> whiteBoardObjectSyncList = new ConcurrentHashMap<>();
+
+	private static final Logger log = Red5LoggerFactory.getLogger(WhiteboardObjectSyncManager.class, webAppRootKey);
+
+	/*
+	 * Initial Sync Process
+	 */
+	public void setWhiteBoardSyncListByRoomid(Long roomId, Map<String, WhiteboardSyncLockObject> mapObject) {
+		whiteBoardSyncList.put(roomId, mapObject);
+	}
+
+	public Map<String, WhiteboardSyncLockObject> getWhiteBoardSyncListByRoomid(Long roomId) {
+		if (whiteBoardSyncList.containsKey(roomId)) {
+			return whiteBoardSyncList.get(roomId);
+		} else {
+			return new ConcurrentHashMap<>();
+		}
+	}
+
+	/*
+	 * Image Sync Process
+	 */
+	public void setWhiteBoardImagesSyncListByRoomid(Long roomId, Map<String, Map<String, WhiteboardSyncLockObject>> mapObject) {
+		whiteBoardObjectSyncList.put(roomId, mapObject);
+	}
+
+	public void setWhiteBoardImagesSyncListByRoomAndObjectId(Long roomId, String objectId, Map<String, WhiteboardSyncLockObject> imageSyncList) {
+		Map<String, Map<String, WhiteboardSyncLockObject>> roomList = getWhiteBoardObjectSyncListByRoomid(roomId);
+		if (imageSyncList.isEmpty()) {
+			roomList.remove(objectId);
+		} else {
+			roomList.put(objectId, imageSyncList);
+		}
+		setWhiteBoardImagesSyncListByRoomid(roomId, roomList);
+	}
+
+	public Map<String, Map<String, WhiteboardSyncLockObject>> getWhiteBoardObjectSyncListByRoomid(Long roomId) {
+		if (whiteBoardObjectSyncList.containsKey(roomId)) {
+			return whiteBoardObjectSyncList.get(roomId);
+		} else {
+			return new ConcurrentHashMap<>();
+		}
+	}
+
+	public Map<String, WhiteboardSyncLockObject> getWhiteBoardObjectSyncListByRoomAndObjectId(Long roomId, String objectId) {
+		log.debug("getWhiteBoardImagesSyncListByRoomAndImageid roomId: " + roomId);
+		Map<String, Map<String, WhiteboardSyncLockObject>> roomList = getWhiteBoardObjectSyncListByRoomid(roomId);
+		if (log.isDebugEnabled()) {
+			log.debug("getWhiteBoardImagesSyncListByRoomAndImageid roomList: " + roomList);
+			log.debug("getWhiteBoardImagesSyncListByRoomAndImageid objectId: " + objectId);
+			if (roomList.size() == 1) {
+				log.debug("getWhiteBoardImagesSyncListByRoomAndImageid roomList Key imageId: " + roomList.keySet().iterator().next());
+			}
+		}
+		Map<String, WhiteboardSyncLockObject> imageSyncList = roomList.get(objectId);
+		if (imageSyncList == null) {
+			imageSyncList = new ConcurrentHashMap<>();
+		}
+		return imageSyncList;
+	}
+}

http://git-wip-us.apache.org/repos/asf/openmeetings/blob/a5d2b138/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/ConferenceLibrary.java
----------------------------------------------------------------------
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/ConferenceLibrary.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/ConferenceLibrary.java
index b024b5d..58c6350 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/ConferenceLibrary.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/ConferenceLibrary.java
@@ -18,27 +18,22 @@
  */
 package org.apache.openmeetings.core.remote;
 
-import static org.apache.openmeetings.util.OmFileHelper.EXTENSION_MP4;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.webAppRootKey;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.commons.io.FileUtils;
 import org.apache.openmeetings.core.data.whiteboard.WhiteboardManager;
 import org.apache.openmeetings.core.documents.LibraryChartLoader;
 import org.apache.openmeetings.core.documents.LibraryDocumentConverter;
 import org.apache.openmeetings.core.documents.LibraryWmlLoader;
-import org.apache.openmeetings.core.documents.LoadLibraryPresentation;
 import org.apache.openmeetings.core.remote.red5.ScopeApplicationAdapter;
 import org.apache.openmeetings.db.dao.file.FileExplorerItemDao;
 import org.apache.openmeetings.db.dao.server.ISessionManager;
 import org.apache.openmeetings.db.dao.server.SessiondataDao;
 import org.apache.openmeetings.db.dao.user.UserDao;
-import org.apache.openmeetings.db.dto.file.LibraryPresentation;
 import org.apache.openmeetings.db.dto.server.ClientSessionInfo;
 import org.apache.openmeetings.db.entity.file.FileExplorerItem;
 import org.apache.openmeetings.db.entity.file.FileItem;
@@ -48,8 +43,6 @@ import org.apache.openmeetings.db.entity.server.Sessiondata;
 import org.apache.openmeetings.db.util.AuthLevelUtil;
 import org.apache.openmeetings.util.OmFileHelper;
 import org.red5.logging.Red5LoggerFactory;
-import org.red5.server.api.IConnection;
-import org.red5.server.api.Red5;
 import org.red5.server.api.service.IPendingServiceCall;
 import org.red5.server.api.service.IPendingServiceCallback;
 import org.slf4j.Logger;
@@ -72,35 +65,10 @@ public class ConferenceLibrary implements IPendingServiceCallback {
 	@Autowired
 	private FileExplorerItemDao fileDao;
 	@Autowired
-	private WhiteboardManager whiteboardManagement;
+	private WhiteboardManager whiteboardManager;
 	@Autowired
 	private ScopeApplicationAdapter scopeAdapter;
 
-	public LibraryPresentation getPresentationPreviewFileExplorer(String sid, String parentFolder) {
-		try {
-			Sessiondata sd = sessionDao.check(sid);
-
-			log.debug("#############users_id : " + sd.getUserId());
-
-			if (AuthLevelUtil.hasUserLevel(userDao.getRights(sd.getUserId()))) {
-				File working_dir = new File(OmFileHelper.getUploadFilesDir(), parentFolder);
-				log.debug("############# working_dir : " + working_dir);
-
-				File file = new File(working_dir, OmFileHelper.libraryFileName);
-
-				if (!file.exists()) {
-					throw new Exception(file.getCanonicalPath() + ": does not exist");
-				}
-				return LoadLibraryPresentation.parseLibraryFileToObject(file);
-			} else {
-				throw new Exception("not Authenticated");
-			}
-		} catch (Exception e) {
-			log.error("[getListOfFilesByAbsolutePath]", e);
-			return null;
-		}
-	}
-
 	/**
 	 *
 	 * Save an Object to the library and returns the file-explorer Id
@@ -165,7 +133,7 @@ public class ConferenceLibrary implements IPendingServiceCallback {
 		wbClear.put(3, null);
 
 		Long roomId = client.getRoomId();
-		whiteboardManagement.addWhiteBoardObjectById(roomId, wbClear, wbId);
+		whiteboardManager.add(roomId, wbClear, wbId);
 
 		for (int k = 0; k < roomItems.size(); k++) {
 			List<?> actionObject = (List<?>)roomItems.get(k);
@@ -174,7 +142,7 @@ public class ConferenceLibrary implements IPendingServiceCallback {
 			whiteboardObj.put(2, "draw");
 			whiteboardObj.put(3, actionObject);
 
-			whiteboardManagement.addWhiteBoardObjectById(roomId, whiteboardObj, wbId);
+			whiteboardManager.add(roomId, whiteboardObj, wbId);
 		}
 
 		Map<String, Object> sendObject = new HashMap<>();
@@ -206,40 +174,6 @@ public class ConferenceLibrary implements IPendingServiceCallback {
 		return null;
 	}
 
-	/**
-	 * @param sid
-	 * @param fileId
-	 * @return 1 in case of success, -1 otherwise
-	 */
-	public Long copyFileToCurrentRoom(String sid, Long fileId) {
-		try {
-			Sessiondata sd = sessionDao.check(sid);
-			if (AuthLevelUtil.hasUserLevel(userDao.getRights(sd.getUserId()))) {
-				IConnection current = Red5.getConnectionLocal();
-				String streamid = current.getClient().getId();
-
-				Client client = sessionManager.getClientByStreamId(streamid, null);
-				Long roomId = client.getRoomId();
-
-				FileExplorerItem f = fileDao.get(fileId);
-				if (roomId != null && f != null) {
-					File mp4 = f.getFile(EXTENSION_MP4);
-
-					File targetFolder = OmFileHelper.getStreamsSubDir(roomId);
-
-					File target = new File(targetFolder, mp4.getName());
-					if (mp4.exists() && !target.exists()) {
-						FileUtils.copyFile(mp4, target, false);
-					}
-					return 1L;
-				}
-			}
-		} catch (Exception err) {
-			log.error("[copyFileToCurrentRoom] ", err);
-		}
-		return -1L;
-	}
-
 	@Override
 	public void resultReceived(IPendingServiceCall arg0) {
 		// TODO Auto-generated method stub

http://git-wip-us.apache.org/repos/asf/openmeetings/blob/a5d2b138/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/WhiteBoardService.java
----------------------------------------------------------------------
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/WhiteBoardService.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/WhiteBoardService.java
deleted file mode 100644
index 9cd5a9b..0000000
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/WhiteBoardService.java
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License") +  you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.openmeetings.core.remote;
-
-import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_DEFAULT_LANG_KEY;
-import static org.apache.openmeetings.util.OpenmeetingsVariables.webAppRootKey;
-
-import java.io.File;
-import java.io.FilenameFilter;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.Map;
-
-import org.apache.commons.collections4.ComparatorUtils;
-import org.apache.openmeetings.core.data.whiteboard.WhiteBoardObjectListManagerById;
-import org.apache.openmeetings.core.data.whiteboard.WhiteBoardObjectSyncManager;
-import org.apache.openmeetings.core.remote.red5.ScopeApplicationAdapter;
-import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
-import org.apache.openmeetings.db.dao.label.LabelDao;
-import org.apache.openmeetings.db.dao.server.ISessionManager;
-import org.apache.openmeetings.db.dao.server.SessiondataDao;
-import org.apache.openmeetings.db.dao.user.UserDao;
-import org.apache.openmeetings.db.dto.room.Cliparts;
-import org.apache.openmeetings.db.dto.room.WhiteboardObject;
-import org.apache.openmeetings.db.dto.room.WhiteboardObjectList;
-import org.apache.openmeetings.db.dto.room.WhiteboardSyncLockObject;
-import org.apache.openmeetings.db.entity.room.Client;
-import org.apache.openmeetings.db.entity.server.Sessiondata;
-import org.apache.openmeetings.db.entity.user.User;
-import org.apache.openmeetings.db.util.AuthLevelUtil;
-import org.apache.openmeetings.util.OmFileHelper;
-import org.red5.logging.Red5LoggerFactory;
-import org.red5.server.api.IConnection;
-import org.red5.server.api.Red5;
-import org.red5.server.api.scope.IScope;
-import org.red5.server.api.service.IPendingServiceCall;
-import org.red5.server.api.service.IPendingServiceCallback;
-import org.slf4j.Logger;
-import org.springframework.beans.factory.annotation.Autowired;
-
-/**
- *
- * @author sebastianwagner
- *
- */
-public class WhiteBoardService implements IPendingServiceCallback {
-	private static final Logger log = Red5LoggerFactory.getLogger(WhiteBoardService.class, webAppRootKey);
-	@Autowired
-	private UserDao userDao;
-	@Autowired
-	private ScopeApplicationAdapter scopeAdapter;
-	@Autowired
-	private ISessionManager sessionManager;
-	@Autowired
-	private WhiteBoardObjectSyncManager wbListManager;
-	@Autowired
-	private WhiteBoardObjectListManagerById wbListManagerById;
-	@Autowired
-	private SessiondataDao sessionDao;
-	@Autowired
-	private LabelDao labelDao;
-	@Autowired
-	private ConfigurationDao cfgDao;
-
-	public boolean getNewWhiteboardId(String name) {
-		try {
-			IConnection current = Red5.getConnectionLocal();
-			String streamid = current.getClient().getId();
-			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
-			Long roomId = currentClient.getRoomId();
-
-			Long whiteBoardId = wbListManagerById.getNewWhiteboardId(roomId, name);
-			scopeAdapter.sendMessageAll(Arrays.asList("newWhiteboard", whiteBoardId, name));
-		} catch (Exception e) {
-			log.error("[getNewWhiteboardId]", e);
-			return false;
-		}
-		return true;
-	}
-
-	public boolean deleteWhiteboard(Long whiteBoardId) {
-		try {
-			IConnection current = Red5.getConnectionLocal();
-			String streamid = current.getClient().getId();
-			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
-			Long roomId = currentClient.getRoomId();
-
-			WhiteboardObjectList whiteboardObjectList = wbListManagerById.getWhiteBoardObjectListByRoomId(roomId);
-			Object returnValue = whiteboardObjectList.getWhiteboardObjects().remove(whiteBoardId);
-
-			log.debug(" :: whiteBoardId :: " + whiteBoardId);
-
-			wbListManagerById.setWhiteBoardObjectListRoomObj(roomId, whiteboardObjectList);
-
-			if (returnValue != null) {
-				return true;
-			}
-		} catch (Exception err) {
-			log.error("[deleteWhiteboard]", err);
-		}
-		return false;
-	}
-
-	public Map<Long, WhiteboardObject> getRoomItemsBy() {
-		Map<Long, WhiteboardObject> result = new LinkedHashMap<>();
-		try {
-			IConnection current = Red5.getConnectionLocal();
-			String streamid = current.getClient().getId();
-			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
-			Long roomId = currentClient.getRoomId();
-
-			log.debug("getRoomItems: " + roomId);
-			WhiteboardObjectList whiteboardObjectList = wbListManagerById.getWhiteBoardObjectListByRoomId(roomId);
-
-			if (whiteboardObjectList.getWhiteboardObjects().size() == 0) {
-				Long langId = null;
-				{
-					Long userId = currentClient.getUserId();
-					if (userId != null && userId.longValue() < 0) {
-						userId = -userId;
-					}
-					User u = userDao.get(userId);
-					langId = u == null ? cfgDao.getConfValue(CONFIG_DEFAULT_LANG_KEY, Long.class, "1") : u.getLanguageId();
-				}
-				wbListManagerById.getNewWhiteboardId(roomId, labelDao.getString("615", langId));
-				log.debug("Init New Room List");
-				whiteboardObjectList = wbListManagerById.getWhiteBoardObjectListByRoomId(roomId);
-			}
-			whiteboardObjectList.getWhiteboardObjects().entrySet().stream()
-					.sorted(Map.Entry.<Long, WhiteboardObject>comparingByKey().reversed())
-					.forEachOrdered(x -> result.put(x.getKey(), x.getValue()));
-		} catch (Exception err) {
-			log.error("[getRoomItemsBy]", err);
-		}
-		return result;
-	}
-
-	public boolean rename(Long wbId, String name) {
-		try {
-			IConnection current = Red5.getConnectionLocal();
-			String streamid = current.getClient().getId();
-			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
-			Long roomId = currentClient.getRoomId();
-
-			WhiteboardObjectList whiteboardObjectList = wbListManagerById.getWhiteBoardObjectListByRoomId(roomId);
-			WhiteboardObject wb = whiteboardObjectList.getWhiteboardObjects().get(wbId);
-			wb.setName(name);
-
-			log.debug(" :: rename whiteBoard :: id = {}, name = {}", wbId, name);
-			scopeAdapter.sendMessageAll(Arrays.asList("renameWhiteboard", wbId, name));
-		} catch (Exception err) {
-			log.error("[rename]", err);
-			return false;
-		}
-		return true;
-	}
-
-	/**
-	 * change the draw status of a user, allow disallow him to draw anybody
-	 * besides the Moderator to draw on the whiteboard, only a Moderator is
-	 * allowed to trigger this function
-	 *
-	 * @param sid
-	 * @param publicSID
-	 * @param canDraw
-	 * @return null in case of success, false otherwise
-	 */
-	public boolean setCanDraw(String sid, String publicSID, boolean canDraw) {
-		try {
-			IConnection current = Red5.getConnectionLocal();
-			String streamid = current.getClient().getId();
-			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
-
-			Sessiondata sd = sessionDao.check(sid);
-			if (AuthLevelUtil.hasUserLevel(userDao.getRights(sd.getUserId()))) {
-				if (currentClient.getIsMod()) {
-					Client rcl = sessionManager.getClientByPublicSID(publicSID, null);
-
-					if (rcl != null) {
-						rcl.setCanDraw(canDraw);
-						sessionManager.updateClientByStreamId(rcl.getStreamid(), rcl, false, null);
-
-						Map<Integer, Object> newMessage = new HashMap<>();
-						newMessage.put(0, "updateDrawStatus");
-						newMessage.put(1, rcl);
-						scopeAdapter.sendMessageWithClientWithSyncObject(newMessage, true);
-						return true;
-					}
-				}
-			}
-		} catch (Exception err) {
-			log.error("[setCanDraw]", err);
-		}
-		return false;
-	}
-
-	public boolean setCanShare(String sid, String publicSID, boolean canShare) {
-		try {
-			IConnection current = Red5.getConnectionLocal();
-			String streamid = current.getClient().getId();
-			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
-
-			Sessiondata sd = sessionDao.check(sid);
-			if (AuthLevelUtil.hasUserLevel(userDao.getRights(sd.getUserId()))) {
-				if (currentClient.getIsMod()) {
-					Client rcl = sessionManager.getClientByPublicSID(publicSID, null);
-
-					if (rcl != null) {
-						rcl.setCanShare(canShare);
-						sessionManager.updateClientByStreamId(rcl.getStreamid(), rcl, false, null);
-
-						Map<Integer, Object> newMessage = new HashMap<>();
-						newMessage.put(0, "updateDrawStatus");
-						newMessage.put(1, rcl);
-						scopeAdapter.sendMessageWithClientWithSyncObject(newMessage, true);
-						return true;
-					}
-				}
-			}
-		} catch (Exception err) {
-			log.error("[setCanShare]", err);
-		}
-		return false;
-	}
-
-	public boolean setCanRemote(String sid, String publicSID, boolean canRemote) {
-		try {
-			IConnection current = Red5.getConnectionLocal();
-			String streamid = current.getClient().getId();
-			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
-
-			Sessiondata sd = sessionDao.check(sid);
-			if (AuthLevelUtil.hasUserLevel(userDao.getRights(sd.getUserId()))) {
-				if (currentClient.getIsMod()) {
-					Client rcl = sessionManager.getClientByPublicSID(publicSID, null);
-
-					if (rcl != null) {
-						rcl.setCanRemote(canRemote);
-						sessionManager.updateClientByStreamId(rcl.getStreamid(), rcl, false, null);
-
-						Map<Integer, Object> newMessage = new HashMap<>();
-						newMessage.put(0, "updateDrawStatus");
-						newMessage.put(1, rcl);
-						scopeAdapter.sendMessageWithClientWithSyncObject(newMessage, true);
-						return true;
-					}
-				}
-			}
-		} catch (Exception err) {
-			log.error("[setCanDraw]", err);
-		}
-		return false;
-	}
-
-	public boolean setCanGiveAudio(String sid, String publicSID, boolean canGiveAudio) {
-		try {
-			log.debug("[setCanGiveAudio] " + sid + ", " + publicSID + ", " + canGiveAudio);
-			IConnection current = Red5.getConnectionLocal();
-			String streamid = current.getClient().getId();
-			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
-
-			Sessiondata sd = sessionDao.check(sid);
-			if (AuthLevelUtil.hasUserLevel(userDao.getRights(sd.getUserId()))) {
-				if (currentClient.getIsMod()) {
-					Client rcl = sessionManager.getClientByPublicSID(publicSID, null);
-
-					if (rcl != null) {
-						rcl.setCanGiveAudio(canGiveAudio);
-						sessionManager.updateClientByStreamId(rcl.getStreamid(), rcl, false, null);
-
-						Map<Integer, Object> newMessage = new HashMap<>();
-						newMessage.put(0, "updateGiveAudioStatus");
-						newMessage.put(1, rcl);
-						scopeAdapter.sendMessageWithClientWithSyncObject(newMessage, true);
-						return true;
-					}
-				}
-			}
-		} catch (Exception err) {
-			log.error("[setCanGiveAudio]", err);
-		}
-		return false;
-	}
-
-	public WhiteboardSyncLockObject startNewSyncprocess() {
-		try {
-			IConnection current = Red5.getConnectionLocal();
-			String streamid = current.getClient().getId();
-			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
-			Long roomId = currentClient.getRoomId();
-
-			WhiteboardSyncLockObject wSyncLockObject = new WhiteboardSyncLockObject();
-			wSyncLockObject.setAddtime(new Date());
-			wSyncLockObject.setPublicSID(currentClient.getPublicSID());
-			wSyncLockObject.setInitialLoaded(true);
-
-			Map<String, WhiteboardSyncLockObject> syncListRoom = wbListManager.getWhiteBoardSyncListByRoomid(roomId);
-
-			wSyncLockObject.setCurrentLoadingItem(true);
-			wSyncLockObject.setInserted(new Date());
-
-			syncListRoom.put(currentClient.getPublicSID(), wSyncLockObject);
-			wbListManager.setWhiteBoardSyncListByRoomid(roomId, syncListRoom);
-
-			//Sync to clients
-			scopeAdapter.sendMessageToCurrentScope("sendSyncFlag", wSyncLockObject, true);
-
-			return wSyncLockObject;
-		} catch (Exception err) {
-			log.error("[startNewSyncprocess]", err);
-		}
-		return null;
-	}
-
-	public void sendCompletedSyncEvent() {
-		try {
-			IConnection current = Red5.getConnectionLocal();
-			String streamid = current.getClient().getId();
-			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
-			Long roomId = currentClient.getRoomId();
-
-			Map<String, WhiteboardSyncLockObject> syncListRoom = wbListManager.getWhiteBoardSyncListByRoomid(roomId);
-
-			WhiteboardSyncLockObject wSyncLockObject = syncListRoom.get(currentClient.getPublicSID());
-
-			if (wSyncLockObject == null) {
-				log.error("WhiteboardSyncLockObject not found for this Client "
-						+ syncListRoom);
-				return;
-			} else if (!wSyncLockObject.isCurrentLoadingItem()) {
-				log.warn("WhiteboardSyncLockObject was not started yet " + syncListRoom);
-				return;
-			} else {
-				syncListRoom.remove(currentClient.getPublicSID());
-				wbListManager.setWhiteBoardSyncListByRoomid(roomId, syncListRoom);
-
-				int numberOfInitial = getNumberOfInitialLoaders(syncListRoom);
-
-				if (numberOfInitial == 0) {
-					scopeAdapter.sendMessageToCurrentScope("sendSyncCompleteFlag", wSyncLockObject, true);
-				} else {
-					return;
-				}
-			}
-		} catch (Exception err) {
-			log.error("[sendCompletedSyncEvent]", err);
-		}
-		return;
-	}
-
-	private static int getNumberOfInitialLoaders(Map<String, WhiteboardSyncLockObject> syncListRoom) {
-		int number = 0;
-		for (Map.Entry<String, WhiteboardSyncLockObject> e : syncListRoom.entrySet()) {
-			if (e.getValue().isInitialLoaded()) {
-				number++;
-			}
-		}
-		return number;
-	}
-
-	/*
-	 * Image Sync Sequence
-	 */
-
-	public void startNewObjectSyncProcess(String objectId, boolean isStarting) {
-		try {
-			log.debug("startNewObjectSyncprocess: " + objectId);
-
-			IConnection current = Red5.getConnectionLocal();
-			String streamid = current.getClient().getId();
-			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
-			Long roomId = currentClient.getRoomId();
-
-			WhiteboardSyncLockObject wSyncLockObject = new WhiteboardSyncLockObject();
-			wSyncLockObject.setAddtime(new Date());
-			wSyncLockObject.setPublicSID(currentClient.getPublicSID());
-			wSyncLockObject.setInserted(new Date());
-
-			Map<String, WhiteboardSyncLockObject> syncListImage = wbListManager.getWhiteBoardObjectSyncListByRoomAndObjectId(roomId, objectId);
-			syncListImage.put(currentClient.getPublicSID(), wSyncLockObject);
-			wbListManager.setWhiteBoardImagesSyncListByRoomAndObjectId(roomId, objectId, syncListImage);
-
-			// Do only send the Token to show the Loading Splash for the
-			// initial-Request that starts the loading
-			if (isStarting) {
-				scopeAdapter.sendMessageToCurrentScope("sendObjectSyncFlag", wSyncLockObject, true);
-			}
-		} catch (Exception err) {
-			log.error("[startNewObjectSyncProcess]", err);
-		}
-	}
-
-	public int sendCompletedObjectSyncEvent(String objectId) {
-		try {
-			log.debug("sendCompletedObjectSyncEvent: " + objectId);
-
-			IConnection current = Red5.getConnectionLocal();
-			String streamid = current.getClient().getId();
-			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
-			Long roomId = currentClient.getRoomId();
-
-			Map<String, WhiteboardSyncLockObject> syncListImage = wbListManager.getWhiteBoardObjectSyncListByRoomAndObjectId(roomId, objectId);
-
-			log.debug("sendCompletedObjectSyncEvent syncListImage: " + syncListImage);
-
-			WhiteboardSyncLockObject wSyncLockObject = syncListImage.get(currentClient.getPublicSID());
-
-			if (wSyncLockObject == null) {
-				log.error("WhiteboardSyncLockObject not found for this Client " + currentClient.getPublicSID());
-				log.error("WhiteboardSyncLockObject not found for this syncListImage " + syncListImage);
-				return -2;
-			} else {
-				log.debug("sendCompletedImagesSyncEvent remove: " + currentClient.getPublicSID());
-
-				syncListImage.remove(currentClient.getPublicSID());
-				wbListManager.setWhiteBoardImagesSyncListByRoomAndObjectId(roomId, objectId, syncListImage);
-
-				int numberOfInitial = wbListManager.getWhiteBoardObjectSyncListByRoomid(roomId).size();
-
-				log.debug("sendCompletedImagesSyncEvent numberOfInitial: " + numberOfInitial);
-
-				if (numberOfInitial == 0) {
-					scopeAdapter.sendMessageToCurrentScope("sendObjectSyncCompleteFlag", wSyncLockObject, true);
-					return 1;
-				} else {
-					return -4;
-				}
-			}
-		} catch (Exception err) {
-			log.error("[sendCompletedObjectSyncEvent]", err);
-		}
-		return -1;
-	}
-
-	public synchronized void removeUserFromAllLists(IScope scope, Client currentClient) {
-		try {
-			Long roomId = currentClient.getRoomId();
-
-			// TODO: Maybe we should also check all rooms, independent from the
-			// current roomId if there is any user registered
-			if (roomId != null) {
-				log.debug("removeUserFromAllLists this.whiteBoardObjectListManager: " + wbListManager);
-				log.debug("removeUserFromAllLists roomId: " + roomId);
-
-				// Check Initial Loaders
-				Map<String, WhiteboardSyncLockObject> syncListRoom = wbListManager.getWhiteBoardSyncListByRoomid(roomId);
-
-				WhiteboardSyncLockObject wSyncLockObject = syncListRoom.get(currentClient.getPublicSID());
-
-				if (wSyncLockObject != null) {
-					syncListRoom.remove(currentClient.getPublicSID());
-				}
-				wbListManager.setWhiteBoardSyncListByRoomid(roomId, syncListRoom);
-
-				int numberOfInitial = getNumberOfInitialLoaders(syncListRoom);
-
-				log.debug("scope " + scope);
-
-				if (numberOfInitial == 0 && scope != null) {
-					scopeAdapter.sendMessageToCurrentScope("" + roomId, "sendSyncCompleteFlag", wSyncLockObject, false);
-				}
-
-				// Check Image Loaders
-				Map<String, Map<String, WhiteboardSyncLockObject>> syncListRoomImages = wbListManager.getWhiteBoardObjectSyncListByRoomid(roomId);
-
-				for (Map.Entry<String, Map<String, WhiteboardSyncLockObject>> e : syncListRoomImages.entrySet()) {
-					if (e.getValue().containsKey(currentClient.getPublicSID())) {
-						e.getValue().remove(currentClient.getPublicSID());
-					}
-					wbListManager.setWhiteBoardImagesSyncListByRoomAndObjectId(roomId, e.getKey(), e.getValue());
-				}
-
-				int numberOfImageLoaders = wbListManager.getWhiteBoardObjectSyncListByRoomid(roomId).size();
-
-				if (numberOfImageLoaders == 0 && scope != null) {
-					scopeAdapter.sendMessageToCurrentScope("" + roomId, "sendImagesSyncCompleteFlag", new Object[] { "remove" }, true);
-				}
-			}
-		} catch (Exception err) {
-			log.error("[removeUserFromAllLists]", err);
-		}
-	}
-
-	public Cliparts getClipArtIcons() {
-		try {
-			File clipart_dir = OmFileHelper.getPublicClipartsDir();
-
-			FilenameFilter getFilesOnly = new FilenameFilter() {
-				@Override
-				public boolean accept(File b, String name) {
-					File f = new File(b, name);
-					return !f.isDirectory();
-				}
-			};
-
-			FilenameFilter getDirectoriesOnly = new FilenameFilter() {
-				@Override
-				public boolean accept(File b, String name) {
-					File f = new File(b, name);
-					return f.isDirectory() && !f.getName().equals("thumb");
-				}
-			};
-
-			Cliparts cl = new Cliparts();
-			cl.setFolderName("general");
-
-			Comparator<String> comparator = ComparatorUtils.naturalComparator();
-			String[] files_general = clipart_dir.list(getFilesOnly);
-			if (files_general != null) {
-				Arrays.sort(files_general, comparator);
-				cl.setGeneralList(files_general);
-			}
-			cl.setSubCategories(new LinkedList<Cliparts>());
-
-			File[] dirs = clipart_dir.listFiles(getDirectoriesOnly);
-			if (dirs != null) {
-				for (File dir : dirs) {
-					Cliparts cl_sub = new Cliparts();
-					cl_sub.setFolderName("math");
-					String[] files = dir.list(getFilesOnly);
-					if (files != null) {
-						Arrays.sort(files, comparator);
-						cl_sub.setGeneralList(files);
-						cl.getSubCategories().add(cl_sub);
-					}
-				}
-			}
-
-			return cl;
-		} catch (Exception err) {
-			log.error("[getClipArtIcons]", err);
-		}
-		return null;
-	}
-
-	@Override
-	public void resultReceived(IPendingServiceCall arg0) {
-		log.debug("resultReceived: " + arg0);
-	}
-}

http://git-wip-us.apache.org/repos/asf/openmeetings/blob/a5d2b138/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/WhiteboardService.java
----------------------------------------------------------------------
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/WhiteboardService.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/WhiteboardService.java
new file mode 100644
index 0000000..7107100
--- /dev/null
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/WhiteboardService.java
@@ -0,0 +1,560 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.core.remote;
+
+import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_DEFAULT_LANG_KEY;
+import static org.apache.openmeetings.util.OpenmeetingsVariables.webAppRootKey;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+import org.apache.commons.collections4.ComparatorUtils;
+import org.apache.openmeetings.core.data.whiteboard.WhiteboardCache;
+import org.apache.openmeetings.core.data.whiteboard.WhiteboardObjectSyncManager;
+import org.apache.openmeetings.core.remote.red5.ScopeApplicationAdapter;
+import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
+import org.apache.openmeetings.db.dao.label.LabelDao;
+import org.apache.openmeetings.db.dao.server.ISessionManager;
+import org.apache.openmeetings.db.dao.server.SessiondataDao;
+import org.apache.openmeetings.db.dao.user.UserDao;
+import org.apache.openmeetings.db.dto.room.Cliparts;
+import org.apache.openmeetings.db.dto.room.Whiteboard;
+import org.apache.openmeetings.db.dto.room.WhiteboardSyncLockObject;
+import org.apache.openmeetings.db.dto.room.Whiteboards;
+import org.apache.openmeetings.db.entity.room.Client;
+import org.apache.openmeetings.db.entity.server.Sessiondata;
+import org.apache.openmeetings.db.entity.user.User;
+import org.apache.openmeetings.db.util.AuthLevelUtil;
+import org.apache.openmeetings.util.OmFileHelper;
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.IConnection;
+import org.red5.server.api.Red5;
+import org.red5.server.api.scope.IScope;
+import org.red5.server.api.service.IPendingServiceCall;
+import org.red5.server.api.service.IPendingServiceCallback;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ *
+ * @author sebastianwagner
+ *
+ */
+public class WhiteboardService implements IPendingServiceCallback {
+	private static final Logger log = Red5LoggerFactory.getLogger(WhiteboardService.class, webAppRootKey);
+	@Autowired
+	private UserDao userDao;
+	@Autowired
+	private ScopeApplicationAdapter scopeAdapter;
+	@Autowired
+	private ISessionManager sessionManager;
+	@Autowired
+	private WhiteboardObjectSyncManager wbListManager;
+	@Autowired
+	private WhiteboardCache wbCache;
+	@Autowired
+	private SessiondataDao sessionDao;
+	@Autowired
+	private LabelDao labelDao;
+	@Autowired
+	private ConfigurationDao cfgDao;
+
+	public boolean getNewWhiteboardId(String name) {
+		try {
+			IConnection current = Red5.getConnectionLocal();
+			String streamid = current.getClient().getId();
+			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
+			Long roomId = currentClient.getRoomId();
+
+			Long whiteBoardId = wbCache.getNewWhiteboardId(roomId, name);
+			scopeAdapter.sendMessageAll(Arrays.asList("newWhiteboard", whiteBoardId, name));
+		} catch (Exception e) {
+			log.error("[getNewWhiteboardId]", e);
+			return false;
+		}
+		return true;
+	}
+
+	public boolean deleteWhiteboard(Long whiteBoardId) {
+		try {
+			IConnection current = Red5.getConnectionLocal();
+			String streamid = current.getClient().getId();
+			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
+			Long roomId = currentClient.getRoomId();
+
+			Whiteboards whiteboards = wbCache.get(roomId);
+			Object returnValue = whiteboards.getWhiteboards().remove(whiteBoardId);
+
+			log.debug(" :: whiteBoardId :: " + whiteBoardId);
+
+			wbCache.set(roomId, whiteboards);
+
+			if (returnValue != null) {
+				return true;
+			}
+		} catch (Exception err) {
+			log.error("[deleteWhiteboard]", err);
+		}
+		return false;
+	}
+
+	public Map<Long, Whiteboard> getRoomItemsBy() {
+		Map<Long, Whiteboard> result = new LinkedHashMap<>();
+		try {
+			IConnection current = Red5.getConnectionLocal();
+			String streamid = current.getClient().getId();
+			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
+			Long roomId = currentClient.getRoomId();
+
+			log.debug("getRoomItems: " + roomId);
+			Whiteboards whiteboards = wbCache.get(roomId);
+
+			if (whiteboards.getWhiteboards().isEmpty()) {
+				Long langId = null;
+				{
+					Long userId = currentClient.getUserId();
+					if (userId != null && userId.longValue() < 0) {
+						userId = -userId;
+					}
+					User u = userDao.get(userId);
+					langId = u == null ? cfgDao.getConfValue(CONFIG_DEFAULT_LANG_KEY, Long.class, "1") : u.getLanguageId();
+				}
+				wbCache.getNewWhiteboardId(roomId, labelDao.getString("615", langId));
+				log.debug("Init New Room List");
+				whiteboards = wbCache.get(roomId);
+			}
+			whiteboards.getWhiteboards().entrySet().stream()
+					.sorted(Map.Entry.<Long, Whiteboard>comparingByKey().reversed())
+					.forEachOrdered(x -> result.put(x.getKey(), x.getValue()));
+		} catch (Exception err) {
+			log.error("[getRoomItemsBy]", err);
+		}
+		return result;
+	}
+
+	public boolean rename(Long wbId, String name) {
+		try {
+			IConnection current = Red5.getConnectionLocal();
+			String streamid = current.getClient().getId();
+			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
+			Long roomId = currentClient.getRoomId();
+
+			Whiteboards whiteboards = wbCache.get(roomId);
+			Whiteboard wb = whiteboards.getWhiteboards().get(wbId);
+			wb.setName(name);
+
+			log.debug(" :: rename whiteBoard :: id = {}, name = {}", wbId, name);
+			scopeAdapter.sendMessageAll(Arrays.asList("renameWhiteboard", wbId, name));
+		} catch (Exception err) {
+			log.error("[rename]", err);
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * change the draw status of a user, allow disallow him to draw anybody
+	 * besides the Moderator to draw on the whiteboard, only a Moderator is
+	 * allowed to trigger this function
+	 *
+	 * @param sid
+	 * @param publicSID
+	 * @param canDraw
+	 * @return null in case of success, false otherwise
+	 */
+	public boolean setCanDraw(String sid, String publicSID, boolean canDraw) {
+		try {
+			IConnection current = Red5.getConnectionLocal();
+			String streamid = current.getClient().getId();
+			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
+
+			Sessiondata sd = sessionDao.check(sid);
+			if (AuthLevelUtil.hasUserLevel(userDao.getRights(sd.getUserId()))) {
+				if (currentClient.getIsMod()) {
+					Client rcl = sessionManager.getClientByPublicSID(publicSID, null);
+
+					if (rcl != null) {
+						rcl.setCanDraw(canDraw);
+						sessionManager.updateClientByStreamId(rcl.getStreamid(), rcl, false, null);
+
+						Map<Integer, Object> newMessage = new HashMap<>();
+						newMessage.put(0, "updateDrawStatus");
+						newMessage.put(1, rcl);
+						scopeAdapter.sendMessageWithClientWithSyncObject(newMessage, true);
+						return true;
+					}
+				}
+			}
+		} catch (Exception err) {
+			log.error("[setCanDraw]", err);
+		}
+		return false;
+	}
+
+	public boolean setCanShare(String sid, String publicSID, boolean canShare) {
+		try {
+			IConnection current = Red5.getConnectionLocal();
+			String streamid = current.getClient().getId();
+			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
+
+			Sessiondata sd = sessionDao.check(sid);
+			if (AuthLevelUtil.hasUserLevel(userDao.getRights(sd.getUserId()))) {
+				if (currentClient.getIsMod()) {
+					Client rcl = sessionManager.getClientByPublicSID(publicSID, null);
+
+					if (rcl != null) {
+						rcl.setCanShare(canShare);
+						sessionManager.updateClientByStreamId(rcl.getStreamid(), rcl, false, null);
+
+						Map<Integer, Object> newMessage = new HashMap<>();
+						newMessage.put(0, "updateDrawStatus");
+						newMessage.put(1, rcl);
+						scopeAdapter.sendMessageWithClientWithSyncObject(newMessage, true);
+						return true;
+					}
+				}
+			}
+		} catch (Exception err) {
+			log.error("[setCanShare]", err);
+		}
+		return false;
+	}
+
+	public boolean setCanRemote(String sid, String publicSID, boolean canRemote) {
+		try {
+			IConnection current = Red5.getConnectionLocal();
+			String streamid = current.getClient().getId();
+			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
+
+			Sessiondata sd = sessionDao.check(sid);
+			if (AuthLevelUtil.hasUserLevel(userDao.getRights(sd.getUserId()))) {
+				if (currentClient.getIsMod()) {
+					Client rcl = sessionManager.getClientByPublicSID(publicSID, null);
+
+					if (rcl != null) {
+						rcl.setCanRemote(canRemote);
+						sessionManager.updateClientByStreamId(rcl.getStreamid(), rcl, false, null);
+
+						Map<Integer, Object> newMessage = new HashMap<>();
+						newMessage.put(0, "updateDrawStatus");
+						newMessage.put(1, rcl);
+						scopeAdapter.sendMessageWithClientWithSyncObject(newMessage, true);
+						return true;
+					}
+				}
+			}
+		} catch (Exception err) {
+			log.error("[setCanDraw]", err);
+		}
+		return false;
+	}
+
+	public boolean setCanGiveAudio(String sid, String publicSID, boolean canGiveAudio) {
+		try {
+			log.debug("[setCanGiveAudio] " + sid + ", " + publicSID + ", " + canGiveAudio);
+			IConnection current = Red5.getConnectionLocal();
+			String streamid = current.getClient().getId();
+			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
+
+			Sessiondata sd = sessionDao.check(sid);
+			if (AuthLevelUtil.hasUserLevel(userDao.getRights(sd.getUserId()))) {
+				if (currentClient.getIsMod()) {
+					Client rcl = sessionManager.getClientByPublicSID(publicSID, null);
+
+					if (rcl != null) {
+						rcl.setCanGiveAudio(canGiveAudio);
+						sessionManager.updateClientByStreamId(rcl.getStreamid(), rcl, false, null);
+
+						Map<Integer, Object> newMessage = new HashMap<>();
+						newMessage.put(0, "updateGiveAudioStatus");
+						newMessage.put(1, rcl);
+						scopeAdapter.sendMessageWithClientWithSyncObject(newMessage, true);
+						return true;
+					}
+				}
+			}
+		} catch (Exception err) {
+			log.error("[setCanGiveAudio]", err);
+		}
+		return false;
+	}
+
+	public WhiteboardSyncLockObject startNewSyncprocess() {
+		try {
+			IConnection current = Red5.getConnectionLocal();
+			String streamid = current.getClient().getId();
+			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
+			Long roomId = currentClient.getRoomId();
+
+			WhiteboardSyncLockObject wSyncLockObject = new WhiteboardSyncLockObject();
+			wSyncLockObject.setAddtime(new Date());
+			wSyncLockObject.setPublicSID(currentClient.getPublicSID());
+			wSyncLockObject.setInitialLoaded(true);
+
+			Map<String, WhiteboardSyncLockObject> syncListRoom = wbListManager.getWhiteBoardSyncListByRoomid(roomId);
+
+			wSyncLockObject.setCurrentLoadingItem(true);
+			wSyncLockObject.setInserted(new Date());
+
+			syncListRoom.put(currentClient.getPublicSID(), wSyncLockObject);
+			wbListManager.setWhiteBoardSyncListByRoomid(roomId, syncListRoom);
+
+			//Sync to clients
+			scopeAdapter.sendMessageToCurrentScope("sendSyncFlag", wSyncLockObject, true);
+
+			return wSyncLockObject;
+		} catch (Exception err) {
+			log.error("[startNewSyncprocess]", err);
+		}
+		return null;
+	}
+
+	public void sendCompletedSyncEvent() {
+		try {
+			IConnection current = Red5.getConnectionLocal();
+			String streamid = current.getClient().getId();
+			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
+			Long roomId = currentClient.getRoomId();
+
+			Map<String, WhiteboardSyncLockObject> syncListRoom = wbListManager.getWhiteBoardSyncListByRoomid(roomId);
+
+			WhiteboardSyncLockObject wSyncLockObject = syncListRoom.get(currentClient.getPublicSID());
+
+			if (wSyncLockObject == null) {
+				log.error("WhiteboardSyncLockObject not found for this Client "
+						+ syncListRoom);
+				return;
+			} else if (!wSyncLockObject.isCurrentLoadingItem()) {
+				log.warn("WhiteboardSyncLockObject was not started yet " + syncListRoom);
+				return;
+			} else {
+				syncListRoom.remove(currentClient.getPublicSID());
+				wbListManager.setWhiteBoardSyncListByRoomid(roomId, syncListRoom);
+
+				int numberOfInitial = getNumberOfInitialLoaders(syncListRoom);
+
+				if (numberOfInitial == 0) {
+					scopeAdapter.sendMessageToCurrentScope("sendSyncCompleteFlag", wSyncLockObject, true);
+				} else {
+					return;
+				}
+			}
+		} catch (Exception err) {
+			log.error("[sendCompletedSyncEvent]", err);
+		}
+		return;
+	}
+
+	private static int getNumberOfInitialLoaders(Map<String, WhiteboardSyncLockObject> syncListRoom) {
+		int number = 0;
+		for (Map.Entry<String, WhiteboardSyncLockObject> e : syncListRoom.entrySet()) {
+			if (e.getValue().isInitialLoaded()) {
+				number++;
+			}
+		}
+		return number;
+	}
+
+	/*
+	 * Image Sync Sequence
+	 */
+
+	public void startNewObjectSyncProcess(String objectId, boolean isStarting) {
+		try {
+			log.debug("startNewObjectSyncprocess: " + objectId);
+
+			IConnection current = Red5.getConnectionLocal();
+			String streamid = current.getClient().getId();
+			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
+			Long roomId = currentClient.getRoomId();
+
+			WhiteboardSyncLockObject wSyncLockObject = new WhiteboardSyncLockObject();
+			wSyncLockObject.setAddtime(new Date());
+			wSyncLockObject.setPublicSID(currentClient.getPublicSID());
+			wSyncLockObject.setInserted(new Date());
+
+			Map<String, WhiteboardSyncLockObject> syncListImage = wbListManager.getWhiteBoardObjectSyncListByRoomAndObjectId(roomId, objectId);
+			syncListImage.put(currentClient.getPublicSID(), wSyncLockObject);
+			wbListManager.setWhiteBoardImagesSyncListByRoomAndObjectId(roomId, objectId, syncListImage);
+
+			// Do only send the Token to show the Loading Splash for the
+			// initial-Request that starts the loading
+			if (isStarting) {
+				scopeAdapter.sendMessageToCurrentScope("sendObjectSyncFlag", wSyncLockObject, true);
+			}
+		} catch (Exception err) {
+			log.error("[startNewObjectSyncProcess]", err);
+		}
+	}
+
+	public int sendCompletedObjectSyncEvent(String objectId) {
+		try {
+			log.debug("sendCompletedObjectSyncEvent: " + objectId);
+
+			IConnection current = Red5.getConnectionLocal();
+			String streamid = current.getClient().getId();
+			Client currentClient = sessionManager.getClientByStreamId(streamid, null);
+			Long roomId = currentClient.getRoomId();
+
+			Map<String, WhiteboardSyncLockObject> syncListImage = wbListManager.getWhiteBoardObjectSyncListByRoomAndObjectId(roomId, objectId);
+
+			log.debug("sendCompletedObjectSyncEvent syncListImage: " + syncListImage);
+
+			WhiteboardSyncLockObject wSyncLockObject = syncListImage.get(currentClient.getPublicSID());
+
+			if (wSyncLockObject == null) {
+				log.error("WhiteboardSyncLockObject not found for this Client " + currentClient.getPublicSID());
+				log.error("WhiteboardSyncLockObject not found for this syncListImage " + syncListImage);
+				return -2;
+			} else {
+				log.debug("sendCompletedImagesSyncEvent remove: " + currentClient.getPublicSID());
+
+				syncListImage.remove(currentClient.getPublicSID());
+				wbListManager.setWhiteBoardImagesSyncListByRoomAndObjectId(roomId, objectId, syncListImage);
+
+				int numberOfInitial = wbListManager.getWhiteBoardObjectSyncListByRoomid(roomId).size();
+
+				log.debug("sendCompletedImagesSyncEvent numberOfInitial: " + numberOfInitial);
+
+				if (numberOfInitial == 0) {
+					scopeAdapter.sendMessageToCurrentScope("sendObjectSyncCompleteFlag", wSyncLockObject, true);
+					return 1;
+				} else {
+					return -4;
+				}
+			}
+		} catch (Exception err) {
+			log.error("[sendCompletedObjectSyncEvent]", err);
+		}
+		return -1;
+	}
+
+	public synchronized void removeUserFromAllLists(IScope scope, Client currentClient) {
+		try {
+			Long roomId = currentClient.getRoomId();
+
+			// TODO: Maybe we should also check all rooms, independent from the
+			// current roomId if there is any user registered
+			if (roomId != null) {
+				log.debug("removeUserFromAllLists this.whiteBoardObjectListManager: " + wbListManager);
+				log.debug("removeUserFromAllLists roomId: " + roomId);
+
+				// Check Initial Loaders
+				Map<String, WhiteboardSyncLockObject> syncListRoom = wbListManager.getWhiteBoardSyncListByRoomid(roomId);
+
+				WhiteboardSyncLockObject wSyncLockObject = syncListRoom.get(currentClient.getPublicSID());
+
+				if (wSyncLockObject != null) {
+					syncListRoom.remove(currentClient.getPublicSID());
+				}
+				wbListManager.setWhiteBoardSyncListByRoomid(roomId, syncListRoom);
+
+				int numberOfInitial = getNumberOfInitialLoaders(syncListRoom);
+
+				log.debug("scope " + scope);
+
+				if (numberOfInitial == 0 && scope != null) {
+					scopeAdapter.sendMessageToCurrentScope("" + roomId, "sendSyncCompleteFlag", wSyncLockObject, false);
+				}
+
+				// Check Image Loaders
+				Map<String, Map<String, WhiteboardSyncLockObject>> syncListRoomImages = wbListManager.getWhiteBoardObjectSyncListByRoomid(roomId);
+
+				for (Map.Entry<String, Map<String, WhiteboardSyncLockObject>> e : syncListRoomImages.entrySet()) {
+					if (e.getValue().containsKey(currentClient.getPublicSID())) {
+						e.getValue().remove(currentClient.getPublicSID());
+					}
+					wbListManager.setWhiteBoardImagesSyncListByRoomAndObjectId(roomId, e.getKey(), e.getValue());
+				}
+
+				int numberOfImageLoaders = wbListManager.getWhiteBoardObjectSyncListByRoomid(roomId).size();
+
+				if (numberOfImageLoaders == 0 && scope != null) {
+					scopeAdapter.sendMessageToCurrentScope("" + roomId, "sendImagesSyncCompleteFlag", new Object[] { "remove" }, true);
+				}
+			}
+		} catch (Exception err) {
+			log.error("[removeUserFromAllLists]", err);
+		}
+	}
+
+	public Cliparts getClipArtIcons() {
+		try {
+			File clipart_dir = OmFileHelper.getPublicClipartsDir();
+
+			FilenameFilter getFilesOnly = new FilenameFilter() {
+				@Override
+				public boolean accept(File b, String name) {
+					File f = new File(b, name);
+					return !f.isDirectory();
+				}
+			};
+
+			FilenameFilter getDirectoriesOnly = new FilenameFilter() {
+				@Override
+				public boolean accept(File b, String name) {
+					File f = new File(b, name);
+					return f.isDirectory() && !f.getName().equals("thumb");
+				}
+			};
+
+			Cliparts cl = new Cliparts();
+			cl.setFolderName("general");
+
+			Comparator<String> comparator = ComparatorUtils.naturalComparator();
+			String[] files_general = clipart_dir.list(getFilesOnly);
+			if (files_general != null) {
+				Arrays.sort(files_general, comparator);
+				cl.setGeneralList(files_general);
+			}
+			cl.setSubCategories(new LinkedList<Cliparts>());
+
+			File[] dirs = clipart_dir.listFiles(getDirectoriesOnly);
+			if (dirs != null) {
+				for (File dir : dirs) {
+					Cliparts cl_sub = new Cliparts();
+					cl_sub.setFolderName("math");
+					String[] files = dir.list(getFilesOnly);
+					if (files != null) {
+						Arrays.sort(files, comparator);
+						cl_sub.setGeneralList(files);
+						cl.getSubCategories().add(cl_sub);
+					}
+				}
+			}
+
+			return cl;
+		} catch (Exception err) {
+			log.error("[getClipArtIcons]", err);
+		}
+		return null;
+	}
+
+	@Override
+	public void resultReceived(IPendingServiceCall arg0) {
+		log.debug("resultReceived: " + arg0);
+	}
+}

http://git-wip-us.apache.org/repos/asf/openmeetings/blob/a5d2b138/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/red5/ScopeApplicationAdapter.java
----------------------------------------------------------------------
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/red5/ScopeApplicationAdapter.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/red5/ScopeApplicationAdapter.java
index 16a6a4c..c854997 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/red5/ScopeApplicationAdapter.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/red5/ScopeApplicationAdapter.java
@@ -18,9 +18,11 @@
  */
 package org.apache.openmeetings.core.remote.red5;
 
+import static org.apache.openmeetings.util.OmFileHelper.EXTENSION_MP4;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.webAppRootKey;
 
 import java.awt.Point;
+import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
@@ -34,11 +36,13 @@ import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicLong;
 
+import org.apache.commons.io.FileUtils;
 import org.apache.openmeetings.IApplication;
 import org.apache.openmeetings.core.data.conference.RoomManager;
+import org.apache.openmeetings.core.data.whiteboard.WhiteboardCache;
 import org.apache.openmeetings.core.data.whiteboard.WhiteboardManager;
 import org.apache.openmeetings.core.remote.RecordingService;
-import org.apache.openmeetings.core.remote.WhiteBoardService;
+import org.apache.openmeetings.core.remote.WhiteboardService;
 import org.apache.openmeetings.core.remote.util.SessionVariablesUtil;
 import org.apache.openmeetings.core.util.WebSocketHelper;
 import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
@@ -99,9 +103,11 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 	@Autowired
 	private ISessionManager sessionManager;
 	@Autowired
-	private WhiteBoardService whiteBoardService;
+	private WhiteboardService whiteBoardService;
 	@Autowired
-	private WhiteboardManager whiteboardManagement;
+	private WhiteboardManager whiteboardManager;
+	@Autowired
+	private WhiteboardCache whiteboardCache;
 	@Autowired
 	private RecordingService recordingService;
 	@Autowired
@@ -1160,7 +1166,6 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 	}
 
 	private static List<?> getWbObject(FileItem fi, String url) {
-		String fuid = UUID.randomUUID().toString();
 		Point size = getSize(fi);
 		String type = "n/a";
 		switch (fi.getType()) {
@@ -1190,7 +1195,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 				, size.x // initwidth //14
 				, size.y // initheight //15
 				, 100 // currentzoom //16 FIXME TODO
-				, fuid // uniquObjectSyncName //17
+				, fi.getHash() // uniquObjectSyncName //17
 				, fi.getName() // standardFileName //18
 				, true // fullFit //19 FIXME TODO
 				, 0 // zIndex //-8
@@ -1200,18 +1205,17 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 				, 0 // posy //-4
 				, size.x // width //-3
 				, size.y // height //-2
-				, fuid // this.currentlayer.name //-1
+				, fi.getHash() // this.currentlayer.name //-1
 				);
 	}
 
-	private static List<?> getFlvWbObject(FileItem fi) {
-		String fuid = UUID.randomUUID().toString();
+	private static List<?> getMp4WbObject(FileItem fi, String url) {
 		Point size = getSize(fi);
 		return Arrays.asList(
 				"flv" // 0: 'flv'
 				, fi.getId() // 1: 7
 				, fi.getName() // 2: 'BigBuckBunny_512kb.mp4'
-				, false // 3: false //playRemote
+				, url // 3: posterUrl
 				, size.x // 4: 416
 				, size.y // 5: 240
 				, 0 // 6: 1 // z-index
@@ -1221,10 +1225,27 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 				, 0 // 10: 0 //TODO // y
 				, size.x // 11: 749 // width
 				, size.y // 12: 739 // height
-				, fuid // 13: 'flv_1469602000351'
+				, fi.getHash() // 13: 'flv_1469602000351'
 				);
 	}
 
+	private static void copyFileToRoom(Long roomId, FileItem f) {
+		try {
+			if (roomId != null && f != null) {
+				File mp4 = f.getFile(EXTENSION_MP4);
+
+				File targetFolder = OmFileHelper.getStreamsSubDir(roomId);
+
+				File target = new File(targetFolder, mp4.getName());
+				if (mp4.exists() && !target.exists()) {
+					FileUtils.copyFile(mp4, target, false);
+				}
+			}
+		} catch (Exception err) {
+			log.error("[copyFileToCurrentRoom] ", err);
+		}
+	}
+
 	public void sendToWhiteboard(String uid, Long wbId, FileItem fi, String url, boolean clean) {
 		ClientSessionInfo csi = sessionManager.getClientByPublicSIDAnyServer(uid);
 		if (csi == null) {
@@ -1242,7 +1263,9 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 				wbObject = getWbObject(fi, url);
 				break;
 			case Video:
-				wbObject = getFlvWbObject(fi);
+			case Recording:
+				wbObject = getMp4WbObject(fi, url);
+				copyFileToRoom(client.getRoomId(), fi);
 				break;
 			default:
 		}
@@ -1251,6 +1274,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 			wbClear.put("id", wbId);
 			wbClear.put("param", Arrays.asList("whiteboard", new Date(), "clear", null));
 
+			whiteboardCache.get(client.getRoomId(), wbId).clear();
 			sendToScope(client.getRoomId(), "sendVarsToWhiteboardById", Arrays.asList(null, wbClear));
 		}
 		sendToWhiteboard(client, Arrays.asList("whiteboard", new Date(), "draw", wbObject), wbId);
@@ -1300,10 +1324,10 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 
 					whiteboardTempObj.put(3, tempActionObject);
 
-					whiteboardManagement.addWhiteBoardObjectById(roomId, whiteboardTempObj, wbId);
+					whiteboardManager.add(roomId, whiteboardTempObj, wbId);
 				}
 			} else {
-				whiteboardManagement.addWhiteBoardObjectById(roomId, whiteboardObj, wbId);
+				whiteboardManager.add(roomId, whiteboardObj, wbId);
 			}
 
 			Map<String, Object> sendObject = new HashMap<>();

http://git-wip-us.apache.org/repos/asf/openmeetings/blob/a5d2b138/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/room/Whiteboard.java
----------------------------------------------------------------------
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/room/Whiteboard.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/room/Whiteboard.java
new file mode 100644
index 0000000..0cfe6d5
--- /dev/null
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/room/Whiteboard.java
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.db.dto.room;
+
+import static org.apache.openmeetings.util.OpenmeetingsVariables.webAppRootKey;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+
+public class Whiteboard {
+	private static final Logger log = Red5LoggerFactory.getLogger(Whiteboard.class, webAppRootKey);
+	private long whiteBoardId;
+	private Integer x = 0;
+	private Integer y = 0;
+	private Integer zoom = 100;
+	private Boolean fullFit = true;
+	private Map<String, List<Object>> roomItems = new ConcurrentHashMap<>();
+	private Date created = new Date();
+	private int zIndex = 1;
+	private String name;
+
+	public Whiteboard() {}
+
+	public Whiteboard(String name) {
+		this.name = name;
+	}
+
+	public long getWhiteBoardId() {
+		return whiteBoardId;
+	}
+
+	public void setWhiteBoardId(long whiteBoardId) {
+		this.whiteBoardId = whiteBoardId;
+	}
+
+	public Integer getX() {
+		return x;
+	}
+
+	public void setX(Integer x) {
+		this.x = x;
+	}
+
+	public Integer getY() {
+		return y;
+	}
+
+	public void setY(Integer y) {
+		this.y = y;
+	}
+
+	public Date getCreated() {
+		return created;
+	}
+
+	public void setCreated(Date created) {
+		this.created = created;
+	}
+
+	public Integer getZoom() {
+		return zoom;
+	}
+
+	public void setZoom(Integer zoom) {
+		this.zoom = zoom;
+	}
+
+	public Boolean getFullFit() {
+		return fullFit;
+	}
+
+	public void setFullFit(Boolean fullFit) {
+		this.fullFit = fullFit;
+	}
+
+	public void clear() {
+		roomItems.clear();
+		zIndex = 1;
+	}
+
+	//getter is required, otherwise roomItems are not available in red5
+	public Map<String, List<Object>> getRoomItems() {
+		return roomItems;
+	}
+
+	public void add(String oid, List<Object> actionObject) {
+		Object type = actionObject.size() > 0 ? actionObject.get(0) : "";
+		if (actionObject.size() > 8 && ("swf".equals(type) || "image".equals(type) || "flv".equals(type))) {
+			Integer zInd = (Integer)actionObject.get(actionObject.size() - 8);
+			if (zInd == null || zInd == 0 || zInd < zIndex) {
+				actionObject.set(actionObject.size() - 8, zIndex++);
+			}
+		}
+		roomItems.put(oid, actionObject);
+	}
+
+	public List<Object> get(String oid) {
+		return roomItems.get(oid);
+	}
+
+	public Set<Entry<String, List<Object>>> entrySet() {
+		return roomItems.entrySet();
+	}
+
+	public void remove(Object oid) {
+		roomItems.remove(oid);
+	}
+
+	public void remove(List<Object> actionObject) {
+		String oid = actionObject.get(actionObject.size() - 1).toString();
+		String type = actionObject.get(0).toString();
+		log.debug("Removal of object: oid = {}, type = {} ", oid, type);
+
+		/* I believe this is redundant
+		// Re-Index all items in its zIndex
+		if (type.equals("ellipse")
+				|| type.equals("drawarrow")
+				|| type.equals("line")
+				|| type.equals("paint")
+				|| type.equals("rectangle")
+				|| type.equals("uline")
+				|| type.equals("image")
+				|| type.equals("letter")
+				|| type.equals("clipart")
+				|| type.equals("swf")
+				|| type.equals("mindmapnode")
+				|| type.equals("flv")) {
+
+			Integer zIndex = Integer.valueOf(actionObject.get(actionObject.size() - 8).toString());
+
+			log.debug("1|zIndex " + zIndex);
+			log.debug("2|zIndex " + actionObject.get(actionObject.size() - 8).toString());
+			log.debug("3|zIndex " + actionObject.get(actionObject.size() - 8));
+
+			int l = 0;
+			for (Object o : actionObject) {
+				log.debug("4|zIndex " + l + " -- " + o);
+				l++;
+			}
+
+			for (Entry<String, List<Object>> e : roomItems.entrySet()) {
+				List<Object> actionObjectStored = e.getValue();
+
+				Integer zIndexStored = Integer.valueOf(actionObjectStored.get(actionObjectStored.size() - 8).toString());
+
+				log.debug("zIndexStored|zIndex " + zIndexStored + "|" + zIndex);
+
+				if (zIndexStored >= zIndex) {
+					zIndexStored -= 1;
+					log.debug("new-zIndex " + zIndexStored);
+				}
+				actionObjectStored.set(actionObjectStored.size() - 8, zIndexStored);
+			}
+		}
+		*/
+		roomItems.remove(oid);
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}