Merge branch 'master_14.3.1-4' into asm_14.3.1

Conflicts:
	cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/ui/rsc/FFMPResource.java
	edexOsgi/com.raytheon.uf.edex.grid.staticdata/src/com/raytheon/uf/edex/grid/staticdata/StaticDataGenerator.java
	edexOsgi/com.raytheon.uf.edex.plugin.grid/utility/common_static/base/purge/gridPurgeRules.xml

Former-commit-id: 52358cb3e2ba2c7ff4ff9c9a5de03af50c3a1199
This commit is contained in:
brian.dyke 2014-05-19 09:45:37 -04:00
commit 011d121e4b
1313 changed files with 24160 additions and 40597 deletions

View file

@ -70,34 +70,6 @@
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.ecf"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.ecf.filetransfer"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.ecf.provider.filetransfer"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.ecf.identity"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.equinox.p2.touchpoint.eclipse"
download-size="0"
@ -237,11 +209,4 @@
version="0.0.0"
unpack="false"/>
<plugin
id="org.hamcrest.core"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
</feature>

View file

@ -40,7 +40,6 @@
id="org.apache.commons.compress"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
version="0.0.0"/>
</feature>

View file

@ -30,6 +30,14 @@
recursive="false"
extensionFilter=".xml">
</path>
<path
application="Archive"
localizationType="COMMON_STATIC"
name="gui"
value="archiver/gui"
recursive="false"
extensionFilter=".xml">
</path>
</extension>
<extension
point="org.eclipse.ui.menus">

View file

@ -17,25 +17,28 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.edex.uengine;
package com.raytheon.uf.viz.archive.data;
/**
* Activator for uEngine component
* A listener to notify when SizeJob has obtain all display data.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 8, 2008 njensen Initial creation
* Apr 23, 2014 3045 rferrel Initial creation
*
* </pre>
*
* @author njensen
* @author rferrel
* @version 1.0
*/
public class Activator {
public static final String PLUGIN_ID = "com.raytheon.edex.uengine";
public interface ILoadDisplayDataListener {
/**
* Called by SizeJob after obtaining all display data for all
* archive/category tables.
*/
public void loadedAllDisplayData();
}

View file

@ -52,6 +52,7 @@ import com.raytheon.uf.common.time.util.TimeUtil;
* Dec 11, 2013 #2603 rferrel Selected list changed to a Set.
* Dec 11, 2013 #2624 rferrel Clear display variables when recomputing sizes.
* Mar 27, 2014 #2879 rferrel Loading Case no longer changes Start/End times.
* Apr 23, 2014 #3045 rferrel Changes to prevent race condition while getting labels.
*
* </pre>
*
@ -156,17 +157,17 @@ public class SizeJob extends Job {
private boolean stopComputeSize;
/**
* Priority queue for getting display data for an archive/category.
* Priority queue for getting display data all archive/category tables.
*/
// Do not use a PriorityBlockingQueue since the load select and change
// display methods need to be notified when the display data is available.
private final PriorityQueue<MissingData> missingDataQueue = new PriorityQueue<SizeJob.MissingData>(
DEFAULT_INITIAL_CAPACITY, new Comparator<MissingData>() {
private final PriorityQueue<LoadDisplayData> loadDisplayDataQueue = new PriorityQueue<SizeJob.LoadDisplayData>(
DEFAULT_INITIAL_CAPACITY, new Comparator<LoadDisplayData>() {
@Override
public int compare(MissingData o1, MissingData o2) {
if (o1.visiable != o2.visiable) {
return o1.visiable ? -1 : +1;
public int compare(LoadDisplayData o1, LoadDisplayData o2) {
if (o1.visible != o2.visible) {
return o1.visible ? -1 : +1;
}
if (o1.isSelected() != o2.isSelected()) {
return o1.isSelected() ? -1 : +1;
@ -182,16 +183,22 @@ public class SizeJob extends Job {
});
/**
* Job for processing the missing data queue.
* Job for obtaining display data for all the archive/category tables.
*/
private final MissingDataJob missingDataJob = new MissingDataJob();
private LoadDisplayDataJob loadDisplayDataJob;
/**
* Listener to invoke when all display data loaded.
*/
private final ILoadDisplayDataListener loadDisplayDataListener;
/**
* Constructor.
*/
public SizeJob() {
public SizeJob(ILoadDisplayDataListener loadDisplayDataListener) {
super("Size Job");
setSystem(true);
this.loadDisplayDataListener = loadDisplayDataListener;
}
/**
@ -285,9 +292,11 @@ public class SizeJob extends Job {
* Check all displayData selection state so only the data in selections are
* set.
*
* @param selections
* @param selectName
* @param type
* @return errorMessage when unable to load else null
*/
public void loadSelect(String selectName, ArchiveConstants.Type type) {
public String loadSelect(String selectName, ArchiveConstants.Type type) {
ArchiveConfigManager manager = ArchiveConfigManager.getInstance();
String fileName = ArchiveConstants.selectFileName(type, selectName);
SelectConfig selections = manager.loadSelection(fileName);
@ -301,24 +310,18 @@ public class SizeJob extends Job {
for (String categoryName : archiveInfo.getCategoryNames()) {
Set<String> selectionsSet = selections.getSelectedSet(
archiveName, categoryName);
MissingData missingData = removeMissingData(archiveName,
categoryName);
if (missingData != null) {
missingData.setSelectedSet(selectionsSet);
addMissingData(missingData);
} else {
CategoryInfo categoryInfo = archiveInfo.get(categoryName);
for (DisplayData displayData : categoryInfo
.getDisplayDataList()) {
String displayLabel = displayData.getDisplayLabel();
boolean selected = selectionsSet.contains(displayLabel);
if (selected != displayData.isSelected()) {
setSelect(displayData, selected);
}
CategoryInfo categoryInfo = archiveInfo.get(categoryName);
for (DisplayData displayData : categoryInfo
.getDisplayDataList()) {
String displayLabel = displayData.getDisplayLabel();
boolean selected = selectionsSet.contains(displayLabel);
if (selected != displayData.isSelected()) {
setSelect(displayData, selected);
}
}
}
}
return null;
}
/**
@ -327,10 +330,13 @@ public class SizeJob extends Job {
* @return selected
*/
public List<DisplayData> getSelectAll() {
synchronized (missingDataQueue) {
while (!missingDataQueue.isEmpty()) {
if (missingDataJob.currentMissingData == null
|| missingDataJob.currentMissingData.isSelected()) {
synchronized (loadDisplayDataQueue) {
while (!loadDisplayDataQueue.isEmpty()) {
if ((loadDisplayDataJob.currentLoadDisplayData == null)
|| loadDisplayDataJob.currentLoadDisplayData
.isVisible()
|| loadDisplayDataJob.currentLoadDisplayData
.isSelected()) {
missingDataQueueWait();
} else {
break;
@ -440,33 +446,81 @@ public class SizeJob extends Job {
}
/**
* Change the archive/category display.
*
* @param archiveName
* - non null value
* @param categoryName
* @return displayData when display needs to change otherwise null
* - non null value
* @return true if archiveName and categoryName match the current display
*/
public boolean isCurrentDisplay(String archiveName, String categoryName) {
return archiveName.equals(displayArchive)
&& categoryName.equals(displayCategory);
}
/**
* This method returns a display data list to replace the contents of the
* GUI's achive/category display table or a null list if no update is
* needed. It is assumed this method is called from an non-UI thread.
*
* @param archiveName
* - archive for the new display table
* @param categoryName
* - category for the new display table
* @param shutdown
* - Becomes true when user requests a different table while this
* is waiting for data.
* @return displayData
*/
public List<DisplayData> changeDisplay(String archiveName,
String categoryName) {
String categoryName, AtomicBoolean shutdown) {
List<DisplayData> displayDatas = null;
// Only get data when the display really needs to be changed.
if (!archiveName.equals(displayArchive)
|| !categoryName.equals(displayCategory)) {
MissingData missingData = removeMissingData(archiveName,
// Update visible status of current display.
if ((displayArchive != null) && (displayCategory != null)) {
LoadDisplayData currentMissingData = removeLoadDisplayData(
displayArchive, displayCategory);
if (currentMissingData != null) {
currentMissingData.setVisible(false);
addLoadDisplayData(currentMissingData);
}
}
LoadDisplayData missingData = removeLoadDisplayData(archiveName,
categoryName);
displayArchive = archiveName;
displayCategory = categoryName;
// Update visible status of the new current display.
if (missingData != null) {
missingData.setVisiable(true);
synchronized (missingDataQueue) {
addMissingData(missingData);
while (missingDataQueue.contains(missingData)) {
missingDataQueueWait();
synchronized (loadDisplayDataQueue) {
missingData.setVisible(true);
addLoadDisplayData(missingData);
/*
* Wait for the display data to be loaded or no longer
* needed.
*/
while (loadDisplayDataJob.processing(missingData)
&& !shutdown.get()) {
missingDataQueueWait(500L);
}
}
}
displayDatas = archiveInfoMap.get(archiveName).get(categoryName)
.getDisplayDataList();
displayArchive = archiveName;
displayCategory = categoryName;
changeDisplay(displayDatas);
/*
* If user still needs the data update status of old visible data
* and the new visible data.
*/
if (!shutdown.get()) {
displayDatas = archiveInfoMap.get(archiveName)
.get(categoryName).getDisplayDataList();
changeDisplay(displayDatas);
}
}
return displayDatas;
}
@ -474,7 +528,7 @@ public class SizeJob extends Job {
/**
* Change to display all selected data..
*
* @return displayhData when display needs to change otherwise null.
* @return displayData when display needs to change otherwise null.
*/
public List<DisplayData> changeDisplayAll() {
List<DisplayData> selectedData = null;
@ -499,7 +553,7 @@ public class SizeJob extends Job {
}
iRetentionHour.setRetentionTimes(selections.getStarRetentionHours());
missingDataQueue.clear();
loadDisplayDataQueue.clear();
visibleList = manager.getDisplayData(displayArchive, displayCategory,
false);
@ -527,51 +581,48 @@ public class SizeJob extends Job {
} else {
selectedSet = selections.getSelectedSet(archiveName,
categoryName);
MissingData missingData = new MissingData(archiveName,
categoryName, selectedSet);
missingDataQueue.add(missingData);
LoadDisplayData missingData = new LoadDisplayData(
archiveName, categoryName, selectedSet);
loadDisplayDataQueue.add(missingData);
}
}
put(archiveName, archiveInfo);
}
missingDataJob.schedule();
loadDisplayDataJob = new LoadDisplayDataJob(loadDisplayDataListener,
loadDisplayDataQueue.size());
loadDisplayDataJob.schedule();
return selections.getName();
}
/**
* Find and remove the missing data from the missing data queue.
* Find and remove the associated load display data from the queue.
*
* @param archiveName
* @param categoryName
* @return missingData or null if not on the missing data queue
* @return loadDisplayData or null if no longer on the queue
*/
private MissingData removeMissingData(String archiveName,
private LoadDisplayData removeLoadDisplayData(String archiveName,
String categoryName) {
MissingData missingData = null;
synchronized (missingDataQueue) {
if (missingDataJob.currentMissingData != null
&& archiveName
.equals(missingDataJob.currentMissingData.archive)
&& categoryName
.equals(missingDataJob.currentMissingData.category)) {
// Finish the process of getting the data.
missingDataQueueWait();
} else if (!missingDataQueue.isEmpty()) {
Iterator<MissingData> iterator = missingDataQueue.iterator();
LoadDisplayData loadDisplayData = null;
synchronized (loadDisplayDataQueue) {
if (!loadDisplayDataQueue.isEmpty()) {
Iterator<LoadDisplayData> iterator = loadDisplayDataQueue
.iterator();
while (iterator.hasNext()) {
MissingData md = iterator.next();
LoadDisplayData md = iterator.next();
if (md.archive.equals(archiveName)
&& md.category.equals(categoryName)) {
iterator.remove();
missingData = md;
loadDisplayData = md;
break;
}
}
}
}
return missingData;
return loadDisplayData;
}
/**
@ -580,9 +631,20 @@ public class SizeJob extends Job {
* @return false when interrupted exception
*/
private boolean missingDataQueueWait() {
return missingDataQueueWait(0L);
}
/**
* Wait for notification that the current missing data is finished
* processing or the desired time has lapsed.
*
* @param time
* @return false when interrupted exception
*/
private boolean missingDataQueueWait(long time) {
boolean state = true;
try {
missingDataQueue.wait();
loadDisplayDataQueue.wait(time);
} catch (InterruptedException e) {
state = false;
statusHandler.handle(Priority.INFO, e.getLocalizedMessage(), e);
@ -591,32 +653,30 @@ public class SizeJob extends Job {
}
/**
* This inserts a load display data onto the queue. Should
*
* @param missingData
* @param loadDisplayData
*/
private void addMissingData(MissingData missingData) {
synchronized (missingDataQueue) {
missingDataQueue.add(missingData);
if (missingDataJob.getState() == Job.NONE) {
missingDataJob.schedule();
private void addLoadDisplayData(LoadDisplayData loadDisplayData) {
synchronized (loadDisplayDataQueue) {
loadDisplayDataQueue.add(loadDisplayData);
if (loadDisplayDataJob.getState() == Job.NONE) {
loadDisplayDataJob.schedule();
}
}
}
/**
* Change update visible to the new list.
* Change visible status to reflect the new list.
*
* @param newDisplays
*/
private void changeDisplay(List<DisplayData> newDisplays) {
List<DisplayData> oldDisplays = visibleList;
visibleList = newDisplays;
List<DisplayData> visibleList = new ArrayList<DisplayData>(newDisplays);
for (DisplayData displayData : oldDisplays) {
if (!visibleList.remove(displayData)) {
setVisible(displayData, false);
}
setVisible(displayData, false);
}
for (DisplayData displayData : visibleList) {
@ -761,25 +821,25 @@ public class SizeJob extends Job {
@Override
protected void canceling() {
clearQueue();
missingDataQueue.clear();
missingDataJob.cancel();
loadDisplayDataQueue.clear();
loadDisplayDataJob.cancel();
shutdown.set(true);
}
/**
* Class used by the missing data job to obtain display data for given
* archive/category off the UI thread.
* Class used to track missing display data for the archive/category tables.
* Allowing the information to be retrieved in a non-UI thread.
*/
private static class MissingData {
private static class LoadDisplayData {
protected final String archive;
protected final String category;
protected final Set<String> selectedSet;
protected boolean visiable = false;
protected boolean visible = false;
public MissingData(String archive, String category,
public LoadDisplayData(String archive, String category,
Set<String> selectedSet) {
this.archive = archive;
this.category = category;
@ -790,21 +850,20 @@ public class SizeJob extends Job {
return !selectedSet.isEmpty();
}
public void setVisiable(boolean state) {
this.visiable = state;
public boolean isVisible() {
return visible;
}
public void setSelectedSet(Set<String> selectedSet) {
this.selectedSet.clear();
this.selectedSet.addAll(selectedSet);
public void setVisible(boolean state) {
this.visible = state;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("MissingData[");
StringBuilder sb = new StringBuilder("LoadDisplayData[");
sb.append("archive: ").append(archive);
sb.append(", category: ").append(category);
sb.append(", visible: ").append(visiable);
sb.append(", visible: ").append(isVisible());
sb.append(", isSelected: ").append(isSelected());
sb.append("]");
return sb.toString();
@ -815,14 +874,34 @@ public class SizeJob extends Job {
* This handles getting the display data in the missing data queue and
* queuing the results for the size job.
*/
private class MissingDataJob extends Job {
private class LoadDisplayDataJob extends Job {
private final AtomicBoolean shutdown = new AtomicBoolean(false);
protected MissingData currentMissingData = null;
protected LoadDisplayData currentLoadDisplayData = null;
public MissingDataJob() {
super("MissingData");
private final ILoadDisplayDataListener loadDisplayDataListener;
/**
* Must be set to the maximum number of LoadDisplayData to process.
* Cannot use the queue size since adjusting the queue to change the
* priority may make its size 0. This could cause the job to be
* rescheduled to finish when data added back onto the queue.
*/
private int loadDisplayDataCnt;
/**
* The constructor.
*
* @param loadDisplayDataListener
* @param loadDisplayDataCnt
*/
public LoadDisplayDataJob(
ILoadDisplayDataListener loadDisplayDataListener,
int loadDisplayDataCnt) {
super("Loading Data Sets");
this.loadDisplayDataListener = loadDisplayDataListener;
this.loadDisplayDataCnt = loadDisplayDataCnt;
}
@Override
@ -834,20 +913,21 @@ public class SizeJob extends Job {
ArchiveConfigManager manager = ArchiveConfigManager.getInstance();
while (!shutdown.get()) {
synchronized (missingDataQueue) {
if (currentMissingData != null) {
missingDataQueue.notifyAll();
synchronized (loadDisplayDataQueue) {
if (currentLoadDisplayData != null) {
currentLoadDisplayData = null;
loadDisplayDataQueue.notifyAll();
--loadDisplayDataCnt;
}
currentLoadDisplayData = loadDisplayDataQueue.poll();
if (currentLoadDisplayData == null) {
break;
}
currentMissingData = missingDataQueue.poll();
}
if (currentMissingData == null) {
break;
}
String archiveName = currentMissingData.archive;
String categoryName = currentMissingData.category;
Set<String> selectedSet = currentMissingData.selectedSet;
String archiveName = currentLoadDisplayData.archive;
String categoryName = currentLoadDisplayData.category;
Set<String> selectedSet = currentLoadDisplayData.selectedSet;
List<DisplayData> displayDatas = manager.getDisplayData(
archiveName, categoryName, false);
if (shutdown.get()) {
@ -868,13 +948,31 @@ public class SizeJob extends Job {
}
}
if (loadDisplayDataCnt == 0) {
if (loadDisplayDataListener != null) {
loadDisplayDataListener.loadedAllDisplayData();
}
}
return Status.OK_STATUS;
}
/**
*
* @param loadDisplayData
* @return true when missingData still needs to be processed.
*/
public boolean processing(LoadDisplayData loadDisplayData) {
synchronized (loadDisplayDataQueue) {
return loadDisplayDataQueue.contains(loadDisplayData)
|| loadDisplayData.equals(currentLoadDisplayData);
}
}
@Override
protected void canceling() {
shutdown.set(true);
}
}
}

View file

@ -22,6 +22,7 @@ package com.raytheon.uf.viz.archive.ui;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.core.runtime.IProgressMonitor;
@ -53,6 +54,7 @@ import com.raytheon.uf.common.util.SizeUtil;
import com.raytheon.uf.viz.archive.data.ArchiveInfo;
import com.raytheon.uf.viz.archive.data.CategoryInfo;
import com.raytheon.uf.viz.archive.data.IArchiveTotals;
import com.raytheon.uf.viz.archive.data.ILoadDisplayDataListener;
import com.raytheon.uf.viz.archive.data.IRetentionHour;
import com.raytheon.uf.viz.archive.data.IUpdateListener;
import com.raytheon.uf.viz.archive.data.SizeJob;
@ -77,6 +79,10 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
* Aug 06, 2013 2222 rferrel Changes to display all selected data.
* Nov 14, 2013 2549 rferrel Get category data moved off the UI thread.
* Dec 11, 2013 2624 rferrel No longer clear table prior to populating.
* Apr 15, 2014 3034 lvenable Added dispose checks in runAsync calls.
* Apr 10, 2014 3023 rferrel Added setTotalSelectedSize method.
* Apr 23, 2014 3045 rferrel Changes to prevent race condition while getting labels.
*
* </pre>
*
* @author bgonzale
@ -84,7 +90,8 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
*/
public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
IArchiveTotals, IUpdateListener, IModifyListener, IRetentionHour {
IArchiveTotals, IUpdateListener, IModifyListener, IRetentionHour,
ILoadDisplayDataListener {
/** Table composite that holds the table controls. */
private ArchiveTableComp tableComp;
@ -112,7 +119,7 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
/**
* Job that computes sizes of table row entries off the UI thread.
*/
protected final SizeJob sizeJob = new SizeJob();
protected final SizeJob sizeJob = new SizeJob(this);
/** Keeps track of when it is safe to clear the busy cursor. */
protected final AtomicInteger busyCnt = new AtomicInteger(0);
@ -136,6 +143,9 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
private String previousSelectedCategory = null;
/** Job running to populate the currently selected archive/category. */
private Job populateTableJob = null;
/**
* @param parentShell
*/
@ -362,6 +372,9 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
protected void disposed() {
sizeJob.removeUpdateListener(this);
sizeJob.cancel();
if (populateTableJob != null) {
populateTableJob.cancel();
}
}
/**
@ -460,12 +473,17 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
}
/**
* Load a select configuration file.
* Load selected configuration file.
*
* @param selectName
*/
protected void loadSelect(String selectName) {
sizeJob.loadSelect(selectName, type);
protected boolean loadSelect(String selectName) {
String message = sizeJob.loadSelect(selectName, type);
if (message != null) {
MessageDialog.openError(shell, "Unable to load Case", message);
return false;
}
return true;
}
/**
@ -480,15 +498,39 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
setShowingSelected(false);
Job job = new Job("populate category table") {
if (populateTableJob != null) {
populateTableJob.cancel();
setCursorBusy(false);
}
populateTableJob = new Job("populate category table") {
private AtomicBoolean shutdown = new AtomicBoolean(false);
@Override
protected IStatus run(IProgressMonitor monitor) {
getCategoryTableData(archiveName, categoryName);
getCategoryTableData(archiveName, categoryName, shutdown);
// Just populated the current table update cursor.
if (!shutdown.get()) {
populateTableJob = null;
VizApp.runAsync(new Runnable() {
@Override
public void run() {
setCursorBusy(false);
}
});
}
return Status.OK_STATUS;
}
@Override
protected void canceling() {
shutdown.set(true);
}
};
job.schedule();
populateTableJob.schedule();
}
/**
@ -498,26 +540,40 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
*
* @param archiveName
* @param categoryName
* @param shutdown
*/
private void getCategoryTableData(final String archiveName,
final String categoryName) {
final String categoryName, final AtomicBoolean shutdown) {
if (!sizeJob.isCurrentDisplay(archiveName, categoryName)) {
VizApp.runAsync(new Runnable() {
@Override
public void run() {
if (!isDisposed()) {
tableComp.clearTable();
}
}
});
}
final List<DisplayData> displayDatas = sizeJob.changeDisplay(
archiveName, categoryName);
archiveName, categoryName, shutdown);
VizApp.runAsync(new Runnable() {
@Override
public void run() {
try {
if (displayDatas != null) {
tableComp.populateTable(archiveName, categoryName,
displayDatas);
} else {
tableComp.refresh();
}
} finally {
setCursorBusy(false);
// If the dialog has been disposed then return.
if (isDisposed()) {
return;
}
if (displayDatas != null) {
tableComp.populateTable(archiveName, categoryName,
displayDatas);
} else {
tableComp.refresh();
}
}
});
@ -529,11 +585,14 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
* @param state
*/
protected void setCursorBusy(boolean state) {
if (state) {
busyCnt.addAndGet(1);
shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_WAIT));
} else if (busyCnt.addAndGet(-1) == 0) {
shell.setCursor(null);
if (!shell.isDisposed()) {
if (state) {
busyCnt.addAndGet(1);
shell.setCursor(shell.getDisplay().getSystemCursor(
SWT.CURSOR_WAIT));
} else if (busyCnt.addAndGet(-1) == 0) {
shell.setCursor(null);
}
}
}
@ -570,15 +629,22 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
}
}
setTotalSelectedSize(totalSize);
setTotalSelectedItems(totalSelected);
}
/**
*
* @param selectedTotalSize
*/
protected void setTotalSelectedSize(long selectedTotalSize) {
String sizeMsg = null;
if (totalSize == DisplayData.UNKNOWN_SIZE) {
if (selectedTotalSize == DisplayData.UNKNOWN_SIZE) {
sizeMsg = DisplayData.UNKNOWN_SIZE_LABEL;
} else {
sizeMsg = SizeUtil.prettyByteSize(totalSize);
sizeMsg = SizeUtil.prettyByteSize(selectedTotalSize);
}
setTotalSizeText(sizeMsg);
setTotalSelectedItems(totalSelected);
}
/**
@ -676,6 +742,11 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
@Override
public void run() {
// If the dialog has been disposed then return.
if (isDisposed()) {
return;
}
tableComp.updateSize(myDisplayDatas);
updateTotals(null);
}
@ -766,6 +837,11 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
return errorMsg == null;
}
/**
* Allows sub-class to perform updates once all the display data is loaded.
*/
abstract public void loadedAllDisplayData();
/**
* When unsaved modifications this asks the user to verify the close.
*

View file

@ -56,6 +56,8 @@ import com.raytheon.uf.common.time.util.TimeUtil;
* Aug 26, 2013 #2225 rferrel Make dialog perspective independent.
* Oct 01, 2013 #2147 rferrel Change getEnd() to pick up files with future time stamps.
* Oct 07, 2013 #2438 rferrel Properly save and load retention times.
* Apr 14, 2014 #3023 rferrel Code clean up.
* Apr 24, 2014 #3045 rferrel Implement loadedAllDsipalyData.
*
* </pre>
*
@ -70,12 +72,6 @@ public class ArchiveRetentionDlg extends AbstractArchiveDlg {
/** Current Archive/Category selection's extended retention hours. */
private RetentionHours extRetention;
/** Displays the total number of selected items for all tables. */
private Label totalSelectedItems;
/** Displays the total size of selected items. */
private Label totalSizeLbl;
/** Flag to indicate when retention hours are modified. */
private boolean retentionHoursAreModified = false;
@ -293,9 +289,6 @@ public class ArchiveRetentionDlg extends AbstractArchiveDlg {
*/
@Override
protected void setTotalSizeText(String sizeStringText) {
if (totalSizeLbl != null && !totalSizeLbl.isDisposed()) {
totalSizeLbl.setText(sizeStringText);
}
}
/*
@ -307,9 +300,6 @@ public class ArchiveRetentionDlg extends AbstractArchiveDlg {
*/
@Override
protected void setTotalSelectedItems(int totalSize) {
if (totalSelectedItems != null && !totalSelectedItems.isDisposed()) {
totalSelectedItems.setText("" + totalSize);
}
}
/*
@ -426,4 +416,9 @@ public class ArchiveRetentionDlg extends AbstractArchiveDlg {
archiveComboSelection();
categoryComboSelection();
}
@Override
public void loadedAllDisplayData() {
// nothing to update.
}
}

View file

@ -19,6 +19,7 @@
**/
package com.raytheon.uf.viz.archive.ui;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@ -63,6 +64,7 @@ import com.raytheon.uf.viz.archive.data.SizeJob;
* Aug 06, 2013 #2222 rferrel Changes to display all selected data.
* Aug 14, 2013 #2220 rferrel Add refresh method.
* Aug 26, 2013 #2225 rferrel Add missing updates.
* Apr 23, 2014 #3045 rferrel Added clearTable method and new column name.
*
* </pre>
*
@ -71,12 +73,19 @@ import com.raytheon.uf.viz.archive.data.SizeJob;
*/
public class ArchiveTableComp extends Composite {
/** Column label when table displaying category information. */
private final String CATEGORY_COL_LABEL = "Data Set";
/** Column label when table displaying select all information. */
private final String SEL_ALL_COL_LABEL = "Archive | Category | Data Set";
/** Column to display label information. */
private final int LABEL_COL_INDEX = 0;
/** Column to display size information,. */
private final int SIZE_COL_INDEX = 1;
/** Flag to indicate all selections are being displayed. */
private boolean showSelectAll = false;
/** Name of table's archive. */
@ -205,7 +214,7 @@ public class ArchiveTableComp extends Composite {
});
TableColumn pathColumn = new TableColumn(table, SWT.LEFT);
pathColumn.setText("Label");
pathColumn.setText(CATEGORY_COL_LABEL);
TableColumn sizeColumn = new TableColumn(table, SWT.CENTER);
if (type == Type.Retention) {
@ -464,10 +473,17 @@ public class ArchiveTableComp extends Composite {
protected void populateTable(String archiveName, String categoryName,
List<DisplayData> displayDatas) {
showSelectAll = false;
table.getColumn(0).setText("Label");
table.getColumn(0).setText(CATEGORY_COL_LABEL);
populateTable(displayDatas);
}
/**
* Clear table entries.
*/
protected void clearTable() {
populateTable(new ArrayList<DisplayData>(0));
}
/**
* Flag table as showing all selected data and update display.
*
@ -475,7 +491,7 @@ public class ArchiveTableComp extends Composite {
*/
protected void populateSelectAll(List<DisplayData> displayDatas) {
showSelectAll = true;
table.getColumn(0).setText("Archive | Category | Label");
table.getColumn(0).setText(SEL_ALL_COL_LABEL);
populateTable(displayDatas);
}

View file

@ -0,0 +1,79 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.archive.ui;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Archive case creation dialog's configuration options.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 11, 2014 3023 rferrel Initial creation
*
* </pre>
*
* @author rferrel
* @version 1.0
*/
@XmlRootElement(name = "CaseCreation")
@XmlAccessorType(XmlAccessType.NONE)
public class CaseCreation {
@XmlElement(name = "CautionThreshold")
private float cautionThreshold;
@XmlElement(name = "DangerThreshold")
private float dangerThreshold;
@XmlElement(name = "FatalThreshold")
private float fatalThreshold;
public float getCautionThreshold() {
return cautionThreshold;
}
public void setCautionThreshold(float cautionThreshold) {
this.cautionThreshold = cautionThreshold;
}
public float getDangerThreshold() {
return dangerThreshold;
}
public void setDangerThreshold(float dangerThreshold) {
this.dangerThreshold = dangerThreshold;
}
public float getFatalThreshold() {
return fatalThreshold;
}
public void setFatalThreshold(float fatalThreshold) {
this.fatalThreshold = fatalThreshold;
}
}

View file

@ -75,6 +75,9 @@ import com.raytheon.viz.ui.dialogs.ICloseCallback;
* Aug 26, 2013 #2225 rferrel Make perspective independent and no longer modal.
* Mar 24, 2014 #2853 rferrel Populate case label directory with default value.
* Mar 26, 2014 32880 rferrerl Implement case compression and split.
* Apr 11, 2014 #3023 rferrel Configurable Threshold options.
* Apr 23, 2014 #3045 rferrel To prevent race condition only allow a case
* load after all labels are loaded.
*
* </pre>
*
@ -165,6 +168,12 @@ public class CaseCreationDlg extends AbstractArchiveDlg {
/** Allow only single instance of dialog. */
private GenerateCaseDlg generateCaseDlg;
/** Manager for configurable values for the dialog. */
private final CaseCreationManager ccManager;
/** Flag to indicate all labels for all tables are loaded. */
private volatile boolean haveAllLabels = false;
/**
* Constructor.
*
@ -179,6 +188,7 @@ public class CaseCreationDlg extends AbstractArchiveDlg {
this.setSelect = false;
this.type = Type.Case;
this.defaultCaseDir = defaultCaseDir;
this.ccManager = new CaseCreationManager();
}
/*
@ -487,34 +497,48 @@ public class CaseCreationDlg extends AbstractArchiveDlg {
// }
// });
String tooltip = "Waiting on loading of Data Sets.";
Color color = shell.getDisplay().getSystemColor(SWT.COLOR_YELLOW);
saveBtn = new Button(actionControlComp, SWT.PUSH);
saveBtn.setText(" Save ");
saveBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent selectionEvent) {
saveSelection(selectName);
clearModified();
if (haveAllLabels) {
saveSelection(selectName);
clearModified();
}
}
});
saveBtn.setToolTipText(tooltip);
saveBtn.setEnabled(false);
saveBtn.setBackground(color);
saveAsBtn = new Button(actionControlComp, SWT.PUSH);
saveAsBtn.setText(" Save As... ");
saveAsBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent selectionEvent) {
handleSaveAsCase();
if (haveAllLabels) {
handleSaveAsCase();
}
}
});
saveAsBtn.setToolTipText(tooltip);
saveAsBtn.setBackground(color);
loadBtn = new Button(actionControlComp, SWT.PUSH);
loadBtn.setText(" Load... ");
loadBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent selectionEvent) {
handleLoadCase();
if (haveAllLabels) {
handleLoadCase();
}
}
});
loadBtn.setToolTipText(tooltip);
loadBtn.setBackground(color);
deleteBtn = new Button(actionControlComp, SWT.PUSH);
deleteBtn.setText(" Delete... ");
@ -603,11 +627,12 @@ public class CaseCreationDlg extends AbstractArchiveDlg {
public void dialogClosed(Object returnValue) {
if (returnValue instanceof String) {
String name = returnValue.toString();
loadSelect(name);
populateTableComp();
updateTotals(null);
setSelectName(name);
clearModified();
if (loadSelect(name)) {
populateTableComp();
updateTotals(null);
setSelectName(name);
clearModified();
}
}
}
});
@ -832,24 +857,33 @@ public class CaseCreationDlg extends AbstractArchiveDlg {
if (isDisposed()) {
return;
}
File dir = (File) locationLbl.getData();
Object o = locationLbl.getData();
if (!(o instanceof File)) {
return;
}
File dir = (File) o;
long totSpace = dir.getTotalSpace();
long freeSpace = dir.getUsableSpace();
o = uncompressSizeLbl.getData();
if (o instanceof Long) {
freeSpace -= (Long) o;
}
long percentFull = (long) Math.round(((totSpace - freeSpace) * 100.0)
/ totSpace);
String state = null;
Color bgColor = null;
Color fgColor = null;
Display display = shell.getDisplay();
if (percentFull <= 84) {
if (freeSpace > ccManager.getCautionThreshold()) {
state = "GOOD";
bgColor = display.getSystemColor(SWT.COLOR_GREEN);
fgColor = display.getSystemColor(SWT.COLOR_BLACK);
} else if (percentFull <= 94) {
} else if (freeSpace > ccManager.getDangerThreshold()) {
state = "CAUTION";
bgColor = display.getSystemColor(SWT.COLOR_YELLOW);
fgColor = display.getSystemColor(SWT.COLOR_BLACK);
} else if (percentFull <= 97) {
} else if (freeSpace > ccManager.getFatalThreshold()) {
state = "DANGER";
bgColor = display.getSystemColor(SWT.COLOR_RED);
fgColor = display.getSystemColor(SWT.COLOR_BLACK);
@ -958,10 +992,46 @@ public class CaseCreationDlg extends AbstractArchiveDlg {
return str;
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.archive.ui.AbstractArchiveDlg#setTotalSizeText(java
* .lang.String)
*/
@Override
protected void setTotalSizeText(String text) {
uncompressSizeLbl.setText(text);
if (!uncompressSizeLbl.isDisposed()) {
uncompressSizeLbl.setText(text);
}
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.archive.ui.AbstractArchiveDlg#setTotalSelectedSize
* (long)
*/
@Override
protected void setTotalSelectedSize(long totalSize) {
super.setTotalSelectedSize(totalSize);
Long tSize = null;
if (totalSize > 0) {
tSize = new Long(totalSize);
}
uncompressSizeLbl.setData(tSize);
updateLocationState();
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.archive.ui.AbstractArchiveDlg#setTotalSelectedItems
* (int)
*/
@Override
protected void setTotalSelectedItems(int totalSelected) {
selectedItemsSize = totalSelected;
totalSelectedItemsLbl.setText("" + totalSelected);
@ -1034,4 +1104,40 @@ public class CaseCreationDlg extends AbstractArchiveDlg {
defaultCaseDir));
}
}
/*
* (non-Javadoc)
*
* @see com.raytheon.uf.viz.archive.ui.AbstractArchiveDlg#haveAllLabels()
*/
@Override
public void loadedAllDisplayData() {
haveAllLabels = true;
/*
* Restore the buttons' default background color and tooltip text. The
* buttons color is not the system standard and the tool tip text
* indicates it is waiting for the labels to be loaded.
*/
VizApp.runAsync(new Runnable() {
@Override
public void run() {
if (!isDisposed()) {
saveBtn.setBackground(null);
saveBtn.setToolTipText(null);
saveAsBtn.setBackground(null);
saveAsBtn.setToolTipText(null);
loadBtn.setBackground(null);
loadBtn.setToolTipText(null);
}
}
});
}
@Override
protected boolean isModified() {
return super.isModified();
}
}

View file

@ -0,0 +1,98 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.archive.ui;
import java.io.File;
import javax.xml.bind.JAXB;
import org.apache.commons.io.FileUtils;
import com.raytheon.uf.common.localization.IPathManager;
import com.raytheon.uf.common.localization.PathManagerFactory;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
/**
* This class obtains the configurable options for the archive case creation
* dialog.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 11, 2014 3023 rferrel Initial creation
*
* </pre>
*
* @author rferrel
* @version 1.0
*/
public class CaseCreationManager {
private static transient IUFStatusHandler statusHandler = UFStatus
.getHandler(CaseCreationManager.class);
private CaseCreation caseCreation;
public CaseCreationManager() {
initValues();
}
private void initValues() {
String path = "archiver" + IPathManager.SEPARATOR + "gui"
+ IPathManager.SEPARATOR + "CaseCreation.xml";
IPathManager pm = PathManagerFactory.getPathManager();
File file = pm.getStaticFile(path);
try {
caseCreation = JAXB.unmarshal(file, CaseCreation.class);
} catch (RuntimeException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e);
caseCreation = new CaseCreation();
}
if (caseCreation.getCautionThreshold() <= 0.0) {
caseCreation.setCautionThreshold((float) 2.0);
}
if (caseCreation.getDangerThreshold() <= 0.0) {
caseCreation.setDangerThreshold((float) 1.0);
}
if (caseCreation.getFatalThreshold() <= 0.0) {
caseCreation.setFatalThreshold((float) 0.5);
}
}
public long getCautionThreshold() {
return (long) (caseCreation.getCautionThreshold() * FileUtils.ONE_GB);
}
public long getDangerThreshold() {
return (long) (caseCreation.getDangerThreshold() * FileUtils.ONE_GB);
}
public long getFatalThreshold() {
return (long) (caseCreation.getFatalThreshold() * FileUtils.ONE_GB);
}
}

View file

@ -116,7 +116,7 @@ public class CaseLoadSaveDeleteDlg extends CaveSWTDialog {
private void init() {
createCaseControls();
GuiUtil.addSeparator(shell, SWT.HORIZONTAL);
createBottomAcitonButtons();
createBottomActionButtons();
}
/**
@ -151,7 +151,7 @@ public class CaseLoadSaveDeleteDlg extends CaveSWTDialog {
/**
* Button layout at the bottom of the dialog.
*/
private void createBottomAcitonButtons() {
private void createBottomActionButtons() {
Composite actionControlComp = new Composite(shell, SWT.NONE);
GridLayout gl = new GridLayout(2, false);
GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);

View file

@ -27,8 +27,13 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.zip.GZIPOutputStream;
@ -60,6 +65,9 @@ import org.eclipse.swt.widgets.Shell;
import com.raytheon.uf.common.archive.config.ArchiveConfigManager;
import com.raytheon.uf.common.archive.config.ArchiveConstants;
import com.raytheon.uf.common.archive.config.DisplayData;
import com.raytheon.uf.common.dataquery.requests.SharedLockRequest;
import com.raytheon.uf.common.dataquery.requests.SharedLockRequest.RequestType;
import com.raytheon.uf.common.dataquery.responses.SharedLockResponse;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
@ -67,10 +75,12 @@ import com.raytheon.uf.common.time.util.ITimer;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.raytheon.uf.common.util.FileUtil;
import com.raytheon.uf.viz.core.VizApp;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.requests.ThriftClient;
import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
/**
* This class performs the desired type of case creation and display a
* This class performs the desired type of case creation and displays a
* progress/status message dialog.
*
* <pre>
@ -84,8 +94,9 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
* archive and category directory and
* implementation of compression.
* Oct 08, 2013 2442 rferrel Remove category directory.
* Feb 04, 2013 2270 rferrel Move HDF files to parent's directory.
* Feb 04, 2014 2270 rferrel Move HDF files to parent's directory.
* Mar 26, 2014 2880 rferrel Compress and split cases implemented.
* Apr 03, 2014 2862 rferrel Logic for shared locking of top level directories.
*
* </pre>
*
@ -95,12 +106,12 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
public class GenerateCaseDlg extends CaveSWTDialog {
/** Extension for HDF files. */
private static final String hdfExt = ".h5";
private final IUFStatusHandler statusHandler = UFStatus
.getHandler(GenerateCaseDlg.class);
/** Extension for HDF files. */
private static final String hdfExt = ".h5";
/** Use to display the current state of the case generation. */
private Label stateLbl;
@ -125,7 +136,7 @@ public class GenerateCaseDlg extends CaveSWTDialog {
/** End time for the case. */
private final Calendar endCal;
/** Data list for the case. */
/** Data list for the case sorted by archive and category names. */
private final DisplayData[] sourceDataList;
/** When true compress the case directory. */
@ -374,24 +385,74 @@ public class GenerateCaseDlg extends CaveSWTDialog {
}
/**
* The performs the work of generating the case on a non-UI thread.
* This performs the work of generating the case on a non-UI thread.
*/
private class GenerateJob extends Job {
/** Parent flag to shutdown the job. */
private final AtomicBoolean shutdown = new AtomicBoolean(false);
/** How long to wait before making another request for a plug-in lock. */
private final long LOCK_RETRY_TIME = 2 * TimeUtil.MILLIS_PER_MINUTE;
/** Files/directories needing plug-in locks in order to copy. */
private final Map<CopyInfo, Map<String, List<File>>> caseCopyMap = new HashMap<CopyInfo, Map<String, List<File>>>();
/** Timer to determine when to send another request for a plug-in lock. */
private final ITimer retrytimer = TimeUtil.getTimer();
/** Timer to update current lock's last execute time. */
private Timer updateTimer = null;
/**
* Constructor.
*/
public GenerateJob() {
super("Generate Case");
}
@Override
protected IStatus run(IProgressMonitor monitor) {
if (monitor.isCanceled()) {
return Status.OK_STATUS;
/**
* Add file to the caseCopyMap.
*
* @param copyInfo
* @param plugin
* @param file
* @return
*/
private boolean putFile(CopyInfo copyInfo, String plugin, File file) {
if (caseCopyMap.size() == 0) {
retrytimer.start();
}
Map<String, List<File>> pluginMap = caseCopyMap.get(copyInfo);
if (pluginMap == null) {
pluginMap = new HashMap<String, List<File>>();
caseCopyMap.put(copyInfo, pluginMap);
}
List<File> files = pluginMap.get(plugin);
if (files == null) {
files = new ArrayList<File>();
pluginMap.put(plugin, files);
}
return files.add(file);
}
/**
* @param copyInfo
* @return true if locks needed to complete the copy.
*/
private boolean keepCaseCopy(CopyInfo copyInfo) {
return caseCopyMap.get(copyInfo) != null;
}
/**
* @return true when valid case directory.
*/
private boolean validateCaseDirectory() {
setStateLbl("Creating: " + caseDir.getName(),
caseDir.getAbsolutePath());
ICaseCopy caseCopy = null;
String errorMessage = null;
if (caseDir.exists()) {
@ -403,41 +464,98 @@ public class GenerateCaseDlg extends CaveSWTDialog {
if (errorMessage != null) {
setStateLbl(errorMessage, caseDir.getAbsolutePath());
setProgressBar(100, SWT.ERROR);
return Status.OK_STATUS;
return false;
}
if (shutdown.get()) {
return false;
}
return true;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.
* IProgressMonitor)
*/
@Override
protected IStatus run(IProgressMonitor monitor) {
if (monitor.isCanceled()) {
return Status.OK_STATUS;
}
if (!validateCaseDirectory()) {
return Status.OK_STATUS;
}
ICaseCopy caseCopy = null;
String currentArchive = null;
String currentCategory = null;
boolean updateDestDir = false;
int rootDirLen = -1;
File rootDir = null;
String plugin = null;
boolean allowCopy = true;
CopyInfo copyInfo = null;
ITimer timer = TimeUtil.getTimer();
timer.start();
try {
/*
* The sourceDataList is sorted so all the displayDatas for a
* given archive/category are grouped together in the loop.
*/
for (DisplayData displayData : sourceDataList) {
if (shutdown.get()) {
return Status.OK_STATUS;
}
if (!displayData.getArchiveName().equals(currentArchive)) {
updateDestDir = true;
/*
* The current display data is for a different
* archive/category then the previous one.
*/
if (!displayData.getArchiveName().equals(currentArchive)
|| !displayData.getCategoryName().equals(
currentCategory)) {
// Finish up previous archive/category.
if (caseCopy != null) {
if (allowCopy) {
releaseLock(plugin);
}
/*
* The copyInfo needs locks in order to finish.
* Force creation of a new caseCopy for the new
* category.
*/
if (keepCaseCopy(copyInfo)) {
caseCopy = null;
copyInfo = null;
} else {
caseCopy.finishCase();
}
plugin = null;
}
// Set up for new category.
currentArchive = displayData.getArchiveName();
currentCategory = displayData.getCategoryName();
} else if (!displayData.getCategoryName().equals(
currentCategory)) {
updateDestDir = true;
currentCategory = displayData.getCategoryName();
}
rootDir = new File(displayData.getRootDir());
rootDirLen = displayData.getRootDir().length();
allowCopy = true;
if (updateDestDir) {
updateDestDir = false;
if (caseCopy != null) {
caseCopy.finishCase();
} else {
setStateLbl(currentArchive + " | " + currentCategory,
caseDir.getAbsolutePath() + "\n"
+ currentArchive + "\n"
+ currentCategory);
/*
* When caseCopy is not null it is safe to reuse it for
* the new category.
*/
if (caseCopy == null) {
if (!doCompress) {
caseCopy = new CopyMove();
} else if (doMultiFiles) {
@ -445,33 +563,83 @@ public class GenerateCaseDlg extends CaveSWTDialog {
} else {
caseCopy = new CompressCopy();
}
copyInfo = new CopyInfo(caseCopy, currentArchive,
currentCategory, caseDir);
}
caseCopy.startCase(caseDir, displayData, shutdown);
setStateLbl(currentArchive + " | " + currentCategory,
caseDir.getAbsolutePath() + "\n"
+ currentArchive + "\n"
+ currentCategory);
}
List<File> files = archiveManager.getDisplayFiles(
displayData, startCal, endCal);
/*
* Check all files/directories in the displayData and
* attempt a recursive copy.
*/
for (File source : files) {
if (shutdown.get()) {
return Status.OK_STATUS;
}
caseCopy.copy(source);
String dirName = source.getAbsolutePath()
.substring(rootDirLen).split(File.separator)[0];
String newPlugin = (new File(rootDir, dirName))
.getAbsolutePath();
// Have new plugin.
if (!newPlugin.equals(plugin)) {
// Release the current lock.
if (allowCopy && (plugin != null)) {
releaseLock(plugin);
}
allowCopy = requestLock(newPlugin);
plugin = newPlugin;
}
if (allowCopy) {
// Have lock safe to perform recursive copy.
caseCopy.copy(source);
} else {
// No lock add to Map of files needing locks.
putFile(copyInfo, plugin, source);
}
} // End of files loop
/*
* The copy may have taken some time see if any pending
* copies can be completed.
*/
if (retrytimer.getElapsedTime() >= LOCK_RETRY_TIME) {
retryCasesCopy();
}
}
if (caseCopy != null) {
caseCopy.finishCase();
} // End of sourceDataList loop
// Finish up the loop's last plugin.
if (plugin != null) {
if (allowCopy) {
releaseLock(plugin);
}
// Finish last case
if (!keepCaseCopy(copyInfo)) {
caseCopy.finishCase();
}
plugin = null;
}
caseCopy = null;
// Finish pending copies needing locks.
waitForLocks();
if (shutdown.get()) {
return Status.OK_STATUS;
}
setStateLbl("Created: " + caseName, caseDir.getAbsolutePath());
setProgressBar(100, SWT.NORMAL);
} catch (CaseCreateException e) {
} catch (Exception e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
setStateLbl(
@ -479,15 +647,25 @@ public class GenerateCaseDlg extends CaveSWTDialog {
caseDir.getAbsolutePath() + "\n"
+ e.getLocalizedMessage());
setProgressBar(100, SWT.ERROR);
shutdown.set(true);
} finally {
if (caseCopy != null) {
try {
caseCopy.finishCase();
} catch (Exception ex) {
// Ignore
}
caseCopy = null;
// shutdown the time.
if (updateTimer != null) {
updateTimer.cancel();
updateTimer = null;
}
// Release resources of active case copy.
if (caseCopy != null) {
if (!keepCaseCopy(copyInfo)) {
try {
// Allow the caseCopy to clean its resources.
caseCopy.finishCase();
} catch (Exception ex) {
// Ignore
}
caseCopy = null;
}
timer.stop();
if (statusHandler.isPriorityEnabled(Priority.INFO)) {
String message = String.format("Case %s took %s.",
@ -495,11 +673,201 @@ public class GenerateCaseDlg extends CaveSWTDialog {
TimeUtil.prettyDuration(timer.getElapsedTime()));
statusHandler.handle(Priority.INFO, message);
}
}
// Release current lock.
if (allowCopy && (plugin != null)) {
releaseLock(plugin);
}
// Release resources of any pending case copy.
if (caseCopyMap.size() > 0) {
for (CopyInfo cpi : caseCopyMap.keySet()) {
try {
cpi.caseCopy.finishCase();
} catch (CaseCreateException ex) {
// Ignore
}
}
caseCopyMap.clear();
}
}
return Status.OK_STATUS;
}
/**
* Finish copying all files needing locks.
*
* @throws CaseCreateException
* @throws InterruptedException
*/
private void waitForLocks() throws CaseCreateException,
InterruptedException {
int retryCount = 0;
boolean updateStatus = true;
while (caseCopyMap.size() > 0) {
if (updateStatus) {
++retryCount;
StringBuilder tooltip = new StringBuilder();
tooltip.append("Waiting to finish ").append(
caseCopyMap.size());
if (caseCopyMap.size() == 1) {
tooltip.append(" category.");
} else {
tooltip.append(" categories.");
}
tooltip.append("\nAttempt: ").append(retryCount);
setStateLbl("Waiting for locks", tooltip.toString());
updateStatus = false;
}
synchronized (this) {
wait(TimeUtil.MILLIS_PER_SECOND / 2L);
}
if (shutdown.get()) {
return;
}
if (retrytimer.getElapsedTime() >= LOCK_RETRY_TIME) {
retryCasesCopy();
updateStatus = true;
}
}
}
/**
* Attempt to copy files still waiting on plug-in locks.
*
* @throws CaseCreateException
*/
private void retryCasesCopy() throws CaseCreateException {
if (shutdown.get()) {
return;
}
if (caseCopyMap.size() > 0) {
retrytimer.stop();
retrytimer.reset();
String lockedPlugin = null;
try {
Iterator<CopyInfo> copyInfoIter = caseCopyMap.keySet()
.iterator();
while (copyInfoIter.hasNext()) {
CopyInfo copyInfo = copyInfoIter.next();
setStateLbl(copyInfo.archive + " | "
+ copyInfo.category,
copyInfo.caseDir.getAbsolutePath() + "\n"
+ copyInfo.archive + "\n"
+ copyInfo.category);
Map<String, List<File>> pluginMap = caseCopyMap
.get(copyInfo);
Iterator<String> pluginIter = pluginMap.keySet()
.iterator();
while (pluginIter.hasNext()) {
String plugin = pluginIter.next();
if (shutdown.get()) {
return;
}
if (requestLock(plugin)) {
lockedPlugin = plugin;
for (File source : pluginMap.get(plugin)) {
copyInfo.caseCopy.copy(source);
if (shutdown.get()) {
return;
}
}
releaseLock(plugin);
lockedPlugin = null;
pluginIter.remove();
}
}
if (pluginMap.size() == 0) {
copyInfo.caseCopy.finishCase();
copyInfoIter.remove();
}
}
} finally {
if (lockedPlugin != null) {
releaseLock(lockedPlugin);
}
}
}
if (caseCopyMap.size() > 0) {
retrytimer.start();
}
}
/**
* Request a lock for the plug-in.
*
* @param details
* @return true when lock obtained otherwise false
*/
private boolean requestLock(String details) {
SharedLockRequest request = new SharedLockRequest(
ArchiveConstants.CLUSTER_NAME, details,
RequestType.READER_LOCK);
try {
Object o = ThriftClient.sendRequest(request);
if (o instanceof SharedLockResponse) {
SharedLockResponse response = (SharedLockResponse) o;
if (response.isSucessful()) {
if (updateTimer == null) {
updateTimer = new Timer(
"Case Creation update timer", true);
}
TimerTask timerTask = new LockUpdateTask(details);
updateTimer.schedule(timerTask,
TimeUtil.MILLIS_PER_MINUTE,
TimeUtil.MILLIS_PER_MINUTE);
return true;
}
}
} catch (VizException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
}
return false;
}
/**
* Release previously obtained lock for the details.
*
* @param details
* @return true when lock released otherwise false.
*/
private boolean releaseLock(String details) {
SharedLockRequest request = new SharedLockRequest(
ArchiveConstants.CLUSTER_NAME, details,
RequestType.READER_UNLOCK);
try {
if (updateTimer != null) {
updateTimer.cancel();
updateTimer = null;
}
Object o = ThriftClient.sendRequest(request);
if (o instanceof SharedLockResponse) {
SharedLockResponse response = (SharedLockResponse) o;
if (response.isSucessful()) {
details = null;
return true;
}
}
} catch (VizException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
}
return false;
}
/*
* (non-Javadoc)
*
@ -574,7 +942,7 @@ public class GenerateCaseDlg extends CaveSWTDialog {
copyFile(new File(source, file),
new File(destination, file));
}
} else {
} else if (source.exists()) {
// DR 2270 bump HDF files up a directory.
if (destination.getName().endsWith(hdfExt)) {
destination = new File(destination.getParentFile()
@ -745,7 +1113,7 @@ public class GenerateCaseDlg extends CaveSWTDialog {
tarDirFile.add(file);
addTarFiles(file.listFiles());
}
} else {
} else if (file.exists()) {
checkFit(file);
// DR 2270 bump HDF files up a directory.
if (name.endsWith(hdfExt)) {
@ -1000,4 +1368,46 @@ public class GenerateCaseDlg extends CaveSWTDialog {
}
}
}
/** Task to update the lock plugin's last execute time. */
private final class LockUpdateTask extends TimerTask {
/** The locked cluster task's details. */
private final String details;
public LockUpdateTask(String details) {
this.details = details;
}
@Override
public void run() {
SharedLockRequest request = new SharedLockRequest(
ArchiveConstants.CLUSTER_NAME, details,
RequestType.READER_UPDATE_TIME);
try {
ThriftClient.sendRequest(request);
} catch (VizException e) {
statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
e);
}
}
}
/** Information needed to update status when retrying a copy. */
private static class CopyInfo {
protected final ICaseCopy caseCopy;
protected final String archive;
protected final String category;
protected final File caseDir;
public CopyInfo(ICaseCopy caseCopy, String archive, String category,
File caseDir) {
this.caseCopy = caseCopy;
this.archive = archive;
this.category = category;
this.caseDir = caseDir;
}
}
}

View file

@ -2,13 +2,13 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Ccfp Plug-in
Bundle-SymbolicName: com.raytheon.uf.viz.ccfp;singleton:=true
Bundle-Version: 1.12.1174.qualifier
Bundle-Activator: com.raytheon.uf.viz.ccfp.Activator
Bundle-Version: 1.14.0.qualifier
Bundle-Vendor: RAYTHEON
Eclipse-RegisterBuddy: com.raytheon.viz.core, com.raytheon.uf.viz.core
Require-Bundle: com.raytheon.uf.viz.core
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Import-Package: com.raytheon.edex.plugin.ccfp,
com.raytheon.uf.common.dataplugin,
Bundle-ActivationPolicy: lazy
Import-Package: com.raytheon.uf.common.dataplugin,
com.raytheon.uf.common.dataplugin.ccfp,
com.raytheon.uf.common.geospatial,
com.raytheon.uf.common.status,
com.raytheon.uf.common.time,
@ -18,15 +18,9 @@ Import-Package: com.raytheon.edex.plugin.ccfp,
com.raytheon.uf.viz.core.map,
com.raytheon.uf.viz.core.rsc,
com.raytheon.uf.viz.core.rsc.capabilities,
com.raytheon.uf.viz.core.status,
com.vividsolutions.jts.geom,
org.eclipse.core.runtime,
org.eclipse.swt.graphics,
org.eclipse.ui.plugin,
org.opengis.referencing.crs,
org.osgi.framework
Bundle-ActivationPolicy: lazy
Require-Bundle: com.raytheon.uf.viz.core,
org.geotools;bundle-version="2.5.2"
Export-Package: com.raytheon.uf.viz.ccfp,
com.raytheon.uf.viz.ccfp.rsc
Export-Package: com.raytheon.uf.viz.ccfp.rsc

View file

@ -1,81 +0,0 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.ccfp;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
/**
* The activator class controls the plug-in life cycle
*
* <pre>
*
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 22, 2009 3072 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class Activator extends AbstractUIPlugin {
// The plug-in ID
public static final String PLUGIN_ID = "com.raytheon.uf.viz.ccfp";
// The shared instance
private static Activator plugin;
/**
* The constructor
*/
public Activator() {
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}
/**
* Returns the shared instance
*
* @return the shared instance
*/
public static Activator getDefault() {
return plugin;
}
}

View file

@ -32,8 +32,8 @@ import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.raytheon.edex.plugin.ccfp.CcfpRecord;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.ccfp.CcfpRecord;
import com.raytheon.uf.common.geospatial.ReferencedCoordinate;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.viz.core.IExtent;

View file

@ -25,8 +25,8 @@ import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import com.raytheon.edex.plugin.ccfp.CcfpRecord;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.ccfp.CcfpRecord;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;

View file

@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Collaboratioin
Bundle-SymbolicName: com.raytheon.uf.viz.collaboration.comm;singleton:=true
Bundle-Version: 1.13.0.qualifier
Bundle-Version: 1.14.0.qualifier
Bundle-Activator: com.raytheon.uf.viz.collaboration.comm.Activator
Bundle-Vendor: RAYTHEON
Eclipse-RegisterBuddy: com.raytheon.uf.viz.core
@ -32,6 +32,8 @@ Export-Package: com.raytheon.uf.viz.collaboration.comm,
com.raytheon.uf.viz.collaboration.comm.identity.user,
com.raytheon.uf.viz.collaboration.comm.packet,
com.raytheon.uf.viz.collaboration.comm.provider,
com.raytheon.uf.viz.collaboration.comm.provider.account,
com.raytheon.uf.viz.collaboration.comm.provider.connection,
com.raytheon.uf.viz.collaboration.comm.provider.event,
com.raytheon.uf.viz.collaboration.comm.provider.info,
com.raytheon.uf.viz.collaboration.comm.provider.session,

View file

@ -19,6 +19,7 @@
**/
package com.raytheon.uf.viz.collaboration.comm;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
@ -34,6 +35,7 @@ import com.raytheon.uf.common.comm.NetworkStatistics;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 27, 2012 jkorman Initial creation
* Apr 23, 2014 2822 bclement added getBundleVersion()
*
* </pre>
*
@ -80,4 +82,20 @@ public class Activator implements BundleActivator {
return plugin;
}
/**
* Get the version from the manifest
*
* @return null if not available
*/
public static String getBundleVersion(){
String rval = null;
if ( plugin != null){
BundleContext context = plugin.getContext();
if ( context != null){
Bundle bundle = context.getBundle();
rval = bundle.getVersion().toString();
}
}
return rval;
}
}

View file

@ -40,7 +40,7 @@ package com.raytheon.uf.viz.collaboration.comm.identity;
import com.raytheon.uf.viz.collaboration.comm.identity.event.IEventPublisher;
import com.raytheon.uf.viz.collaboration.comm.identity.user.IUser;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
/**
* Base interface for sessions in which the client is interacting with others on

View file

@ -36,6 +36,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
* Feb 13, 2014 2751 bclement changed sendObjectToPeer id to VenueParticipant
* Feb 13, 2014 2751 njensen Added changeLeader()
* Feb 19, 2014 2751 bclement Added isClosed()
* Apr 15, 2014 2822 bclement added isSharedDisplayClient()
*
* </pre>
*
@ -124,4 +125,10 @@ public interface ISharedDisplaySession extends IVenueSession {
*/
public boolean isClosed();
/**
* @param participant
* @return true if the participant is viewing the shared display
*/
public boolean isSharedDisplayClient(VenueParticipant participant);
}

View file

@ -19,9 +19,10 @@
**/
package com.raytheon.uf.viz.collaboration.comm.identity.event;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.packet.Presence;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
/**
* Event fired when the roster has changed
*
@ -33,6 +34,7 @@ import org.jivesoftware.smack.packet.Presence;
* ------------ ---------- ----------- --------------------------
* Apr 06, 2012 jkorman Initial creation.
* Feb 24, 2014 2632 mpduff Added getPresence, changed getItem to getEntry.
* Apr 24, 2014 3070 bclement getEntry() returns UserId
*
* </pre>
*
@ -54,7 +56,7 @@ public interface IRosterChangeEvent {
*
* @return The changed entry
*/
RosterEntry getEntry();
UserId getEntry();
/**
* Get the Presence object.

View file

@ -19,7 +19,7 @@
**/
package com.raytheon.uf.viz.collaboration.comm.identity.roster;
import com.raytheon.uf.viz.collaboration.comm.provider.session.ISubscriptionRequestCompleteAction;
import com.raytheon.uf.viz.collaboration.comm.provider.account.ISubscriptionRequestCompleteAction;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
/**

View file

@ -17,7 +17,7 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider.session;
package com.raytheon.uf.viz.collaboration.comm.provider.account;
import java.util.Arrays;
import java.util.Map;
@ -34,6 +34,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.ISession;
import com.raytheon.uf.viz.collaboration.comm.identity.IVenueSession;
import com.raytheon.uf.viz.collaboration.comm.identity.roster.ISubscriptionResponder;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.event.UserPresenceChangedEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
@ -60,6 +61,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
* Feb 12, 2014 2797 bclement added protective copy to sendPresence
* Feb 13, 2014 2755 bclement added user input for which group to add contact to
* Apr 07, 2014 2785 mpduff Moved PacketListener implementation to its own class
* Apr 14, 2014 2903 bclement moved from session subpackage to account, made constructor public
*
* </pre>
*
@ -81,7 +83,7 @@ public class AccountManager implements IAccountManager {
*
* @param adapter
*/
AccountManager(CollaborationConnection manager) {
public AccountManager(CollaborationConnection manager) {
sessionManager = manager;
subscriptionEventListener = new SubscriptionPacketListener(
sessionManager);

View file

@ -17,7 +17,7 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider.session;
package com.raytheon.uf.viz.collaboration.comm.provider.account;
import java.net.URI;
import java.security.GeneralSecurityException;
@ -50,6 +50,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 24, 2014 2756 bclement Initial creation
* Apr 14, 2014 2903 bclement moved from session subpackage to account
*
* </pre>
*

View file

@ -17,7 +17,7 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider.session;
package com.raytheon.uf.viz.collaboration.comm.provider.account;
import com.raytheon.uf.viz.collaboration.comm.identity.roster.SubscriptionResponse;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
@ -32,6 +32,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 04, 2014 2785 mpduff Initial creation
* Apr 14, 2014 2903 bclement moved from session subpackage to account
*
* </pre>
*

View file

@ -17,7 +17,7 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider.session;
package com.raytheon.uf.viz.collaboration.comm.provider.account;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.RosterEntry;
@ -32,6 +32,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.event.IRosterChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.event.RosterChangeType;
import com.raytheon.uf.viz.collaboration.comm.identity.roster.ISubscriptionResponder;
import com.raytheon.uf.viz.collaboration.comm.identity.roster.SubscriptionResponse;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.event.RosterChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager;
import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter;
@ -49,6 +50,8 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 04, 2014 2785 mpduff Initial creation
* Apr 14, 2014 2903 bclement moved from session subpackage to account
* Apr 24, 2014 3070 bclement RosterChangeEvent changes, adds back even if blocked
*
* </pre>
*
@ -117,10 +120,8 @@ public class SubscriptionPacketListener implements PacketListener,
* @param fromID
*/
private void handleSubscribed(UserId fromID) {
ContactsManager cm = sessionManager.getContactsManager();
RosterEntry entry = cm.getRosterEntry(fromID);
IRosterChangeEvent event = new RosterChangeEvent(RosterChangeType.ADD,
entry);
fromID);
sessionManager.postEvent(event);
}
@ -130,13 +131,8 @@ public class SubscriptionPacketListener implements PacketListener,
* @param fromID
*/
private void handleUnsubscribed(UserId fromID) {
ContactsManager cm = sessionManager.getContactsManager();
RosterEntry entry = cm.getRosterEntry(fromID);
if (entry == null) {
return;
}
IRosterChangeEvent event = new RosterChangeEvent(
RosterChangeType.DELETE, entry);
RosterChangeType.DELETE, fromID);
sessionManager.postEvent(event);
}
@ -147,28 +143,29 @@ public class SubscriptionPacketListener implements PacketListener,
*/
private void handleSubResponse(UserId fromId, SubscriptionResponse response) {
Presence.Type subscribedType;
ContactsManager cm = sessionManager.getContactsManager();
boolean addToRoster = false;
if (response.isAccepted()) {
subscribedType = Presence.Type.subscribed;
RosterEntry entry = cm.getRosterEntry(fromId);
if (entry == null) {
addToRoster = true;
}
} else {
subscribedType = Presence.Type.unsubscribed;
}
Presence presence = new Presence(subscribedType);
try {
sendPresence(fromId, presence);
if (addToRoster) {
if (response.addToGroup()) {
cm.addToGroup(response.getGroup(), fromId);
} else {
cm.addToRoster(fromId);
if (response.isAccepted()) {
/* add them back */
ContactsManager cm = sessionManager.getContactsManager();
RosterEntry entry = cm.getRosterEntry(fromId);
if (entry != null && ContactsManager.isBlocked(entry)) {
/* in roster, but blocked */
cm.sendContactRequest(fromId);
}
if (response.addToGroup()) {
/*
* if contact is not in roster, this will also send them a
* contact request, otherwise it just add them to the group
*/
cm.addToGroup(response.getGroup(), fromId);
}
}
} catch (CollaborationException e) {
log.error("Unable to send presence", e);

View file

@ -17,31 +17,26 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider.session;
package com.raytheon.uf.viz.collaboration.comm.provider.connection;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang.StringUtils;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.StreamError;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smackx.muc.InvitationListener;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.pubsub.PubSubElementType;
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
import org.jivesoftware.smackx.pubsub.provider.SubscriptionProvider;
import org.jivesoftware.smackx.pubsub.provider.SubscriptionsProvider;
import com.google.common.eventbus.EventBus;
import com.google.common.net.HostAndPort;
@ -50,28 +45,25 @@ import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.xmpp.PacketConstants;
import com.raytheon.uf.common.xmpp.iq.AuthInfo;
import com.raytheon.uf.common.xmpp.iq.AuthInfoProvider;
import com.raytheon.uf.viz.collaboration.comm.Activator;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.IAccountManager;
import com.raytheon.uf.viz.collaboration.comm.identity.ISession;
import com.raytheon.uf.viz.collaboration.comm.identity.event.IEventPublisher;
import com.raytheon.uf.viz.collaboration.comm.identity.event.IRosterChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.event.IVenueInvitationEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.event.RosterChangeType;
import com.raytheon.uf.viz.collaboration.comm.identity.invite.SharedDisplayVenueInvite;
import com.raytheon.uf.viz.collaboration.comm.identity.invite.VenueInvite;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayload;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayload.PayloadType;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayloadProvider;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.event.RosterChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.event.ServerDisconnectEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.event.VenueInvitationEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.account.AccountManager;
import com.raytheon.uf.viz.collaboration.comm.provider.account.ClientAuthManager;
import com.raytheon.uf.viz.collaboration.comm.provider.event.VenueUserEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CreateSessionData;
import com.raytheon.uf.viz.collaboration.comm.provider.session.PeerToPeerChat;
import com.raytheon.uf.viz.collaboration.comm.provider.session.SharedDisplaySession;
import com.raytheon.uf.viz.collaboration.comm.provider.session.VenueSession;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager;
import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserSearch;
import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueId;
import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
/**
@ -119,6 +111,10 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
* changed session map to a concurrent hash map
* Apr 07, 2014 2785 mpduff Changed the order of startup, sets up listeners before actually connecting.
* Apr 09, 2014 2785 mpduff Throw error when not connected and the connection should exist.
* Apr 14, 2014 2903 bclement moved from session subpackage to connection, removed password from memory,
* moved listeners to own classes, reworked connect/register listeners/login order
* Apr 15, 2014 2822 bclement added pubsub owner subscriptions provider registration
* Apr 23, 2014 2822 bclement added resource name and getCollaborationVersion()
*
* </pre>
*
@ -135,18 +131,31 @@ public class CollaborationConnection implements IEventPublisher {
PacketConstants.COLLAB_XMLNS, new SessionPayloadProvider());
pm.addIQProvider(PacketConstants.QUERY_ELEMENT_NAME,
AuthInfo.AUTH_QUERY_XMLNS, new AuthInfoProvider());
/*
* smack doesn't support some of the OWNER operations such as getting
* all subscriptions on a node. PubSubOperations creates the request
* objects for these operations, but the response needs to be parsed.
* Here we register the existing smack parsers using the OWNER
* namespace.
*/
pm.addExtensionProvider(
PubSubElementType.SUBSCRIPTION.getElementName(),
PubSubNamespace.OWNER.getXmlns(), new SubscriptionProvider());
pm.addExtensionProvider(
PubSubElementType.SUBSCRIPTIONS.getElementName(),
PubSubNamespace.OWNER.getXmlns(), new SubscriptionsProvider());
}
private static final String RESOURCE_BASENAME = "CAVE";
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(CollaborationConnection.class);
private static CollaborationConnection instance = null;
private static volatile CollaborationConnection instance = null;
private static Map<CollaborationConnectionData, CollaborationConnection> instanceMap = new HashMap<CollaborationConnectionData, CollaborationConnection>();
private final Map<String, ISession> sessions;
private Map<String, ISession> sessions;
private UserId user;
private final UserId user;
private Presence userPresence;
@ -154,7 +163,7 @@ public class CollaborationConnection implements IEventPublisher {
private IAccountManager accountManager = null;
private EventBus eventBus;
private final EventBus eventBus;
private ContactsManager contactsMgr;
@ -162,6 +171,8 @@ public class CollaborationConnection implements IEventPublisher {
private XMPPConnection connection;
private final ConnectionConfiguration smackConfig;
private ClientAuthManager authManager;
private static boolean COMPRESS = true;
@ -178,59 +189,127 @@ public class CollaborationConnection implements IEventPublisher {
}
}
/**
* Returns the currently connected connection or null if it's not connected
*
* @return
*/
public static CollaborationConnection getConnection() {
return instance;
}
/**
* Create a {@link CollaborationConnection} given the
* {@link CollaborationConnectionData}
*
* @param userData
* @return
* @throws CollaborationException
*/
public static CollaborationConnection createConnection(
CollaborationConnectionData userData) throws CollaborationException {
synchronized (CollaborationConnection.class) {
if (instance == null) {
instance = new CollaborationConnection(userData);
} else {
throw new CollaborationException("Already connected");
}
}
return getConnection();
}
private CollaborationConnection(CollaborationConnectionData connectionData)
throws CollaborationException {
this.connectionData = connectionData;
init();
}
/**
* Initialize this object.
*/
private void init() throws CollaborationException {
eventBus = new EventBus();
sessions = new ConcurrentHashMap<String, ISession>();
HostAndPort hnp = HostAndPort.fromString(connectionData.getServer());
ConnectionConfiguration conConfig;
if (hnp.hasPort()) {
conConfig = new ConnectionConfiguration(hnp.getHostText(),
hnp.getPort());
} else {
conConfig = new ConnectionConfiguration(hnp.getHostText());
}
conConfig.setCompressionEnabled(COMPRESS);
connection = new XMPPConnection(conConfig);
accountManager = new AccountManager(this);
this.eventBus = new EventBus();
this.sessions = new ConcurrentHashMap<String, ISession>();
this.smackConfig = createSmackConfiguration(connectionData);
/* connects to XMPP server, but doesn't log in */
this.connection = createXmppConnection(smackConfig);
/* create managers and listeners before login */
this.accountManager = new AccountManager(this);
this.user = new UserId(connectionData.getUserName(),
connection.getServiceName());
setupInternalConnectionListeners();
getPeerToPeerSession();
instanceMap.put(connectionData, this);
if (instance == null) {
instance = this;
}
this.chatInstance = initPeerToPeerSession();
this.contactsMgr = new ContactsManager(this, this.getXmppConnection());
registerEventHandler(this.contactsMgr);
MultiUserChat.addInvitationListener(connection,
new SessionInviteListener(this));
PeerToPeerCommHelper helper = new PeerToPeerCommHelper(this);
this.connection.addPacketListener(helper, new PacketTypeFilter(
Message.class));
this.connection.addConnectionListener(new XmppConnectionListener(this));
/* login called externally */
}
/**
* connect to XMPP server and login
* Create smack xmpp configuration object from collaboration connection
* options
*
* @param connectionData
* @return
*/
private static ConnectionConfiguration createSmackConfiguration(
CollaborationConnectionData connectionData) {
ConnectionConfiguration rval;
HostAndPort hnp = HostAndPort.fromString(connectionData.getServer());
if (hnp.hasPort()) {
rval = new ConnectionConfiguration(hnp.getHostText(), hnp.getPort());
} else {
rval = new ConnectionConfiguration(hnp.getHostText());
}
rval.setCompressionEnabled(COMPRESS);
rval.setReconnectionAllowed(false);
return rval;
}
/**
* Create xmpp connection object and connect. This method does not login
*
* @param config
* @return
* @throws CollaborationException
*/
private static XMPPConnection createXmppConnection(
ConnectionConfiguration config) throws CollaborationException {
XMPPConnection rval = new XMPPConnection(config);
try {
rval.connect();
} catch (XMPPException e) {
throw new CollaborationException(
"Problem establishing connection to XMPP server", e);
}
return rval;
}
/**
* Login to the XMPP server. This needs to be called after the
* CollaborationConnection has been created and initialized.
*
* @param password
* @throws CollaborationException
*/
public void login(String password) throws CollaborationException {
loginInternal(connectionData.getUserName(), password);
/* auth needs to be logged in to register public key */
authManager = new ClientAuthManager(getXmppConnection());
}
/**
* login to XMPP server
*
* @param username
* @param password
* @throws CollaborationException
*/
private void connectInternal(String username, String password)
private void loginInternal(String username, String password)
throws CollaborationException {
try {
connection.connect();
connection.login(username, password);
connection.login(username, password, getResourceName());
} catch (XMPPException e) {
closeInternals();
close();
// get a nice reason for the user
String msg;
XMPPError xmppErr = e.getXMPPError();
@ -252,9 +331,37 @@ public class CollaborationConnection implements IEventPublisher {
msg = e.getLocalizedMessage();
}
throw new CollaborationException("Login failed: " + msg, e);
} finally {
/* remove password from smack */
SmackConfigScrubber.scrubConfig(smackConfig);
}
}
/**
* get name used for CAVE collaboration XMPP resource
*
* @return
*/
public static String getResourceName() {
String rval = RESOURCE_BASENAME;
String version = getCollaborationVersion();
if (version != null) {
rval += "-" + version;
}
return rval;
}
/**
* @see Activator#getBundleVersion()
* @return
*/
public static String getCollaborationVersion() {
return Activator.getBundleVersion();
}
/**
* @return login data used to create this connection
*/
public CollaborationConnectionData getConnectionData() {
return connectionData;
}
@ -292,18 +399,25 @@ public class CollaborationConnection implements IEventPublisher {
}
/**
* Is this SessionManager currently connected?
* Is this client currently connected to the XMPP server?
*
* @return Is this SessionManager currently connected?
* @return
*/
public boolean isConnected() {
return ((connection != null) && (connection.getConnectionID() != null));
return connection != null && connection.isConnected();
}
private void closeInternals() {
/**
* close any open sessions and disconnect from XMPP server
*/
public void close() {
// Close any created sessions.
for (Entry<String, ISession> entry : sessions.entrySet()) {
entry.getValue().close();
}
sessions.clear();
chatInstance = null;
if (connection != null) {
chatInstance = null;
// Get rid of the account and roster managers
if (connection.isConnected()) {
connection.disconnect();
@ -311,31 +425,11 @@ public class CollaborationConnection implements IEventPublisher {
connection = null;
}
PeerToPeerCommHelper.reset();
instanceMap.remove(connectionData);
if (this == instance) {
instance = null;
}
}
/**
*
*/
public void close() {
if (connection != null) {
// Close any created sessions.
Collection<ISession> toRemove = sessions.values();
sessions.clear();
for (ISession session : toRemove) {
if ((chatInstance != null) && chatInstance.equals(session)) {
chatInstance.close();
chatInstance = null;
} else {
session.close();
}
synchronized (CollaborationConnection.class) {
if (this == instance) {
instance = null;
}
chatInstance = null;
}
closeInternals();
}
/**
@ -345,14 +439,23 @@ public class CollaborationConnection implements IEventPublisher {
* @throws CollaborationException
*/
public ISession getPeerToPeerSession() throws CollaborationException {
if (chatInstance == null) {
chatInstance = new PeerToPeerChat(eventBus, this);
sessions.put(chatInstance.getSessionId(), chatInstance);
postEvent(chatInstance);
}
return chatInstance;
}
/**
* Create and initialize peer to peer chat session object.
*
* @return
* @throws CollaborationException
*/
private PeerToPeerChat initPeerToPeerSession()
throws CollaborationException {
PeerToPeerChat rval = new PeerToPeerChat(eventBus, this);
sessions.put(rval.getSessionId(), rval);
postEvent(rval);
return rval;
}
/**
* Create shared display venue object. This does not create the venue on the
* server. The session should be unregistered when no longer active using
@ -450,6 +553,7 @@ public class CollaborationConnection implements IEventPublisher {
}
/**
* unregister session with connection and notify UI elements
*
* @param session
*/
@ -458,227 +562,16 @@ public class CollaborationConnection implements IEventPublisher {
postEvent(session);
}
// ***************************
// Connection listener
// ***************************
/**
* Get registered session
*
* @param sessionId
* @return
*/
private void setupInternalConnectionListeners() {
final Roster roster = connection.getRoster();
roster.addRosterListener(new RosterListener() {
@Override
public void presenceChanged(Presence presence) {
String fromId = presence.getFrom();
if (contactsMgr != null) {
UserId u = IDConverter.convertFrom(fromId);
if (u != null) {
RosterEntry entry = contactsMgr.getRosterEntry(u);
eventBus.post(entry);
IRosterChangeEvent event = new RosterChangeEvent(
RosterChangeType.PRESENCE, entry, presence);
eventBus.post(event);
}
}
}
@Override
public void entriesUpdated(Collection<String> addresses) {
send(addresses, RosterChangeType.MODIFY);
}
@Override
public void entriesDeleted(Collection<String> addresses) {
send(addresses, RosterChangeType.DELETE);
}
@Override
public void entriesAdded(Collection<String> addresses) {
send(addresses, RosterChangeType.ADD);
}
/**
* Send event bus notification for roster
*
* @param addresses
* @param type
*/
private void send(Collection<String> addresses,
RosterChangeType type) {
for (String addy : addresses) {
RosterEntry entry = roster.getEntry(addy);
if (entry != null) {
IRosterChangeEvent event = new RosterChangeEvent(type,
entry);
eventBus.post(event);
}
}
}
});
}
public ISession getSession(String sessionId) {
return sessions.get(sessionId);
}
private void setupP2PComm() throws CollaborationException {
if (isConnected()) {
PeerToPeerCommHelper helper = new PeerToPeerCommHelper(this);
connection.addPacketListener(helper, new PacketTypeFilter(
Message.class));
} else {
throw new CollaborationException(
"The Collaboration XMPP connection has not been established.");
}
}
private void setupConnectionListener() throws CollaborationException {
if (isConnected()) {
connection.addConnectionListener(new ConnectionListener() {
@Override
public void reconnectionSuccessful() {
statusHandler
.debug("Client successfully reconnected to server");
postSystemMessageToVenues("Connection to collaboration server reestablished.");
}
@Override
public void reconnectionFailed(Exception e) {
String reason = getErrorReason(e);
statusHandler.error("Client can't reconnect to server: "
+ reason, e);
sendDisconnectNotice(reason);
}
@Override
public void reconnectingIn(int seconds) {
statusHandler.debug("Client reconnecting to server in "
+ seconds + " seconds");
}
@Override
public void connectionClosedOnError(Exception e) {
String reason = getErrorReason(e);
statusHandler.error("Server closed on error: " + reason, e);
// don't shutdown yet, we might be able to reconnect
postSystemMessageToVenues("Not currently connected to collaboration server.");
}
private String getErrorReason(Exception e) {
String msg = null;
if (e instanceof XMPPException) {
StreamError streamError = ((XMPPException) e)
.getStreamError();
if (streamError != null) {
if ("conflict".equalsIgnoreCase(streamError
.getCode())) {
msg = "User account in use on another client";
}
}
}
return msg == null ? e.getLocalizedMessage() : msg;
}
@Override
public void connectionClosed() {
statusHandler.info("Server closed connection");
sendDisconnectNotice("Normal termination");
}
private void sendDisconnectNotice(String reason) {
ServerDisconnectEvent event = new ServerDisconnectEvent(
reason);
eventBus.post(event);
}
});
} else {
throw new CollaborationException(
"The Collaboration XMPP connection has not been established.");
}
}
// ***************************
// Venue invitation listener management
// ***************************
/**
* Set up the invitation listener.
*
* @throws CollaborationException
*/
private void setupInternalVenueInvitationListener()
throws CollaborationException {
if (isConnected()) {
MultiUserChat.addInvitationListener(connection,
new InvitationListener() {
@Override
public void invitationReceived(Connection conn,
String room, String inviter, String reason,
String password, Message message) {
// TODO handle password protected rooms
VenueId venueId = new VenueId();
venueId.setName(Tools.parseName(room));
venueId.setHost(Tools.parseHost(room));
UserId invitor = IDConverter.convertFrom(inviter);
if (message != null) {
SessionPayload payload = (SessionPayload) message
.getExtension(PacketConstants.COLLAB_XMLNS);
if (payload != null) {
handleCollabInvite(venueId, invitor,
payload);
return;
}
}
if (reason != null
&& reason.startsWith(Tools.CMD_PREAMBLE)) {
reason = "Shared display invitation from incompatible version of CAVE. "
+ "Session will be chat-only if invitation is accepted";
}
handleChatRoomInvite(venueId, invitor, reason,
message);
}
});
} else {
throw new CollaborationException(
"The Collaboration XMPP connection has not been established.");
}
}
private void handleChatRoomInvite(VenueId venueId, UserId invitor,
String reason, Message message) {
VenueInvite invite = new VenueInvite();
if (!StringUtils.isBlank(reason)) {
invite.setMessage(reason);
} else if (!StringUtils.isBlank(message.getBody())) {
invite.setMessage(message.getBody());
} else {
invite.setMessage("");
}
invite.setSubject(message.getSubject());
IVenueInvitationEvent event = new VenueInvitationEvent(venueId,
invitor, invite);
eventBus.post(event);
}
private void handleCollabInvite(VenueId venueId, UserId invitor,
SessionPayload payload) {
Object obj = payload.getData();
if (obj == null
|| !payload.getPayloadType().equals(PayloadType.Invitation)
|| !(obj instanceof VenueInvite)) {
statusHandler.warn("Received unsupported invite payload");
return;
}
VenueInvite invite = (VenueInvite) obj;
IVenueInvitationEvent event = new VenueInvitationEvent(venueId,
invitor, invite);
eventBus.post(event);
}
/**
* Register an event handler with this
*
@ -712,38 +605,10 @@ public class CollaborationConnection implements IEventPublisher {
return sessions.values();
}
/**
* Returns the currently connected connection or null if it's not connected
*
* @return
*/
public static CollaborationConnection getConnection() {
return instance;
}
/**
* Create a {@link CollaborationConnection} given the
* {@link CollaborationConnectionData}
*
* @param userData
* @return
* @throws CollaborationException
*/
public static CollaborationConnection createConnection(
CollaborationConnectionData userData) throws CollaborationException {
if (instance != null) {
throw new CollaborationException("Already connected");
}
instance = new CollaborationConnection(userData);
return getConnection();
}
/**
* @return Smack connection object
*/
protected XMPPConnection getXmppConnection() {
public XMPPConnection getXmppConnection() {
return connection;
}
@ -776,23 +641,9 @@ public class CollaborationConnection implements IEventPublisher {
}
/**
* Connect to the XMPP server. This needs to be called after the
* CollaborationConnection has been created and initialized.
*
* @throws CollaborationException
* @return the statusHandler
*/
public void connect() throws CollaborationException {
contactsMgr = new ContactsManager(this, this.getXmppConnection());
registerEventHandler(instance.getContactsManager());
connectInternal(connectionData.getUserName(),
connectionData.getPassword());
authManager = new ClientAuthManager(getXmppConnection());
// Finish setup
setupInternalVenueInvitationListener();
setupP2PComm();
setupConnectionListener();
protected static IUFStatusHandler getStatusHandler() {
return statusHandler;
}
}

View file

@ -17,7 +17,7 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider.session;
package com.raytheon.uf.viz.collaboration.comm.provider.connection;
import java.util.HashMap;
import java.util.Map;
@ -36,6 +36,7 @@ import org.jivesoftware.smack.packet.Presence.Mode;
* ------------ ---------- ----------- --------------------------
* Jun 18, 2012 mschenke Initial creation
* Jan 15, 2014 2630 bclement connection data stores status as Mode object
* Apr 14, 2014 2903 bclement removed password, moved from session subpackage to connection
*
* </pre>
*
@ -49,8 +50,6 @@ public class CollaborationConnectionData {
private String userName;
private String password;
private Mode status;
private String message;
@ -91,21 +90,6 @@ public class CollaborationConnectionData {
this.userName = userName;
}
/**
* @return the password
*/
public String getPassword() {
return password;
}
/**
* @param password
* the password to set
*/
public void setPassword(String password) {
this.password = password;
}
/**
* @return the status
*/
@ -163,8 +147,6 @@ public class CollaborationConnectionData {
result = prime * result
+ ((attributes == null) ? 0 : attributes.hashCode());
result = prime * result + ((message == null) ? 0 : message.hashCode());
result = prime * result
+ ((password == null) ? 0 : password.hashCode());
result = prime * result + ((server == null) ? 0 : server.hashCode());
result = prime * result + ((status == null) ? 0 : status.hashCode());
result = prime * result
@ -196,11 +178,6 @@ public class CollaborationConnectionData {
return false;
} else if (!message.equals(other.message))
return false;
if (password == null) {
if (other.password != null)
return false;
} else if (!password.equals(other.password))
return false;
if (server == null) {
if (other.server != null)
return false;

View file

@ -17,7 +17,7 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider.session;
package com.raytheon.uf.viz.collaboration.comm.provider.connection;
import java.net.URI;
import java.net.URL;
@ -63,6 +63,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
* Feb 17, 2014 2756 bclement null check for message from field
* moved url validation from regex to java utility
* Feb 24, 2014 2756 bclement moved xmpp objects to new packages
* Apr 14, 2014 2903 bclement moved from session subpackage to connection
*
* </pre>
*
@ -72,8 +73,8 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
public class PeerToPeerCommHelper implements PacketListener {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(PeerToPeerCommHelper.class);
private static final transient IUFStatusHandler statusHandler = CollaborationConnection
.getStatusHandler();
private static volatile String httpServer;
@ -88,7 +89,7 @@ public class PeerToPeerCommHelper implements PacketListener {
return httpServer;
}
private CollaborationConnection manager;
private final CollaborationConnection manager;
/**
*

View file

@ -0,0 +1,149 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider.connection;
import org.apache.commons.lang.StringUtils;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.muc.InvitationListener;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.xmpp.PacketConstants;
import com.raytheon.uf.viz.collaboration.comm.identity.event.IVenueInvitationEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.invite.VenueInvite;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayload;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayload.PayloadType;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.event.VenueInvitationEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueId;
/**
* Handles incoming session invitations and routes to event bus
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 11, 2014 2903 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class SessionInviteListener implements InvitationListener {
private static final IUFStatusHandler statusHandler = CollaborationConnection
.getStatusHandler();
private final CollaborationConnection manager;
/**
* @param manager
*/
public SessionInviteListener(CollaborationConnection manager) {
this.manager = manager;
}
/*
* (non-Javadoc)
*
* @see
* org.jivesoftware.smackx.muc.InvitationListener#invitationReceived(org
* .jivesoftware.smack.Connection, java.lang.String, java.lang.String,
* java.lang.String, java.lang.String,
* org.jivesoftware.smack.packet.Message)
*/
@Override
public void invitationReceived(Connection conn, String room,
String inviter, String reason, String password, Message message) {
// TODO handle password protected rooms
VenueId venueId = new VenueId();
venueId.setName(Tools.parseName(room));
venueId.setHost(Tools.parseHost(room));
UserId invitor = IDConverter.convertFrom(inviter);
SessionPayload payload = null;
if (message != null) {
payload = (SessionPayload) message
.getExtension(PacketConstants.COLLAB_XMLNS);
}
if (reason != null && reason.startsWith(Tools.CMD_PREAMBLE)) {
reason = "Shared display invitation from incompatible version of CAVE. "
+ "Session will be chat-only if invitation is accepted";
}
if (payload != null) {
handleCollabInvite(venueId, invitor, payload);
} else {
handleChatRoomInvite(venueId, invitor, reason, message);
}
}
/**
* Handles acceptance of a text only session invitation
*
* @param venueId
* @param invitor
* @param reason
* @param message
*/
private void handleChatRoomInvite(VenueId venueId, UserId invitor,
String reason, Message message) {
VenueInvite invite = new VenueInvite();
if (!StringUtils.isBlank(reason)) {
invite.setMessage(reason);
} else if (!StringUtils.isBlank(message.getBody())) {
invite.setMessage(message.getBody());
} else {
invite.setMessage("");
}
invite.setSubject(message.getSubject());
IVenueInvitationEvent event = new VenueInvitationEvent(venueId,
invitor, invite);
manager.postEvent(event);
}
/**
* Handles acceptance of a shared display session invitation
*
* @param venueId
* @param invitor
* @param payload
*/
private void handleCollabInvite(VenueId venueId, UserId invitor,
SessionPayload payload) {
Object obj = payload.getData();
if (obj == null
|| !payload.getPayloadType().equals(PayloadType.Invitation)
|| !(obj instanceof VenueInvite)) {
statusHandler.warn("Received unsupported invite payload");
return;
}
VenueInvite invite = (VenueInvite) obj;
IVenueInvitationEvent event = new VenueInvitationEvent(venueId,
invitor, invite);
manager.postEvent(event);
}
}

View file

@ -0,0 +1,97 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider.connection;
import java.lang.reflect.Field;
import org.jivesoftware.smack.ConnectionConfiguration;
import com.raytheon.uf.common.status.IUFStatusHandler;
/**
* Sanitizes smack configuration object to keep sensitive information out of the
* heap
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 11, 2014 2903 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class SmackConfigScrubber {
private static final IUFStatusHandler log = CollaborationConnection
.getStatusHandler();
private static volatile Field passwordField;
private static final String PASSWORD_FIELD_NAME = "password";
private SmackConfigScrubber() {
}
/**
* remove sensitive information from smack configuration
*
* @param config
*/
public static void scrubConfig(ConnectionConfiguration config) {
if (passwordField == null) {
synchronized (SmackConfigScrubber.class) {
if (passwordField == null) {
passwordField = createPasswordField();
}
}
}
if (passwordField != null) {
try {
passwordField.set(config, null);
} catch (Exception e) {
log.debug("Unable to scrub xmpp configuration: "
+ e.getLocalizedMessage());
}
}
}
/**
* Create a field object for the connection configuration class object
*
* @return null if unable to create
*/
private static Field createPasswordField() {
try {
Class<?> c = ConnectionConfiguration.class;
Field rval = c.getDeclaredField(PASSWORD_FIELD_NAME);
rval.setAccessible(true);
return rval;
} catch (Exception e) {
log.debug("Unable to access xmpp configuration: "
+ e.getLocalizedMessage());
return null;
}
}
}

View file

@ -0,0 +1,123 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider.connection;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.StreamError;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.viz.collaboration.comm.provider.event.ServerDisconnectEvent;
/**
* Handles connection events from the XMPP server
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 11, 2014 2903 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class XmppConnectionListener implements ConnectionListener {
private static final IUFStatusHandler statusHandler = CollaborationConnection
.getStatusHandler();
private final CollaborationConnection manager;
/**
* @param manager
*/
public XmppConnectionListener(CollaborationConnection manager) {
this.manager = manager;
}
@Override
public void reconnectionSuccessful() {
/* this will not be called since we don't allow auto reconnect */
statusHandler.debug("Client successfully reconnected to server");
manager.postSystemMessageToVenues("Connection to collaboration server reestablished.");
}
@Override
public void reconnectionFailed(Exception e) {
/* this will not be called since we don't allow auto reconnect */
String reason = getErrorReason(e);
statusHandler.error("Client can't reconnect to server: " + reason, e);
sendDisconnectNotice(reason);
}
@Override
public void reconnectingIn(int seconds) {
/* this will not be called since we don't allow auto reconnect */
statusHandler.debug("Client reconnecting to server in " + seconds
+ " seconds");
}
@Override
public void connectionClosedOnError(Exception e) {
String reason = getErrorReason(e);
statusHandler.error("Server closed on error: " + reason, e);
sendDisconnectNotice(reason);
}
/**
* Attempt to get the most meaningful message from XMPP exception
*
* @param e
* @return
*/
private String getErrorReason(Exception e) {
String msg = null;
if (e instanceof XMPPException) {
StreamError streamError = ((XMPPException) e).getStreamError();
if (streamError != null) {
if ("conflict".equalsIgnoreCase(streamError.getCode())) {
msg = "User account in use on another client";
}
}
}
return msg == null ? e.getLocalizedMessage() : msg;
}
@Override
public void connectionClosed() {
statusHandler.info("Server closed connection");
/* don't send notice for normal termination */
}
/**
* Alert event bus listeners of disconnect
*
* @param reason
*/
private void sendDisconnectNotice(String reason) {
ServerDisconnectEvent event = new ServerDisconnectEvent(reason);
manager.postEvent(event);
}
}

View file

@ -19,11 +19,11 @@
**/
package com.raytheon.uf.viz.collaboration.comm.provider.event;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.packet.Presence;
import com.raytheon.uf.viz.collaboration.comm.identity.event.IRosterChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.event.RosterChangeType;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
/**
* Event posted when a roster entry needs to be updated
@ -36,6 +36,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.event.RosterChangeType;
* ------------ ---------- ----------- --------------------------
* Apr 11, 2012 jkorman Initial creation
* Feb 24, 2014 2632 mpduff Added getPresence, changed getItem to getEntry.
* Apr 24, 2014 3070 bclement getEntry() returns UserId
*
* </pre>
*
@ -47,7 +48,7 @@ public class RosterChangeEvent implements IRosterChangeEvent {
private final RosterChangeType type;
private final RosterEntry entry;
private final UserId entry;
/** The presence object */
private Presence presence;
@ -60,7 +61,7 @@ public class RosterChangeEvent implements IRosterChangeEvent {
* @param entry
* The changed entry.
*/
public RosterChangeEvent(RosterChangeType type, RosterEntry entry) {
public RosterChangeEvent(RosterChangeType type, UserId entry) {
this.type = type;
this.entry = entry;
}
@ -76,7 +77,7 @@ public class RosterChangeEvent implements IRosterChangeEvent {
* @param presence
* The presence object
*/
public RosterChangeEvent(RosterChangeType type, RosterEntry entry,
public RosterChangeEvent(RosterChangeType type, UserId entry,
Presence presence) {
this.type = type;
this.entry = entry;
@ -102,7 +103,7 @@ public class RosterChangeEvent implements IRosterChangeEvent {
* @see com.raytheon.uf.viz.collaboration.comm.identity.event.IRosterChangeEvent#getEntry()
*/
@Override
public RosterEntry getEntry() {
public UserId getEntry() {
return entry;
}

View file

@ -27,6 +27,7 @@ import com.google.common.eventbus.EventBus;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.ISession;
import com.raytheon.uf.viz.collaboration.comm.identity.user.IUser;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
/**
* Base class for chat and collaboration sessions

View file

@ -34,6 +34,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.IPeerToPeer;
import com.raytheon.uf.viz.collaboration.comm.identity.IPropertied.Property;
import com.raytheon.uf.viz.collaboration.comm.identity.user.IUser;
import com.raytheon.uf.viz.collaboration.comm.provider.TextMessage;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
/**
@ -51,6 +52,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
* Apr 18, 2012 njensen Cleanup
* Dec 6, 2013 2561 bclement removed ECF
* Feb 13, 2014 2751 bclement changed IQualifiedID objects to IUser
* Apr 11, 2014 2903 bclement made constructor public b/c connection code moved packages
*
* </pre>
*
@ -66,7 +68,7 @@ public class PeerToPeerChat extends BaseSession implements IPeerToPeer {
* @param externalBus
* @param manager
*/
PeerToPeerChat(EventBus externalBus,
public PeerToPeerChat(EventBus externalBus,
CollaborationConnection manager) throws CollaborationException {
super(externalBus, manager);
}

View file

@ -19,9 +19,18 @@
**/
package com.raytheon.uf.viz.collaboration.comm.provider.session;
import java.util.List;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smackx.pubsub.Node;
import org.jivesoftware.smackx.pubsub.NodeExtension;
import org.jivesoftware.smackx.pubsub.PubSubElementType;
import org.jivesoftware.smackx.pubsub.Subscription;
import org.jivesoftware.smackx.pubsub.SubscriptionsExtension;
import org.jivesoftware.smackx.pubsub.packet.PubSub;
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
import org.jivesoftware.smackx.pubsub.packet.SyncPacketSend;
@ -38,7 +47,8 @@ import com.raytheon.uf.common.xmpp.ext.ChangeAffiliationExtension;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 18, 2014 2751 bclement Initial creation
* Feb 18, 2014 2751 bclement Initial creation
* Apr 15, 2014 2822 bclement added getAllSubscriptions()
*
* </pre>
*
@ -47,11 +57,14 @@ import com.raytheon.uf.common.xmpp.ext.ChangeAffiliationExtension;
*/
public class PubSubOperations {
public static final String PUBSUB_SUBDOMAIN_PREFIX = "pubsub.";
private PubSubOperations() {
}
/**
* Send packet to change affiliation of user on a pubsub topic node
* Send packet to change affiliation of user on a pubsub topic node. Calling
* client must be owner of node.
*
* @param conn
* @param affiliation
@ -59,12 +72,56 @@ public class PubSubOperations {
*/
public static void sendAffiliationPacket(XMPPConnection conn,
ChangeAffiliationExtension affiliation) throws XMPPException {
PubSub packet = new PubSub();
packet.setType(IQ.Type.SET);
packet.setTo("pubsub." + conn.getServiceName());
packet.setPubSubNamespace(PubSubNamespace.OWNER);
packet.addExtension(affiliation);
PubSub packet = createOwnerPacket(conn, affiliation, IQ.Type.SET);
SyncPacketSend.getReply(conn, packet);
}
/**
* List all subscriptions on node. Calling client must be owner of node.
*
* @param conn
* @param n
* @return
* @throws XMPPException
*/
public static List<Subscription> getAllSubscriptions(XMPPConnection conn,
Node n) throws XMPPException {
PubSubElementType type = PubSubElementType.SUBSCRIPTIONS;
/*
* we need to use the OWNER namespace when we make the request, but we
* reuse the provider (parser) for the default namespace for the return.
* Use the default namespace to get the extension object from the packet
*/
String namespace = type.getNamespace().getXmlns();
NodeExtension ext = new NodeExtension(type, n.getId());
PubSub packet = createOwnerPacket(conn, ext, Type.GET);
Packet reply = SyncPacketSend.getReply(conn, packet);
SubscriptionsExtension resp = (SubscriptionsExtension) reply
.getExtension(type.getElementName(), namespace);
if (resp == null){
throw new XMPPException(
"Subscriptions response missing content for topic: "
+ n.getId());
}
return resp.getSubscriptions();
}
/**
* Create pubsub packet object with owner namespace
*
* @param conn
* @param ext
* @param type
* @return
*/
private static PubSub createOwnerPacket(XMPPConnection conn,
NodeExtension ext, Type type) {
PubSub packet = new PubSub();
packet.setType(type);
packet.setTo(PUBSUB_SUBDOMAIN_PREFIX + conn.getServiceName());
packet.setPubSubNamespace(PubSubNamespace.OWNER);
packet.addExtension(ext);
return packet;
}
}

View file

@ -63,7 +63,12 @@ import com.raytheon.uf.viz.collaboration.comm.identity.user.SharedDisplayRole;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayload;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayload.PayloadType;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.account.ClientAuthManager;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.PeerToPeerCommHelper;
import com.raytheon.uf.viz.collaboration.comm.provider.event.LeaderChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager;
import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
@ -92,6 +97,10 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
* Mar 07, 2014 2848 bclement moved pubsub close logic to closePubSub()
* ensure that subscription is setup before joining room
* Mar 31, 2014 2899 mpduff Improve error messages.
* Apr 15, 2014 2822 bclement added check for other participants being subscribed to topic
* Apr 21, 2014 2822 bclement removed use of resources in topicSubscribers, added skipCache
* Apr 22, 2014 2903 bclement added connection test to closePubSub() method
* Apr 23, 2014 2822 bclement added formatInviteAddress()
*
* </pre>
*
@ -113,6 +122,8 @@ public class SharedDisplaySession extends VenueSession implements
private LeafNode topic;
private final Set<String> topicSubscribers = new HashSet<String>();
private XMPPConnection conn;
private boolean closed = false;
@ -503,21 +514,24 @@ public class SharedDisplaySession extends VenueSession implements
closePubSub();
}
/**
* clean up pub sub subscription and objects
*/
private void closePubSub() {
try {
if (pubsubMgr == null || topic == null || !topicExists()) {
return;
}
Subscription sub = findSubscription(getAccount());
if (sub == null) {
return;
}
topic.unsubscribe(sub.getJid(), sub.getId());
topic.removeItemDeleteListener(this);
topic.removeItemEventListener(this);
if (hasRole(SharedDisplayRole.SESSION_LEADER)) {
cleanUpHttpStorage(topic.getId());
pubsubMgr.deleteNode(topic.getId());
if (conn != null && conn.isConnected() && pubsubMgr != null
&& topic != null && topicExists()) {
Subscription sub = findSubscription(getAccount());
if (sub == null) {
return;
}
topic.unsubscribe(sub.getJid(), sub.getId());
topic.removeItemDeleteListener(this);
topic.removeItemEventListener(this);
if (hasRole(SharedDisplayRole.SESSION_LEADER)) {
cleanUpHttpStorage(topic.getId());
pubsubMgr.deleteNode(topic.getId());
}
}
topic = null;
pubsubMgr = null;
@ -621,6 +635,41 @@ public class SharedDisplaySession extends VenueSession implements
PubSubOperations.sendAffiliationPacket(conn, affiliation);
}
/**
* may return false positives if skipCache is set to false, won't return a
* false negative
*
* @param user
* @param skipCache
* if true, a list of current subscribers is always retrieved
* from the server
* @return return false if user doesn't have a subscription to the session
* topic
* @throws XMPPException
*/
private boolean isSubscribedToTopic(UserId user, boolean skipCache)
throws XMPPException {
boolean rval;
synchronized (topicSubscribers) {
rval = topicSubscribers.contains(user.getNormalizedId());
if (skipCache || !rval) {
topicSubscribers.clear();
List<Subscription> subs = PubSubOperations.getAllSubscriptions(
conn, topic);
for (Subscription sub : subs) {
/*
* we can't use the resource from the subscription here
* because the room user won't always have a resource
*/
UserId subber = IDConverter.convertFrom(sub.getJid());
topicSubscribers.add(subber.getNormalizedId());
}
rval = topicSubscribers.contains(user.getNormalizedId());
}
}
return rval;
}
@Override
public void changeLeader(VenueParticipant newLeader)
throws CollaborationException {
@ -634,6 +683,16 @@ public class SharedDisplaySession extends VenueSession implements
throw new CollaborationException(
"Unable to grant ownership because new leader's actual userid is not known");
}
/*
* leadership transfer must be sync'd between room ownership and topic
* ownership. If a user is in the room under multiple handles, we can't
* know for sure that this handle is associated with the same client
* that understands leadership and is subscribed to the pubsub topic
*/
if (hasMultipleHandles(actualId)) {
throw new CollaborationException(
"Unable to grant ownership because new leader is in the room under multiple handles");
}
final String newLeaderId = actualId.getNormalizedId();
@ -642,6 +701,16 @@ public class SharedDisplaySession extends VenueSession implements
boolean othersNotified = false;
String revokeTarget = null;
try {
/*
* make sure that the new leader is not just in the room, but also
* subscribed to the pubsub topic. Skip cache to handle participants
* who may have switched clients since that last time we cached
*/
if (!isSubscribedToTopic(actualId, true)) {
throw new CollaborationException(
"Unable to grant ownership because new leader is not subscribed to session topic");
}
// was formerly the data provider, so hand off pubsub ownership
grantTopicOwnership(newLeaderId);
topicOwnershipGranted = true;
@ -667,6 +736,8 @@ public class SharedDisplaySession extends VenueSession implements
// 'member' instead of just down to 'admin'
revokeTarget = "room";
muc.revokeAdmin(account.getNormalizedId());
// clear cache of topic subscribers
topicSubscribers.clear();
} catch (XMPPException e) {
if (!othersNotified) {
// transaction, attempt to roll back the ownership changes
@ -710,4 +781,54 @@ public class SharedDisplaySession extends VenueSession implements
return closed;
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.collaboration.comm.identity.ISharedDisplaySession
* #isSharedDisplayClient
* (com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant)
*/
@Override
public boolean isSharedDisplayClient(VenueParticipant participant) {
UserId actualId = getVenue().getParticipantUserid(participant);
boolean rval = false;
if (actualId != null) {
try {
rval = isSubscribedToTopic(actualId, false);
} catch (XMPPException e) {
log.error("Error checking if user is a shared display client",
e);
}
}
return rval;
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.collaboration.comm.provider.session.VenueSession#
* formatInviteAddress
* (com.raytheon.uf.viz.collaboration.comm.provider.user.UserId)
*/
@Override
protected String formatInviteAddress(UserId id) {
CollaborationConnection manager = getConnection();
ContactsManager cm = manager.getContactsManager();
String resource = cm.getSharedDisplayEnabledResource(id);
/*
* resource will be null if we can't find a resource that supports
* shared displays for this user
*/
String rval;
if (resource == null) {
rval = super.formatInviteAddress(id);
} else {
UserId newId = new UserId(id.getName(), id.getHost(), resource);
rval = newId.getFQName();
}
return rval;
}
}

View file

@ -56,6 +56,7 @@ import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayload;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayload.PayloadType;
import com.raytheon.uf.viz.collaboration.comm.provider.TextMessage;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.event.UserNicknameChangedEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.event.VenueParticipantEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.event.VenueUserEvent;
@ -105,6 +106,11 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
* Mar 07, 2014 2848 bclement added getVenueName() and hasOtherParticipants()
* moved muc close logic to closeMuc()
* handle is now set in constructor
* Apr 11, 2014 2903 bclement made constructor public b/c connection code moved packages
* Apr 16, 2014 3020 bclement added check for invited rooms in roomExistsOnServer()
* Apr 21, 2014 2822 bclement added hasMultipleHandles()
* Apr 22, 2014 2903 bclement added connection test to close method
* Apr 23, 2014 2822 bclement added formatInviteAddress()
*
*
* </pre>
@ -145,9 +151,8 @@ public class VenueSession extends BaseSession implements IVenueSession {
* @param container
* @param eventBus
*/
protected VenueSession(EventBus externalBus,
CollaborationConnection manager, String venueName, String handle,
String sessionId) {
public VenueSession(EventBus externalBus, CollaborationConnection manager,
String venueName, String handle, String sessionId) {
super(externalBus, manager, sessionId);
this.venueName = venueName;
this.handle = handle;
@ -158,8 +163,8 @@ public class VenueSession extends BaseSession implements IVenueSession {
* @param container
* @param eventBus
*/
protected VenueSession(EventBus externalBus,
CollaborationConnection manager, CreateSessionData data) {
public VenueSession(EventBus externalBus, CollaborationConnection manager,
CreateSessionData data) {
super(externalBus, manager);
this.venueName = data.getName();
this.handle = data.getHandle();
@ -189,7 +194,10 @@ public class VenueSession extends BaseSession implements IVenueSession {
muc.removeParticipantListener(participantListener);
participantListener = null;
}
muc.leave();
CollaborationConnection conn = getConnection();
if (conn != null && conn.isConnected()) {
muc.leave();
}
muc = null;
}
@ -218,7 +226,6 @@ public class VenueSession extends BaseSession implements IVenueSession {
SessionPayload payload = new SessionPayload(PayloadType.Invitation,
invite);
Message msg = new Message();
msg.setTo(id.getNormalizedId());
UserId user = getAccount();
msg.setFrom(user.getNormalizedId());
msg.setType(Type.normal);
@ -229,7 +236,17 @@ public class VenueSession extends BaseSession implements IVenueSession {
} else if (!StringUtils.isBlank(invite.getSubject())) {
reason = invite.getSubject();
}
muc.invite(msg, id.getNormalizedId(), reason);
muc.invite(msg, formatInviteAddress(id), reason);
}
/**
* format invite address for user
*
* @param id
* @return
*/
protected String formatInviteAddress(UserId id) {
return id.getNormalizedId();
}
/*
@ -431,10 +448,11 @@ public class VenueSession extends BaseSession implements IVenueSession {
public static boolean roomExistsOnServer(XMPPConnection conn, String roomId)
throws XMPPException {
String host = Tools.parseHost(roomId);
/* check for public rooms */
ServiceDiscoveryManager serviceDiscoveryManager = new ServiceDiscoveryManager(
conn);
DiscoverItems result = serviceDiscoveryManager.discoverItems(host);
for (Iterator<DiscoverItems.Item> items = result.getItems(); items
.hasNext();) {
DiscoverItems.Item item = items.next();
@ -442,6 +460,19 @@ public class VenueSession extends BaseSession implements IVenueSession {
return true;
}
}
/* check for private rooms that we have access to */
try {
MultiUserChat.getRoomInfo(conn, roomId);
/* getRoomInfo only returns if the room was found */
return true;
} catch (XMPPException e) {
/*
* getRoomInfo throws a 404 if the room does exist or is private and
* we don't have access. In either case, we can't say that the room
* exists
*/
}
return false;
}
@ -923,6 +954,25 @@ public class VenueSession extends BaseSession implements IVenueSession {
return rval;
}
/**
* the return value is only accurate if the actual userIDs of all
* participants can be seen by this client
*
* @param user
* @return true if the user is in the room under multiple handles
*/
protected boolean hasMultipleHandles(UserId user) {
int count = 0;
IVenue v = getVenue();
for (VenueParticipant p : v.getParticipants()) {
UserId other = v.getParticipantUserid(p);
if (other != null && user.isSameUser(other)) {
count += 1;
}
}
return count > 1;
}
/*
* (non-Javadoc)
*

View file

@ -0,0 +1,244 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider.user;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterListener;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Type;
import com.raytheon.uf.viz.collaboration.comm.identity.event.IRosterChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.event.RosterChangeType;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.event.RosterChangeEvent;
/**
* Keeps track of contacts and resource information. Responsible for sending out
* roster change events.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 22, 2014 2822 bclement Initial creation
* Apr 24, 2014 3070 bclement removed roster,
* RosterChangedEvent sends UserId not RosterEntry
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class ContactsListener implements RosterListener {
private final ContactsManager manager;
private final Map<String, List<ResourceInfo>> contactResources = new HashMap<String, List<ResourceInfo>>();
/**
* @param manager
* @param roster
*/
public ContactsListener(ContactsManager manager) {
this.manager = manager;
}
/*
* (non-Javadoc)
*
* @see
* org.jivesoftware.smack.RosterListener#presenceChanged(org.jivesoftware
* .smack.packet.Presence)
*/
@Override
public void presenceChanged(Presence presence) {
String fromId = presence.getFrom();
UserId u = IDConverter.convertFrom(fromId);
if (u != null) {
synchronized (contactResources) {
/* if they are logging out */
if (presence.getType() == Type.unavailable) {
processLogout(u);
} else {
processUpdate(u, presence);
}
}
RosterEntry entry = manager.getRosterEntry(u);
if (entry != null) {
post(entry);
}
IRosterChangeEvent event = new RosterChangeEvent(
RosterChangeType.PRESENCE, u, presence);
post(event);
}
}
/**
* Update contact resources when resource logs out. Must be externally
* synchronized
*
* @param uid
*/
private void processLogout(UserId uid) {
String bareId = uid.getNormalizedId();
List<ResourceInfo> resources = contactResources.get(bareId);
if (resources != null) {
String resource = uid.getResource();
Iterator<ResourceInfo> iterator = resources.iterator();
while (iterator.hasNext()) {
ResourceInfo next = iterator.next();
if (next.getResourceName().equalsIgnoreCase(resource)) {
iterator.remove();
}
}
if (resources.isEmpty()) {
contactResources.remove(bareId);
}
}
}
/**
* Update contact resources when resource changes (non-logout). Must be
* externally synchronized.
*
* @param uid
* @param presence
*/
private void processUpdate(UserId uid, Presence presence) {
String bareId = uid.getNormalizedId();
String resource = uid.getResource();
List<ResourceInfo> resources = contactResources.get(bareId);
if (resources == null) {
/* we don't expect a large number of clients per user */
resources = new ArrayList<ResourceInfo>(2);
contactResources.put(bareId, resources);
}
ResourceInfo oldInfo = null;
for (ResourceInfo ri : resources) {
if (ri.getResourceName().equalsIgnoreCase(resource)) {
oldInfo = ri;
}
}
/* update resource */
if (oldInfo == null) {
oldInfo = new ResourceInfo(resource, presence);
resources.add(oldInfo);
} else {
oldInfo.updateInfo(presence);
}
}
/*
* (non-Javadoc)
*
* @see
* org.jivesoftware.smack.RosterListener#entriesUpdated(java.util.Collection
* )
*/
@Override
public void entriesUpdated(Collection<String> addresses) {
send(addresses, RosterChangeType.MODIFY);
}
/*
* (non-Javadoc)
*
* @see
* org.jivesoftware.smack.RosterListener#entriesDeleted(java.util.Collection
* )
*/
@Override
public void entriesDeleted(Collection<String> addresses) {
send(addresses, RosterChangeType.DELETE);
}
/*
* (non-Javadoc)
*
* @see
* org.jivesoftware.smack.RosterListener#entriesAdded(java.util.Collection)
*/
@Override
public void entriesAdded(Collection<String> addresses) {
send(addresses, RosterChangeType.ADD);
}
/**
* Send event bus notification for roster
*
* @param addresses
* @param type
*/
private void send(Collection<String> addresses, RosterChangeType type) {
for (String addy : addresses) {
UserId entry = IDConverter.convertFrom(addy);
/*
* RosterChangeEvents can't use RosterEntry objects because DELETE
* events happen after the entry is removed from the server roster
*/
IRosterChangeEvent event = new RosterChangeEvent(type, entry);
post(event);
}
}
/**
* Post event to collaboration event bus
*
* @param event
*/
private void post(Object event) {
CollaborationConnection connection = CollaborationConnection
.getConnection();
connection.postEvent(event);
}
/**
* Get name of resource that supports shared displays for user
*
* @param user
* @return null if no resource found for user that supports shared displays
*/
public String getSharedDisplayEnabledResource(UserId user) {
String rval = null;
synchronized (contactResources) {
List<ResourceInfo> list = contactResources.get(user
.getNormalizedId());
if (list != null) {
for (ResourceInfo ri : list) {
if (ri.supportsSharedDisplays()) {
rval = ri.getResourceName();
break;
}
}
}
}
return rval;
}
}

View file

@ -47,8 +47,9 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.raytheon.uf.common.util.collections.UpdatingSet;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.IAccountManager;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
/**
* Manage contacts from local groups and roster on server
@ -71,6 +72,13 @@ import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConn
* Jan 30, 2014 2698 bclement removed unneeded nickname changed event
* Jan 31, 2014 2700 bclement added addToRoster, fixed add to group when in roster, but blocked
* Feb 3, 2014 2699 bclement fixed assumption that username search was exact
* Apr 11, 2014 2903 bclement moved roster listener from collaboration connection to here
* Apr 16, 2014 2981 bclement fixed NPE when cached shared group deleted on server
* Apr 23, 2014 2822 bclement moved roster listener to ContactsListener,
* added getSharedDisplayEnabledResource()
* Apr 24, 2014 3070 bclement added checks for empty groups, added isContact(),
* added sendContactRequest()
* fixed contact request logic in addToGroup()
*
* </pre>
*
@ -83,13 +91,15 @@ public class ContactsManager {
.getHandler(ContactsManager.class);
private final CollaborationConnection connection;
private final XMPPConnection xmpp;
private final UserSearch search;
private Map<String, String> localAliases;
private final ContactsListener contactsListener;
/**
* Cached view of shared groups list on openfire. Will only reach out to
* server if it hasn't updated in an hour. This will disable itself if there
@ -127,8 +137,11 @@ public class ContactsManager {
this.search = connection.createSearch();
localAliases = UserIdWrapper.readAliasMap();
this.xmpp = xmpp;
Roster roster = xmpp.getRoster();
this.contactsListener = new ContactsListener(this);
roster.addRosterListener(this.contactsListener);
}
/**
* Get groups that are managed by server. These are not modifiable from the
* client.
@ -141,7 +154,13 @@ public class ContactsManager {
Roster roster = getRoster();
for (String group : groups) {
RosterGroup rg = roster.getGroup(group);
rval.add(new SharedGroup(rg));
/*
* group will be null if it has been removed from server after
* cached in shared groups.
*/
if (rg != null && !rg.getEntries().isEmpty()) {
rval.add(new SharedGroup(rg));
}
}
return rval;
}
@ -161,7 +180,8 @@ public class ContactsManager {
} else {
rval = new ArrayList<RosterGroup>(groups.size());
for (RosterGroup group : groups) {
if (!shared.contains(group.getName())) {
if (!shared.contains(group.getName())
&& !group.getEntries().isEmpty()) {
rval.add(group);
}
}
@ -182,24 +202,14 @@ public class ContactsManager {
if (group == null) {
group = createGroup(groupName);
}
String id = user.getNormalizedId();
RosterEntry entry = group.getEntry(id);
if (entry != null) {
if (isBlocked(entry)) {
// entry is in roster, but we aren't subscribed. Request a
// subscription.
try {
connection.getAccountManager().sendPresence(user,
new Presence(Type.subscribe));
} catch (CollaborationException e) {
statusHandler.error("Problem subscribing to user", e);
}
} else {
statusHandler
.debug("Attempted to add user to group it was already in: "
+ id + " in " + groupName);
RosterEntry entry = getRosterEntry(user);
if (entry != null && isBlocked(entry)) {
/* entry is in roster, but we are blocked */
try {
sendContactRequest(user);
} catch (CollaborationException e) {
statusHandler.error("Problem subscribing to user", e);
}
return;
}
try {
addToGroup(group, user);
@ -208,8 +218,8 @@ public class ContactsManager {
}
} catch (XMPPException e) {
String msg = getGroupModInfo(e);
statusHandler.error("Problem adding user to group: " + id + " to "
+ group.getName() + ". " + msg, e);
statusHandler.error("Problem adding user to group: " + user
+ " to " + group.getName() + ". " + msg, e);
}
}
@ -272,19 +282,20 @@ public class ContactsManager {
*/
public void deleteFromGroup(String groupName, UserId user) {
RosterEntry entry = getRosterEntry(user);
if ( entry == null){
statusHandler.warn("Attempted to alter group for non-contact: " + user);
if (entry == null) {
statusHandler.warn("Attempted to alter group for non-contact: "
+ user);
return;
}
RosterGroup group = getRoster().getGroup(groupName);
if ( group != null){
if (group != null) {
deleteFromGroup(group, entry);
} else {
statusHandler.warn("Attempted to modify non-existent group: "
+ groupName);
}
}
/**
* Remove entry from group.
*
@ -299,12 +310,13 @@ public class ContactsManager {
}
} catch (XMPPException e) {
String msg = getGroupModInfo(e);
statusHandler.error("Problem removing entry from group: "
+ IDConverter.convertFrom(entry) + " from "
statusHandler.error(
"Problem removing entry from group: "
+ IDConverter.convertFrom(entry) + " from "
+ group.getName() + ". " + msg, e);
}
}
/**
* Attempt to get more information about group modification error. Returns
* an empty string if no extra information is found.
@ -350,8 +362,9 @@ public class ContactsManager {
public RosterGroup createGroup(String groupName) {
Roster roster = getRoster();
RosterGroup rval = roster.getGroup(groupName);
if ( rval != null){
statusHandler.debug("Attempted to create existing group: " + groupName);
if (rval != null) {
statusHandler.debug("Attempted to create existing group: "
+ groupName);
return rval;
}
rval = roster.createGroup(groupName);
@ -369,7 +382,7 @@ public class ContactsManager {
public void deleteGroup(String groupName) {
Roster roster = getRoster();
RosterGroup group = roster.getGroup(groupName);
if ( group == null){
if (group == null) {
statusHandler.warn("Attempted to delete non-existent group: "
+ groupName);
return;
@ -649,6 +662,7 @@ public class ContactsManager {
}
/**
*
* @param entry
* @return true if we are blocked from seeing updates from user in entry
*/
@ -679,6 +693,51 @@ public class ContactsManager {
return rval;
}
/**
*
* @param entry
* @return true if we can see updates from user in entry
*/
public static boolean isContact(RosterEntry entry) {
ItemType type = entry.getType();
return type != null
&& (type.equals(ItemType.both) || type.equals(ItemType.to));
}
/**
* @see #isContact(RosterEntry)
* @param id
* @return true if we can see updates from user
*/
public boolean isContact(UserId id) {
RosterEntry entry = getRosterEntry(id);
boolean rval = false;
if (entry != null) {
rval = isContact(entry);
}
return rval;
}
/**
* @see ContactsListener#getSharedDisplayEnabledResource(UserId)
* @param user
* @return
*/
public String getSharedDisplayEnabledResource(UserId user) {
return contactsListener.getSharedDisplayEnabledResource(user);
}
/**
* Send a contact request to user
*
* @param user
* @throws CollaborationException
*/
public void sendContactRequest(UserId user) throws CollaborationException {
IAccountManager manager = connection.getAccountManager();
manager.sendPresence(user, new Presence(Type.subscribe));
}
/**
* Listener interface for group update events
*/

View file

@ -0,0 +1,136 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider.user;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Mode;
import org.jivesoftware.smack.packet.Presence.Type;
/**
* Information for an XMPP resource (client ie pidgin)
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 22, 2014 2822 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class ResourceInfo {
public static final String VERSION_KEY = "urn:uf:viz:collaboration:version";
private final String resourceName;
private String collaborationVersion;
private Type lastType;
private Mode lastMode;
/**
* @param resourceName
* @param presence
*/
public ResourceInfo(String resourceName, Presence presence) {
this.resourceName = resourceName;
updateInfo(presence);
}
/**
* Update resource information from presence
*
* @param presence
*/
public void updateInfo(Presence presence) {
Object version = presence.getProperty(VERSION_KEY);
if (version != null) {
this.collaborationVersion = version.toString();
}
this.lastType = presence.getType();
this.lastMode = presence.getMode();
}
/**
* @return true if this resource supports shared displays
*/
public boolean supportsSharedDisplays() {
return this.collaborationVersion != null;
}
/**
* @return the resourceName
*/
public String getResourceName() {
return resourceName;
}
/**
* @return the collaborationVersion
*/
public String getCollaborationVersion() {
return collaborationVersion;
}
/**
* @param collaborationVersion
* the collaborationVersion to set
*/
public void setCollaborationVersion(String collaborationVersion) {
this.collaborationVersion = collaborationVersion;
}
/**
* @return the lastType
*/
public Type getLastType() {
return lastType;
}
/**
* @param lastType
* the lastType to set
*/
public void setLastType(Type lastType) {
this.lastType = lastType;
}
/**
* @return the lastMode
*/
public Mode getLastMode() {
return lastMode;
}
/**
* @param lastMode
* the lastMode to set
*/
public void setLastMode(Mode lastMode) {
this.lastMode = lastMode;
}
}

View file

@ -21,7 +21,6 @@ package com.raytheon.uf.viz.collaboration.comm.provider.user;
import javax.xml.bind.annotation.XmlRootElement;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
@ -40,6 +39,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.user.IUser;
* ------------ ---------- ----------- --------------------------
* Jan 29, 2014 bclement Initial creation
* Feb 13, 2014 2751 bclement no longer is a subclass of UserId
* Apr 22, 2014 3056 bclement made equals case insensitive
*
* </pre>
*
@ -131,12 +131,38 @@ public class VenueParticipant implements IUser {
if (!(obj instanceof VenueParticipant)) {
return false;
}
/*
* the xmpp server lower cases room names so we may get them back as
* lower case when we have them locally as upper/mixed case. Treat case
* insensitive.
*/
VenueParticipant other = (VenueParticipant) obj;
EqualsBuilder builder = new EqualsBuilder();
builder.append(handle, other.handle);
builder.append(host, other.host);
builder.append(room, other.room);
return builder.isEquals();
if (!stringFieldEquals(this.handle, other.handle)){
return false;
}
if (!stringFieldEquals(this.room, other.room)) {
return false;
}
if (!stringFieldEquals(this.host, other.host)) {
return false;
}
return true;
}
/**
* @param field
* @param other
* @return true if both arguments are null or arguments are equal ignoring
* case
*/
private boolean stringFieldEquals(String field, String other) {
boolean rval;
if (field == null) {
rval = other == null;
} else {
rval = field.equalsIgnoreCase(other);
}
return rval;
}
/**

View file

@ -37,6 +37,7 @@ import com.vividsolutions.jts.geom.Coordinate;
* ------------ ---------- ----------- --------------------------
* Apr 3, 2012 mnash Initial creation
* Jan 30, 2014 2698 bclement changed UserId to VenueParticipant
* May 05, 2014 3076 bclement added DISPOSE_ALL
*
* </pre>
*
@ -48,7 +49,7 @@ import com.vividsolutions.jts.geom.Coordinate;
public class CollaborationDrawingEvent {
public static enum CollaborationEventType {
DRAW, ERASE, REDO, UNDO, CLEAR, LOCK_USERS, UNLOCK_USERS, CLEAR_ALL, NEW_USER_ARRIVED;
DRAW, ERASE, REDO, UNDO, CLEAR, CLEAR_ALL, LOCK_USERS, UNLOCK_USERS, DISPOSE_ALL, NEW_USER_ARRIVED;
}
@DynamicSerializeElement

View file

@ -19,6 +19,9 @@
**/
package com.raytheon.uf.viz.collaboration.display.rsc.telestrator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -64,6 +67,8 @@ import com.vividsolutions.jts.geom.Coordinate;
* Jan 30, 2014 2698 bclement changed UserId to VenueParticipant
* Feb 13, 2014 2751 bclement VenueParticipant refactor
* Mar 18, 2014 2895 njensen Fix concurrent mod exception on dispose
* May 05, 2014 3076 bclement old CLEAR_ALL is now DISPOSE_ALL,
* added clearLayers() and getAllDrawingLayers()
*
* </pre>
*
@ -129,7 +134,7 @@ public class CollaborationDrawingResource extends
CollaborationDrawingEvent event = new CollaborationDrawingEvent(
resourceData.getDisplayId());
event.setUserName(myUser);
event.setType(CollaborationEventType.CLEAR_ALL);
event.setType(CollaborationEventType.DISPOSE_ALL);
sendEvent(event);
}
@ -205,6 +210,18 @@ public class CollaborationDrawingResource extends
}
}
/**
* Clear all drawing layers. Does not generate any collaboration events.
* This is not "undoable".
*/
private void clearLayers() {
synchronized (layerMap) {
for (DrawingToolLayer layer : layerMap.values()) {
layer.clearAllDrawingData();
}
}
}
/**
* @return the myUser
*/
@ -249,6 +266,23 @@ public class CollaborationDrawingResource extends
return null;
}
/**
* A collection of drawing layers for resource
*
* @return empty collection if there are no layers
*/
public Collection<DrawingToolLayer> getAllDrawingLayers() {
Collection<DrawingToolLayer> rval;
if (layerMap != null) {
synchronized (layerMap) {
rval = new ArrayList<DrawingToolLayer>(layerMap.values());
}
} else {
rval = Collections.emptyList();
}
return rval;
}
/*
* (non-Javadoc)
*
@ -377,9 +411,12 @@ public class CollaborationDrawingResource extends
case UNDO:
layer.undo();
break;
case CLEAR_ALL:
case DISPOSE_ALL:
disposeLayers();
break;
case CLEAR_ALL:
clearLayers();
break;
case NEW_USER_ARRIVED:
CollaborationDrawingToolLayer myLayer = (CollaborationDrawingToolLayer) getDrawingLayerFor(getMyUser());
InitialCollaborationData dataBundle = new InitialCollaborationData(

View file

@ -54,8 +54,8 @@ import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.viz.collaboration.comm.compression.CompressionUtil;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.ISharedDisplaySession;
import com.raytheon.uf.viz.collaboration.comm.provider.session.ClientAuthManager;
import com.raytheon.uf.viz.collaboration.comm.provider.session.PeerToPeerCommHelper;
import com.raytheon.uf.viz.collaboration.comm.provider.account.ClientAuthManager;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.PeerToPeerCommHelper;
import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
import com.raytheon.uf.viz.remote.graphics.Dispatcher;
import com.raytheon.uf.viz.remote.graphics.events.AbstractDispatchingObjectEvent;

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 B

View file

@ -35,7 +35,7 @@ import org.jivesoftware.smack.packet.RosterPacket.ItemType;
import com.raytheon.uf.viz.collaboration.comm.identity.info.SiteConfigInformation;
import com.raytheon.uf.viz.collaboration.comm.identity.user.IUser;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
/**
@ -52,6 +52,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
* Feb 13, 2014 2751 bclement made generic for IUsers
* Feb 13, 2014 2751 njensen Extracted getImageName() to allow overrides
* Feb 17, 2014 2751 bclement moved block image logic to roster specific code
* Apr 24, 2014 3070 bclement added pending contact icon
*
* </pre>
*
@ -103,6 +104,14 @@ public abstract class AbstractUserLabelProvider<T extends IUser> extends
return null;
}
String key = getImageName(user);
if (element instanceof RosterEntry) {
RosterEntry entry = (RosterEntry) element;
ItemStatus status = entry.getStatus();
if (status != null) {
/* status always indicates pending */
key = "pending";
}
}
if (imageMap.get(key) == null && !key.equals("")) {
imageMap.put(key, CollaborationUtils.getNodeImage(key));
@ -144,7 +153,8 @@ public abstract class AbstractUserLabelProvider<T extends IUser> extends
}
ItemStatus status = entry.getStatus();
if (status != null) {
text.append(status).append(" pending\n");
/* status always indicates pending */
text.append("Contact request pending\n");
}
}
// delete trailing newline

View file

@ -42,6 +42,7 @@ import com.raytheon.uf.viz.core.localization.HierarchicalPreferenceStore;
* Mar 1, 2012 rferrel Initial creation
* Feb 19, 2014 2631 mpduff Changed to use the HierarchicalPreferenceStore.
* Feb 20, 2014 2631 mpduff Need to set defaults here since we changed to use the HierarchicalPreferenceStore
* Apr 24, 2014 3070 bclement added default groupname to preference defaults
*
* </pre>
*
@ -126,6 +127,8 @@ public class Activator extends AbstractUIPlugin {
prefs.setDefault(CollabPrefConstants.DEFAULT_HANDLE,
CollabPrefConstants.HandleOption.USERNAME.name());
prefs.setDefault(CollabPrefConstants.CUSTOM_HANDLE, "");
prefs.setDefault(CollabPrefConstants.DEFAULT_GROUPNAME_PREF,
"Contacts");
}
return prefs;
}

View file

@ -37,7 +37,7 @@ import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.viz.ui.dialogs.CaveSWTDialog;

View file

@ -72,6 +72,7 @@ import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.plugin.AbstractUIPlugin;
@ -85,9 +86,8 @@ import com.google.common.eventbus.Subscribe;
import com.raytheon.uf.viz.collaboration.comm.identity.IVenueSession;
import com.raytheon.uf.viz.collaboration.comm.identity.event.IRosterChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.event.RosterChangeType;
import com.raytheon.uf.viz.collaboration.comm.provider.event.ServerDisconnectEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.event.UserPresenceChangedEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager.GroupListener;
import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter;
@ -119,10 +119,12 @@ import com.raytheon.uf.viz.collaboration.ui.data.AlertWordWrapper;
import com.raytheon.uf.viz.collaboration.ui.data.CollaborationGroupContainer;
import com.raytheon.uf.viz.collaboration.ui.data.SessionGroupContainer;
import com.raytheon.uf.viz.collaboration.ui.notifier.NotifierTools;
import com.raytheon.uf.viz.collaboration.ui.prefs.CollabPrefConstants;
import com.raytheon.uf.viz.collaboration.ui.session.AbstractSessionView;
import com.raytheon.uf.viz.core.VizApp;
import com.raytheon.uf.viz.core.icon.IconUtil;
import com.raytheon.viz.ui.views.CaveFloatingView;
import com.raytheon.viz.ui.views.CaveWorkbenchPageManager;
/**
* This class is the main view to display the user's information and allow the
@ -149,6 +151,8 @@ import com.raytheon.viz.ui.views.CaveFloatingView;
* Mar 05, 2014 2837 bclement separate rename action for groups, added more icons
* Mar 05, 2014 2798 mpduff Add getter for displayFeedAction.
* Mar 12, 2014 2632 mpduff Force group deletes from UI if last user is removed.
* Apr 11, 2014 2903 bclement login action changes, removed server disconnect listener,
* added static utility method to show view
*
* </pre>
*
@ -227,12 +231,11 @@ public class CollaborationGroupView extends CaveFloatingView implements
CollaborationConnection connection = CollaborationConnection
.getConnection();
if (connection == null) {
new LoginAction().run();
connection = CollaborationConnection.getConnection();
if (connection == null) {
if (!new LoginAction().login()) {
// user cancelled login
return;
}
connection = CollaborationConnection.getConnection();
}
createFilterText(parent);
@ -871,7 +874,7 @@ public class CollaborationGroupView extends CaveFloatingView implements
.getActivePage().getViewReferences()) {
IViewPart viewPart = ref.getView(false);
if (viewPart instanceof AbstractSessionView) {
((AbstractSessionView) viewPart).setAlertWords(Arrays
((AbstractSessionView<?>) viewPart).setAlertWords(Arrays
.asList(words.getAlertWords()));
}
}
@ -954,24 +957,32 @@ public class CollaborationGroupView extends CaveFloatingView implements
refreshUsersTreeViewerAsync(group);
}
@Subscribe
public void serverDisconnected(final ServerDisconnectEvent e) {
if (logOut == null) {
// we aren't logged in
return;
}
VizApp.runAsync(new Runnable() {
@Override
public void run() {
logOut.closeCollaboration();
}
});
}
/**
* @return the displayFeedAction
*/
public DisplayFeedAction getDisplayFeedAction() {
return displayFeedAction;
}
/**
* @see CaveWorkbenchPageManager#showView(String)
*
* @param initFeedView
* true if feed view should be initialized like this is the first
* time the view has been opened
* @throws PartInitException
*/
public static void showView(boolean initFeedView) throws PartInitException {
CollaborationGroupView view = (CollaborationGroupView) CaveWorkbenchPageManager
.getActiveInstance().showView(ID);
if (initFeedView) {
// if autojoin is selected (to join the default room)
if (Activator.getDefault().getPreferenceStore()
.getBoolean(CollabPrefConstants.AUTO_JOIN)) {
DisplayFeedAction action = view.getDisplayFeedAction();
action.setChecked(true);
action.run();
}
}
}
}

View file

@ -19,6 +19,9 @@
**/
package com.raytheon.uf.viz.collaboration.ui;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
@ -40,7 +43,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.event.ITextMessageEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.event.IVenueInvitationEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.user.IUser;
import com.raytheon.uf.viz.collaboration.comm.provider.TextMessage;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.ui.actions.PeerToPeerChatAction;
import com.raytheon.uf.viz.collaboration.ui.jobs.AwayTimeOut;
@ -70,6 +73,8 @@ import com.raytheon.viz.ui.views.CaveWorkbenchPageManager;
* Feb 13, 2014 2751 bclement messages return IUser instead of IQualifiedID
* Mar 06, 2014 2848 bclement moved SharedDisplaySessionMgr.joinSession call to InviteDialog
* Apr 08, 2014 2785 mpduff removed preference listener
* Apr 11, 2014 2903 bclement added disconnect handler
* Apr 24, 2014 2955 bclement ignore duplicate session invites
*
* </pre>
*
@ -88,6 +93,10 @@ public class ConnectionSubscriber {
private final AwayTimeOut awayTimeOut = new AwayTimeOut();
private final DisconnectHandler disconnect = new DisconnectHandler();
private final Set<String> pendingInviteDialogs = new HashSet<String>();
private ConnectionSubscriber() {
}
@ -124,6 +133,7 @@ public class ConnectionSubscriber {
new SubscriptionResponderImpl(connection));
// Register handlers and events for the new sessionManager.
connection.registerEventHandler(this);
connection.registerEventHandler(disconnect);
try {
ISession p2pSession = connection.getPeerToPeerSession();
p2pSession.registerEventHandler(this);
@ -159,11 +169,14 @@ public class ConnectionSubscriber {
awayTimeOut.cancel();
try {
ISession p2pSession = connection.getPeerToPeerSession();
p2pSession.unregisterEventHandler(this);
if (p2pSession != null) {
p2pSession.unregisterEventHandler(this);
}
} catch (CollaborationException e) {
statusHandler.handle(Priority.PROBLEM,
"Error unregistering peer to peer handler", e);
}
connection.unregisterEventHandler(disconnect);
connection.unregisterEventHandler(this);
}
PlatformUI.getWorkbench().removeWorkbenchListener(wbListener);
@ -171,16 +184,53 @@ public class ConnectionSubscriber {
@Subscribe
public void handleInvitationEvent(final IVenueInvitationEvent event) {
final String roomId = event.getRoomId().getFQName();
VizApp.runAsync(new Runnable() {
@Override
public void run() {
Shell shell = new Shell(Display.getCurrent());
InviteDialog inviteBox = new InviteDialog(shell, event);
if (!(Boolean) inviteBox.open()) {
return;
if (!invitePending(roomId)) {
try {
Shell shell = new Shell(Display.getCurrent());
InviteDialog inviteBox = new InviteDialog(shell, event);
if ((Boolean) inviteBox.open()) {
/* user accepted invite */
openSession(inviteBox);
}
} finally {
synchronized (pendingInviteDialogs) {
pendingInviteDialogs.remove(roomId);
}
}
} else {
statusHandler.debug("Ignoring duplicate session invite: "
+ roomId);
}
}
/**
* @param roomId
* @return true if there is already an invitation pending for this
* room
*/
private boolean invitePending(String roomId) {
synchronized (pendingInviteDialogs) {
boolean pending = pendingInviteDialogs.contains(roomId);
if (!pending) {
/* immediately set to pending to ignore dup invites */
pendingInviteDialogs.add(roomId);
}
return pending;
}
}
/**
* Open session view after invite has been accepted
*
* @param inviteBox
*/
private void openSession(InviteDialog inviteBox) {
try {
IVenueSession session = inviteBox.getSession();
if (inviteBox.isSharedDisplay()) {

View file

@ -25,15 +25,16 @@ import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
/**
@ -48,6 +49,7 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
* ------------ ---------- ----------- --------------------------
* Jun 27, 2012 bsteffen Initial creation
* Jan 24, 2014 2701 bclement removed local groups
* Apr 23, 2014 3040 lvenable Cleaned up dialog code/layout. Added check for group name.
*
* </pre>
*
@ -56,72 +58,122 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
*/
public class CreateGroupDialog extends CaveSWTDialog {
/** Name text field. */
private Text nameText;
/** New group name. */
private String newGroup = null;
/**
* Constructor.
*
* @param parentShell
* Parent shell.
*/
public CreateGroupDialog(Shell parentShell) {
super(parentShell, SWT.DIALOG_TRIM);
setText("Create Group");
}
@Override
protected Layout constructShellLayout() {
GridLayout mainLayout = new GridLayout(1, false);
return mainLayout;
}
@Override
protected Object constructShellLayoutData() {
return new GridData(SWT.FILL, SWT.DEFAULT, true, false);
}
@Override
protected void initializeComponents(Shell shell) {
Composite entryComp = new Composite(shell, SWT.NONE);
RowLayout layout = new RowLayout(SWT.HORIZONTAL);
layout.center = true;
entryComp.setLayout(layout);
entryComp.setLayout(new GridLayout(2, false));
entryComp
.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false));
new Label(entryComp, SWT.NONE).setText("Group Name: ");
nameText = new Text(entryComp, SWT.BORDER);
nameText.setLayoutData(new RowData(100, SWT.DEFAULT));
nameText.setLayoutData(new GridData(150, SWT.DEFAULT));
nameText.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
finish();
handleOkAction();
}
}
});
/*
* Action buttons
*/
Composite buttonComp = new Composite(shell, SWT.NONE);
buttonComp.setLayoutData(new GridData(SWT.RIGHT, SWT.NONE, false,
false, 1, 1));
layout = new RowLayout(SWT.HORIZONTAL);
layout.pack = false;
buttonComp.setLayout(layout);
buttonComp.setLayout(new GridLayout(2, false));
buttonComp.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true,
false));
GridData gd = new GridData(SWT.RIGHT, SWT.DEFAULT, true, false);
gd.widthHint = 75;
Button okButton = new Button(buttonComp, SWT.PUSH);
okButton.setText("OK");
okButton.setLayoutData(gd);
okButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
finish();
handleOkAction();
}
});
gd = new GridData(SWT.LEFT, SWT.DEFAULT, true, false);
gd.widthHint = 75;
Button cancelButton = new Button(buttonComp, SWT.PUSH);
cancelButton.setText("Cancel");
cancelButton.setLayoutData(gd);
cancelButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
close();
}
});
}
private void finish() {
/**
* Handle the OK action.
*/
private void handleOkAction() {
if (validGroupName() == false) {
return;
}
newGroup = nameText.getText();
CollaborationConnection.getConnection().getContactsManager()
.createGroup(newGroup);
close();
}
/**
* Check if there was something entered in the text field.
*
* @return True if there is text in the group name text field.
*/
private boolean validGroupName() {
if (nameText.getText().length() == 0) {
MessageBox mb = new MessageBox(shell, SWT.ICON_WARNING | SWT.OK);
mb.setText("Invalid Name");
mb.setMessage("You have not entered a group name. Please enter one.");
mb.open();
return false;
}
return true;
}
/**
* Get the group name.
*
* @return The group name.
*/
public String getNewGroup() {
return newGroup;
}
}

View file

@ -56,9 +56,9 @@ import com.raytheon.uf.viz.collaboration.comm.identity.ISharedDisplaySession;
import com.raytheon.uf.viz.collaboration.comm.identity.IVenueSession;
import com.raytheon.uf.viz.collaboration.comm.identity.user.SharedDisplayRole;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.PeerToPeerCommHelper;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CreateSessionData;
import com.raytheon.uf.viz.collaboration.comm.provider.session.PeerToPeerCommHelper;
import com.raytheon.uf.viz.collaboration.comm.provider.session.SharedDisplaySession;
import com.raytheon.uf.viz.collaboration.comm.provider.session.VenueSession;
import com.raytheon.uf.viz.collaboration.display.data.SharedDisplaySessionMgr;
@ -93,6 +93,8 @@ import com.raytheon.viz.ui.editor.IMultiPaneEditor;
* Feb 7, 2014 2699 bclement removed handle validation
* Feb 11, 2014 2699 bclement require non-blank handle
* Mar 06, 2014 2848 bclement moved session creation logic to separate method
* Apr 16, 2014 3021 bclement increased width of dialog
* Apr 22, 2014 3056 bclement made room name lowercase to match xmpp server
*
* </pre>
*
@ -138,7 +140,7 @@ public class CreateSessionDialog extends CaveSWTDialog {
label.setText("Name: ");
nameTF = new Text(body, SWT.BORDER);
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
gd.minimumWidth = 200;
gd.minimumWidth = 300;
nameTF.setLayoutData(gd);
VerifyListener validNameListener = new VerifyListener() {
@ -451,7 +453,11 @@ public class CreateSessionDialog extends CaveSWTDialog {
List<String> errorMessages = new ArrayList<String>();
String subject = subjectTF.getText().trim();
String err = validateVenueName();
String name = nameTF.getText();
/*
* xmpp server lowercases all room names, lowercase here to
* match when we get names back from the server
*/
String name = nameTF.getText().toLowerCase();
if (err != null) {
focusField = nameTF;
errorMessages.add(err);

View file

@ -0,0 +1,101 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.ui;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PartInitException;
import com.google.common.eventbus.Subscribe;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.event.ServerDisconnectEvent;
import com.raytheon.uf.viz.collaboration.ui.actions.LogoutAction;
import com.raytheon.uf.viz.collaboration.ui.login.LoginDialog;
import com.raytheon.uf.viz.core.VizApp;
/**
* Handles xmpp server disconnect events
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 11, 2014 2903 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class DisconnectHandler {
private static final String TITLE = "Disconnected from Collaboration Server";
private static final String DEFAULT_MESSAGE = "Click OK to re-login to the collaboration server";
/**
*
*/
public DisconnectHandler() {
}
/**
* Handle a disconnect from the xmpp server
*
* @param e
*/
@Subscribe
public void serverDisconnected(final ServerDisconnectEvent e) {
CollaborationConnection conn = CollaborationConnection.getConnection();
if (conn == null) {
// we aren't logged in
return;
}
VizApp.runAsync(new Runnable() {
@Override
public void run() {
/* close out existing collaboration components */
LogoutAction.closeCollaboration();
Shell shell = new Shell(Display.getCurrent());
StringBuilder msg = new StringBuilder();
String reason = e.getReason();
if (reason != null && !reason.isEmpty()) {
msg.append("Reason: ").append(reason).append('\n');
}
msg.append(DEFAULT_MESSAGE);
/* inform the user of disconnect then re-login if requested */
if (MessageDialog.openConfirm(shell, TITLE, msg.toString())
&& new LoginDialog(shell).login()) {
try {
/* user has logged back in, put the view back */
CollaborationGroupView.showView(true);
} catch (PartInitException e) {
Activator.statusHandler.error(
"Problem restoring collaboration view", e);
}
}
}
});
}
}

View file

@ -42,7 +42,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.invite.SharedDisplayVenue
import com.raytheon.uf.viz.collaboration.comm.identity.invite.VenueInvite;
import com.raytheon.uf.viz.collaboration.comm.identity.user.IUser;
import com.raytheon.uf.viz.collaboration.comm.identity.user.SharedDisplayRole;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.session.SharedDisplaySession;
import com.raytheon.uf.viz.collaboration.comm.provider.session.VenueSession;
import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueId;
@ -67,6 +67,7 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialogBase;
* Feb 13, 2014 2751 bclement better types for roomid and inviter
* Mar 06, 2014 2848 bclement moved join logic to separate method
* Mar 27, 2014 2632 mpduff Set the OK button as the default button.
* Apr 18, 2014 2955 mpduff Make dialog non-modal.
*
* </pre>
*
@ -105,18 +106,11 @@ public class InviteDialog extends CaveSWTDialogBase {
*
* @param parentShell
* Parent shell.
* @param title
* Title for the dialog.
* @param labelStr
* Test to put in the label for the message text control.
* @param messageStr
* Message to be displayed.
* @param iconStyle
* Icon style to be displayed.
* @param event
* The invitation event
*/
public InviteDialog(Shell parentShell, IVenueInvitationEvent event) {
super(parentShell, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL
| SWT.PRIMARY_MODAL | SWT.SYSTEM_MODAL, CAVE.NONE);
super(parentShell, SWT.DIALOG_TRIM, CAVE.NONE);
setText("Session Invitation");
IUser inviter = event.getInviter();
VenueId room = event.getRoomId();
@ -151,7 +145,7 @@ public class InviteDialog extends CaveSWTDialogBase {
@Override
protected void initializeComponents(Shell shell) {
mainComp = new Composite(shell, SWT.NONE);
GridLayout gl = new GridLayout(2, false);
GridLayout gl = new GridLayout(1, false);
gl.marginHeight = 0;
gl.marginWidth = 0;
gl.horizontalSpacing = 0;
@ -233,10 +227,10 @@ public class InviteDialog extends CaveSWTDialogBase {
font = new Font(Display.getCurrent(), fontData[0]);
}
if (heading) {
gd = new GridData(SWT.LEFT, SWT.NONE, false, false);
gd = new GridData(SWT.LEFT, SWT.CENTER, false, false);
label.setFont(font);
} else {
gd = new GridData(SWT.LEFT, SWT.NONE, true, true);
gd = new GridData(SWT.LEFT, SWT.CENTER, true, true);
gd.widthHint = 300;
}
label.setLayoutData(gd);
@ -250,16 +244,15 @@ public class InviteDialog extends CaveSWTDialogBase {
Composite actionButtonComp = new Composite(mainComp, SWT.NONE);
actionButtonComp.setLayout(new GridLayout(2, false));
GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
gd.horizontalSpan = 2;
actionButtonComp.setLayoutData(gd);
int btnWidth = 80;
gd = new GridData(SWT.RIGHT, SWT.DEFAULT, true, false);
gd.widthHint = btnWidth;
Button okBtn = new Button(actionButtonComp, SWT.PUSH);
okBtn.setText("Join");
okBtn.setLayoutData(gd);
okBtn.addSelectionListener(new SelectionAdapter() {
Button joinBtn = new Button(actionButtonComp, SWT.PUSH);
joinBtn.setText("Join");
joinBtn.setLayoutData(gd);
joinBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent se) {
String handle = handleText.getText().trim();
@ -294,7 +287,7 @@ public class InviteDialog extends CaveSWTDialogBase {
}
});
this.getShell().setDefaultButton(okBtn);
this.getShell().setDefaultButton(joinBtn);
}
/**
@ -340,6 +333,11 @@ public class InviteDialog extends CaveSWTDialogBase {
}
}
/**
* Get the IVenueSession being used.
*
* @return the IVenueSession
*/
public IVenueSession getSession() {
return session;
}

View file

@ -34,10 +34,11 @@ import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Shell;
import org.jivesoftware.smack.RosterGroup;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
/**
@ -54,6 +55,10 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
* Jan 31, 2014 2700 bclement don't prompt for group if user is already in one
* Feb 13, 2014 2755 bclement roster addition now done in account manager, user input passed back
* Apr 07, 2014 2785 mpduff Changed to implement CaveSWTDialog
* Fix loading of groups
* Apr 23, 2014 3040 lvenable Cleaned up dialog code/layout. Allow the cancellation of the create
* group dialog without closing this dialog. Added capability to resize
* the group combo box if the names get too long.
*
* </pre>
*
@ -61,12 +66,19 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
* @version 1.0
*/
public class SubRequestDialog extends CaveSWTDialog {
private final String NEW_GROUP = "New Group...";
/** User ID. */
private final String userid;
/** Combo listing all of the available groups. */
private Combo groupCbo;
/** Create group dialog. */
private CreateGroupDialog createGroupDlg;
/** Allow button. */
private Button allowBtn;
/**
* Constructor
*
@ -79,35 +91,70 @@ public class SubRequestDialog extends CaveSWTDialog {
setText("Contact Request");
}
@Override
protected Layout constructShellLayout() {
GridLayout mainLayout = new GridLayout(1, false);
return mainLayout;
}
@Override
protected Object constructShellLayoutData() {
return new GridData(SWT.FILL, SWT.DEFAULT, true, false);
}
@Override
protected void initializeComponents(Shell shell) {
GridLayout gl = new GridLayout(1, false);
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
Composite mainComp = new Composite(shell, SWT.NONE);
GridLayout gl = new GridLayout(1, false);
GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
mainComp.setLayout(gl);
mainComp.setLayoutData(gd);
/*
* Top Label
*/
gd = new GridData(SWT.CENTER, SWT.DEFAULT, true, false);
Label msgLbl = new Label(mainComp, SWT.NONE);
msgLbl.setText(userid + " wants to add you to their contacts list.");
msgLbl.setText(userid + " wants to add you to a contacts list:");
msgLbl.setLayoutData(gd);
gl = new GridLayout(2, false);
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
/*
* Group composite and controls.
*/
Composite groupComp = new Composite(mainComp, SWT.NONE);
gl = new GridLayout(3, false);
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
groupComp.setLayout(gl);
groupComp.setLayoutData(gd);
gd = new GridData(SWT.RIGHT, SWT.DEFAULT, true, false);
gd = new GridData(SWT.DEFAULT, SWT.CENTER, false, true);
Label groupLbl = new Label(groupComp, SWT.NONE);
groupLbl.setText("Group: ");
groupLbl.setLayoutData(gd);
gd = new GridData(SWT.FILL, SWT.CENTER, true, true);
gd.minimumWidth = 130;
groupCbo = new Combo(groupComp, SWT.DROP_DOWN | SWT.READ_ONLY);
groupCbo.setItems(getGroupNames());
groupCbo.select(0);
groupCbo.setLayout(gl);
groupCbo.setLayoutData(gd);
gd = new GridData();
gd.horizontalIndent = 5;
Button newGroup = new Button(groupComp, SWT.PUSH);
newGroup.setText("New Group...");
newGroup.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
handleNewGroupAction();
}
});
addSeparator(mainComp);
/*
* Action buttons.
*/
gl = new GridLayout(2, false);
gd = new GridData(SWT.CENTER, SWT.DEFAULT, true, false);
Composite btnComp = new Composite(mainComp, SWT.NONE);
@ -117,16 +164,21 @@ public class SubRequestDialog extends CaveSWTDialog {
int btnWidth = 75;
gd = new GridData(btnWidth, SWT.DEFAULT);
Button allowBtn = new Button(btnComp, SWT.PUSH);
allowBtn = new Button(btnComp, SWT.PUSH);
allowBtn.setText("Allow");
allowBtn.setLayoutData(gd);
allowBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
action(true);
handleAllowDenyAction(true);
}
});
// Disable the allow button if there are no items in the combo box.
if (groupCbo.getItemCount() == 0) {
allowBtn.setEnabled(false);
}
gd = new GridData(btnWidth, SWT.DEFAULT);
Button denyBtn = new Button(btnComp, SWT.PUSH);
denyBtn.setText("Deny");
@ -134,12 +186,14 @@ public class SubRequestDialog extends CaveSWTDialog {
denyBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
action(false);
handleAllowDenyAction(false);
}
});
}
/**
* Get the list of group names.
*
* @return list of existing group names
*/
private String[] getGroupNames() {
@ -148,36 +202,53 @@ public class SubRequestDialog extends CaveSWTDialog {
if (connection == null) {
return new String[0];
}
Collection<RosterGroup> groups = connection.getContactsManager()
Collection<RosterGroup> rosterGroups = connection.getContactsManager()
.getGroups();
List<String> groupList = new ArrayList<String>(groups.size());
for (String group : groupList) {
groupList.add(group);
List<String> groupList = new ArrayList<String>(rosterGroups.size());
for (RosterGroup group : rosterGroups) {
groupList.add(group.getName());
}
Collections.sort(groupList);
groupList.add(0, NEW_GROUP);
return groupList.toArray(new String[groupList.size()]);
}
/**
* Action handler.
*
* @param approved
* true if request approved, false if denied
* Handle adding a new group.
*/
private void action(boolean approved) {
if (approved) {
if (groupCbo.getSelectionIndex() == 0) {
// new group
CreateGroupDialog dialog = new CreateGroupDialog(Display
.getCurrent().getActiveShell());
dialog.open();
String group = dialog.getNewGroup();
setReturnValue(group);
} else {
private void handleNewGroupAction() {
if (createGroupDlg == null || createGroupDlg.isDisposed()) {
createGroupDlg = new CreateGroupDialog(Display.getCurrent()
.getActiveShell());
createGroupDlg.open();
String groupName = createGroupDlg.getNewGroup();
// If the group name is not null, add it to the combo and then
// select it.
if (groupName != null) {
allowBtn.setEnabled(true);
groupCbo.add(groupName, 0);
groupCbo.select(0);
shell.pack();
}
} else {
createGroupDlg.bringToTop();
}
}
/**
* Handle Allow/Deny action.
*
* @param allowRequest
* True if request allowed, false if denied
*/
private void handleAllowDenyAction(boolean allowRequest) {
if (allowRequest) {
if (groupCbo.getItemCount() != 0) {
setReturnValue(groupCbo.getItem(groupCbo.getSelectionIndex()));
} else {
}
} else {
setReturnValue(null);
@ -185,4 +256,19 @@ public class SubRequestDialog extends CaveSWTDialog {
close();
}
/**
* Add a line separator to the given composite.
*
* @param parentComp
* Parent composite.
*/
private void addSeparator(Composite parentComp) {
GridLayout gl = (GridLayout) parentComp.getLayout();
GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
gd.horizontalSpan = gl.numColumns;
Label sepLbl = new Label(parentComp, SWT.SEPARATOR | SWT.HORIZONTAL);
sepLbl.setLayoutData(gd);
}
}

View file

@ -54,7 +54,7 @@ import org.jivesoftware.smack.XMPPException;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserSearch;
import com.raytheon.uf.viz.collaboration.ui.actions.AddToGroupAction;

View file

@ -31,8 +31,7 @@ import org.eclipse.jface.viewers.ViewerFilter;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterGroup;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.SharedGroup;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.ui.data.CollaborationGroupContainer;
@ -51,6 +50,7 @@ import com.raytheon.uf.viz.collaboration.ui.data.SessionGroupContainer;
* Dec 6, 2013 2561 bclement removed ECF
* Jan 24, 2014 2701 bclement removed local groups, added shared groups
* Jan 27, 2014 2700 bclement added support roster entries
* Apr 24, 2014 3070 bclement removed check for hasInteraction() from group entries
*
* </pre>
*
@ -141,8 +141,7 @@ public class UsersTreeContentProvider implements ITreeContentProvider {
UserId localUser = connection.getUser();
for (RosterEntry entry : entries) {
String user = entry.getUser();
if (!localUser.isSameUser(user)
&& ContactsManager.hasInteraction(entry)) {
if (!localUser.isSameUser(user)) {
result.add(entry);
}
}

View file

@ -38,7 +38,7 @@ import org.jivesoftware.smack.packet.Presence;
import com.raytheon.uf.viz.collaboration.comm.identity.IVenueSession;
import com.raytheon.uf.viz.collaboration.comm.identity.info.IVenue;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager;
import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter;
import com.raytheon.uf.viz.collaboration.comm.provider.user.SharedGroup;

View file

@ -30,8 +30,8 @@ import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterGroup;
import com.raytheon.uf.viz.collaboration.comm.identity.event.RosterChangeType;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.event.RosterChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager;
import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
@ -51,6 +51,7 @@ import com.raytheon.uf.viz.core.icon.IconUtil;
* Jul 3, 2012 bsteffen Initial creation
* Dec 20, 2013 2563 bclement added support for ungrouped roster entries
* Jan 24, 2014 2701 bclement removed local groups
* Apr 24, 2014 3070 bclement RosterChangeEvent changes
*
* </pre>
*
@ -114,8 +115,9 @@ public class AddToGroupAction extends Action {
if (entry != null) {
// the entry wasn't in a group, so the entire tree needs to be
// refreshed
UserId entryId = IDConverter.convertFrom(entry);
connection.postEvent(new RosterChangeEvent(RosterChangeType.MODIFY,
entry));
entryId));
}
}

View file

@ -27,7 +27,7 @@ import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.collaboration.comm.identity.IVenueSession;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.session.SessionMsgArchive;

View file

@ -26,7 +26,7 @@ import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FontDialog;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.core.icon.IconUtil;

View file

@ -26,7 +26,7 @@ import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.ui.ChangePasswordDialog;
/**

View file

@ -33,7 +33,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.info.SiteConfigInformation;
import com.raytheon.uf.viz.collaboration.comm.identity.info.SiteConfigInformation.SiteConfig;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.ui.SiteConfigurationManager;
/**

View file

@ -33,7 +33,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.info.SiteConfigInformation;
import com.raytheon.uf.viz.collaboration.comm.identity.info.SiteConfigInformation.SiteConfig;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.ui.SiteConfigurationManager;
import com.raytheon.uf.viz.collaboration.ui.session.SubscribeList;

View file

@ -33,7 +33,7 @@ import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.CollaborationUtils;
import com.raytheon.uf.viz.core.icon.IconUtil;

View file

@ -28,7 +28,7 @@ import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.login.ChangeStatusDialog;
import com.raytheon.uf.viz.collaboration.ui.prefs.CollabPrefConstants;

View file

@ -28,11 +28,8 @@ import org.eclipse.ui.PartInitException;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.ui.CollaborationGroupView;
import com.raytheon.uf.viz.collaboration.ui.prefs.CollabPrefConstants;
import com.raytheon.viz.ui.views.CaveWorkbenchPageManager;
/**
* Action to open the group view, as well as the default chat room
@ -45,6 +42,7 @@ import com.raytheon.viz.ui.views.CaveWorkbenchPageManager;
* ------------ ---------- ----------- --------------------------
* Mar 1, 2012 rferrel Initial creation
* Mar 05, 2014 2798 mpduff Don't create a new DisplayFeedAction
* Apr 11, 2014 2903 bclement moved collaboration view init to CollaborationGroupView
*
* </pre>
*
@ -62,27 +60,12 @@ public class CollaborationGroupAction extends AbstractHandler {
// If connection is null then user has not logged in
boolean initialExecutionFlag = CollaborationConnection
.getConnection() == null;
new LoginAction().run();
CollaborationConnection connection = CollaborationConnection
.getConnection();
if (connection == null) {
if (!new LoginAction().login()) {
// user cancelled login
return event;
}
CollaborationGroupView view = (CollaborationGroupView) CaveWorkbenchPageManager
.getActiveInstance().showView(CollaborationGroupView.ID);
// Is this is the first log in
if (initialExecutionFlag) {
// if autojoin is selected (to join the default room)
if (Activator.getDefault().getPreferenceStore()
.getBoolean(CollabPrefConstants.AUTO_JOIN)) {
DisplayFeedAction action = view.getDisplayFeedAction();
action.setChecked(true);
action.run();
}
}
CollaborationGroupView.showView(initialExecutionFlag);
} catch (PartInitException e) {
statusHandler.handle(Priority.PROBLEM,
"Unable to open collaboration contact list", e);

View file

@ -22,7 +22,7 @@ package com.raytheon.uf.viz.collaboration.ui.actions;
import org.eclipse.jface.action.Action;
import org.eclipse.swt.widgets.Display;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.CreateGroupDialog;

View file

@ -29,7 +29,7 @@ import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.collaboration.comm.identity.IVenueSession;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CreateSessionData;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.ui.Activator;

View file

@ -21,7 +21,7 @@ package com.raytheon.uf.viz.collaboration.ui.actions;
import org.eclipse.jface.action.Action;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.core.icon.IconUtil;

View file

@ -40,7 +40,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.ISession;
import com.raytheon.uf.viz.collaboration.comm.identity.IVenueSession;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.session.VenueSession;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.prefs.HandleUtil;

View file

@ -42,7 +42,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.ISharedDisplaySession;
import com.raytheon.uf.viz.collaboration.comm.identity.IVenueSession;
import com.raytheon.uf.viz.collaboration.comm.identity.invite.SharedDisplayVenueInvite;
import com.raytheon.uf.viz.collaboration.comm.identity.invite.VenueInvite;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
import com.raytheon.uf.viz.collaboration.display.data.SharedDisplaySessionMgr;

View file

@ -32,7 +32,7 @@ import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import com.raytheon.uf.viz.collaboration.comm.identity.ISharedDisplaySession;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.display.IRemoteDisplayContainer;
import com.raytheon.uf.viz.collaboration.display.editor.ICollaborationEditor;
import com.raytheon.uf.viz.collaboration.display.roles.dataprovider.SharedEditorsManager;

View file

@ -23,7 +23,7 @@ import org.eclipse.jface.action.Action;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.login.LoginDialog;
import com.raytheon.uf.viz.core.icon.IconUtil;
@ -38,6 +38,7 @@ import com.raytheon.uf.viz.core.icon.IconUtil;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jul 11, 2012 bsteffen Initial creation
* Apr 11, 2014 2903 bclement added success flag
*
* </pre>
*
@ -46,6 +47,8 @@ import com.raytheon.uf.viz.core.icon.IconUtil;
*/
public class LoginAction extends Action {
private boolean success = false;
public LoginAction() {
super("Login...", IconUtil.getImageDescriptor(Activator.getDefault()
@ -62,9 +65,24 @@ public class LoginAction extends Action {
if (shell == null) {
return;
}
LoginDialog dlg = new LoginDialog(shell);
dlg.open();
success = new LoginDialog(shell).login();
}
}
/**
* @return the success
*/
public boolean isSuccess() {
return success;
}
/**
* Convenience method to run action and return results
*
* @return true if login was successful
*/
public boolean login() {
this.run();
return isSuccess();
}
}

View file

@ -34,7 +34,7 @@ import org.eclipse.ui.PlatformUI;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.CollaborationGroupView;
import com.raytheon.uf.viz.collaboration.ui.ConnectionSubscriber;
@ -54,6 +54,7 @@ import com.raytheon.viz.ui.views.CaveWorkbenchPageManager;
* ------------ ---------- ----------- --------------------------
* Jul 11, 2012 bsteffen Initial creation
* Dec 19, 2013 2563 bclement moved close logic to public method
* Apr 11, 2014 2903 bclement made close method static, added safety check
*
* </pre>
*
@ -90,7 +91,7 @@ public class LogoutAction extends Action {
* Close collaboration UI and close connection
*
*/
public void closeCollaboration() {
public static void closeCollaboration() {
for (IViewReference ref : CaveWorkbenchPageManager.getActiveInstance()
.getViewReferences()) {
IViewPart view = ref.getView(false);
@ -118,8 +119,10 @@ public class LogoutAction extends Action {
}
CollaborationConnection connection = CollaborationConnection
.getConnection();
ConnectionSubscriber.unsubscribe(connection);
connection.close();
if (connection != null) {
ConnectionSubscriber.unsubscribe(connection);
connection.close();
}
}
}

View file

@ -28,7 +28,7 @@ import org.jivesoftware.smack.packet.Presence.Type;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.session.PeerToPeerView;

View file

@ -21,7 +21,7 @@ package com.raytheon.uf.viz.collaboration.ui.actions;
import org.eclipse.jface.action.Action;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.ui.Activator;

View file

@ -23,9 +23,11 @@ import org.eclipse.jface.action.Action;
import org.jivesoftware.smack.RosterEntry;
import com.raytheon.uf.viz.collaboration.comm.identity.event.RosterChangeType;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.event.RosterChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager;
import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.core.icon.IconUtil;
@ -40,6 +42,7 @@ import com.raytheon.uf.viz.core.icon.IconUtil;
* ------------ ---------- ----------- --------------------------
* Dec 20, 2013 2563 bclement Initial creation
* Mar 05, 2014 2837 bclement changed wording from Roster to Contacts, added image
* Apr 24, 2014 3070 bclement RosterChangeEvent changes
*
* </pre>
*
@ -64,7 +67,8 @@ public class RemoveFromRosterAction extends Action {
ContactsManager manager = connection
.getContactsManager();
manager.removeFromRoster(entry);
UserId entryId = IDConverter.convertFrom(entry);
connection.postEvent(new RosterChangeEvent(RosterChangeType.DELETE,
entry));
entryId));
}
}

View file

@ -21,12 +21,10 @@ package com.raytheon.uf.viz.collaboration.ui.actions;
import org.eclipse.jface.action.Action;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Type;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.IAccountManager;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager;
import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.core.icon.IconUtil;
@ -42,6 +40,7 @@ import com.raytheon.uf.viz.core.icon.IconUtil;
* ------------ ---------- ----------- --------------------------
* Jan 24, 2014 bclement Initial creation
* Mar 05, 2014 2837 bclement added image
* Apr 24, 2014 3070 bclement moved contact request logic to contacts manager
*
* </pre>
*
@ -71,10 +70,9 @@ public class SendSubReqAction extends Action {
@Override
public void run() {
CollaborationConnection connection = CollaborationConnection.getConnection();
IAccountManager manager = connection.getAccountManager();
ContactsManager manager = connection.getContactsManager();
try {
manager.sendPresence(IDConverter.convertFrom(entry), new Presence(
Type.subscribe));
manager.sendContactRequest(IDConverter.convertFrom(entry));
} catch (CollaborationException e) {
Activator.statusHandler.error(
"Unable to send subscription request", e);

View file

@ -22,7 +22,7 @@ package com.raytheon.uf.viz.collaboration.ui.actions;
import org.eclipse.jface.action.Action;
import org.eclipse.swt.widgets.Display;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.UserSearchDialog;
import com.raytheon.uf.viz.core.icon.IconUtil;

View file

@ -23,7 +23,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager;
/**

View file

@ -26,7 +26,7 @@ import java.util.List;
import com.raytheon.uf.viz.collaboration.comm.identity.ISession;
import com.raytheon.uf.viz.collaboration.comm.identity.IVenueSession;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
/**
* Retrieve session objects from contacts list

View file

@ -51,7 +51,9 @@ import com.raytheon.viz.ui.panes.VizDisplayPane;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 7, 2012 mschenke Initial creation
* Jun 07, 2012 mschenke Initial creation
* Apr 23, 2014 3060 njensen Safety checks for SWT widgets disposed
* May 01, 2014 2956 njensen More safety checks for SWT widgets disposed
*
* </pre>
*
@ -179,11 +181,14 @@ public class CollaborationPaneManager extends PaneManager {
setExclude(activeData, true);
activeData = null;
}
noDisplayLabel.setVisible(true);
((GridData) noDisplayLabel.getLayoutData()).exclude = false;
composite.layout();
if (!noDisplayLabel.isDisposed() && !composite.isDisposed()) {
noDisplayLabel.setVisible(true);
((GridData) noDisplayLabel.getLayoutData()).exclude = false;
composite.layout();
}
}
@Override
protected void adjustPaneLayout(int paneCount) {
;// don't do anything, we always want one pane displayed.
}
@ -238,7 +243,9 @@ public class CollaborationPaneManager extends PaneManager {
public void setCanvasSize(IRenderableDisplay display, Rectangle bounds) {
DisplayData data = displayMap.get(display);
if (data == null) {
if (data == null || data.canvasComp.isDisposed()
|| data.scrollable.isDisposed()
|| data.wrapperComp.isDisposed()) {
return;
}
data.canvasBounds = bounds;
@ -269,9 +276,11 @@ public class CollaborationPaneManager extends PaneManager {
}
private void setExclude(DisplayData data, boolean exclude) {
GridData gd = (GridData) data.scrollable.getLayoutData();
data.scrollable.setVisible(!exclude);
gd.exclude = exclude;
if (!data.scrollable.isDisposed()) {
GridData gd = (GridData) data.scrollable.getLayoutData();
data.scrollable.setVisible(!exclude);
gd.exclude = exclude;
}
}
}

View file

@ -36,7 +36,7 @@ import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.prefs.CollabPrefConstants;

View file

@ -52,8 +52,9 @@ import com.raytheon.uf.viz.collaboration.comm.identity.info.SiteConfigInformatio
import com.raytheon.uf.viz.collaboration.comm.identity.info.SiteConfigInformation.HostConfig;
import com.raytheon.uf.viz.collaboration.comm.identity.info.SiteConfigInformation.SiteConfig;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnectionData;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnectionData;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ResourceInfo;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.CollaborationUtils;
import com.raytheon.uf.viz.collaboration.ui.ConnectionSubscriber;
@ -75,6 +76,9 @@ import com.raytheon.uf.viz.collaboration.ui.prefs.CollabPrefConstants;
* Jan 08, 2014 2563 bclement added Add/Remove buttons for server list
* Jan 15, 2014 2630 bclement connection data stores status as Mode object
* Apr 07, 2014 2785 mpduff Implemented change to CollaborationConnection
* Apr 11, 2014 2903 bclement added success flag, moved login logic to static method
* fixed populating server with previous, removed password from heap
* Apr 23, 2014 2822 bclement added version to initial presence
*
* </pre>
*
@ -110,6 +114,8 @@ public class LoginDialog extends Dialog {
private Shell shell;
private boolean success = false;
/**
* @param parentShell
*/
@ -179,10 +185,11 @@ public class LoginDialog extends Dialog {
Iterator<HostConfig> iter = Iterators.concat(siteServers.iterator(),
userServers.iterator());
int index = 0;
String prevServer = loginData.getServer();
for (int i = 0; iter.hasNext() && i < names.length; i++) {
HostConfig config = iter.next();
names[i] = config.toString();
if (loginData.getServer().equals(names[i])) {
if (config.getHostname().equals(prevServer)) {
index = i;
}
}
@ -320,7 +327,7 @@ public class LoginDialog extends Dialog {
@Override
public void widgetSelected(SelectionEvent event) {
loginData.setUserName(userText.getText().trim());
loginData.setPassword(passwordText.getText().trim());
String password = passwordText.getText().trim();
loginData.setServer(HostConfig.removeDescription(serverText
.getText()));
loginData.setStatus(CollaborationUtils.parseMode(statusCombo
@ -347,7 +354,7 @@ public class LoginDialog extends Dialog {
}
loginData.setServer(server);
if (loginData.getPassword().isEmpty()) {
if (password.isEmpty()) {
errorMessages.add("Must enter a password.");
}
@ -365,38 +372,10 @@ public class LoginDialog extends Dialog {
messageBox.setMessage(sb.toString());
messageBox.open();
} else {
try {
// Create the connection
CollaborationConnection collabConnection = CollaborationConnection
.createConnection(loginData);
// Subscribe to the collaboration connection
ConnectionSubscriber.subscribe(collabConnection);
// Connect to the XMPP server
collabConnection.connect();
success = login(loginData, password);
if (success) {
storeLoginData();
shell.dispose();
// send initial presence
Mode mode = loginData.getStatus();
if (mode == null) {
mode = Mode.available;
}
Presence initialPresence = new Presence(Type.available,
loginData.getMessage(), 0, mode);
Tools.setProperties(initialPresence,
loginData.getAttributes());
collabConnection.getAccountManager().sendPresence(
initialPresence);
} catch (CollaborationException e) {
Activator.statusHandler.handle(Priority.PROBLEM,
"Error connecting to collaboration server: "
+ e.getLocalizedMessage(), e);
}
}
}
@ -414,6 +393,62 @@ public class LoginDialog extends Dialog {
});
}
/**
* Attempt to login to xmpp server.
*
* @param loginData
* @param password
* @return true if login was successful
*/
public static boolean login(CollaborationConnectionData loginData,
String password) {
CollaborationConnection collabConnection = null;
boolean rval = false;
boolean subscribed = false;
try {
// Create the connection
collabConnection = CollaborationConnection
.createConnection(loginData);
// Subscribe to the collaboration connection
ConnectionSubscriber.subscribe(collabConnection);
subscribed = true;
// Login to the XMPP server
collabConnection.login(password);
/* login was success, other errors are recoverable */
rval = true;
// send initial presence
Mode mode = loginData.getStatus();
if (mode == null) {
mode = Mode.available;
}
Presence initialPresence = new Presence(Type.available,
loginData.getMessage(), 0, mode);
Tools.setProperties(initialPresence, loginData.getAttributes());
initialPresence.setProperty(ResourceInfo.VERSION_KEY,
CollaborationConnection.getCollaborationVersion());
collabConnection.getAccountManager().sendPresence(initialPresence);
} catch (CollaborationException e) {
if (subscribed && collabConnection != null) {
ConnectionSubscriber.unsubscribe(collabConnection);
}
String msg;
if (rval) {
msg = "Error sending initial presence to collaboration server";
} else {
msg = "Error connecting to collaboration server: "
+ e.getLocalizedMessage();
}
Activator.statusHandler.handle(Priority.PROBLEM, msg, e);
}
return rval;
}
private void storeLoginData() {
preferences.setValue(CollabPrefConstants.P_USERNAME,
loginData.getUserName());
@ -435,4 +470,21 @@ public class LoginDialog extends Dialog {
loginData.setMessage(preferences
.getString(CollabPrefConstants.P_MESSAGE));
}
/**
* @return the success
*/
public boolean isSuccess() {
return success;
}
/**
* Convenience method to open dialog and return true if login was successful
*
* @return
*/
public boolean login() {
open();
return isSuccess();
}
}

View file

@ -46,7 +46,7 @@ import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.util.FileUtil;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.core.sounds.SoundUtil;

View file

@ -34,6 +34,7 @@ package com.raytheon.uf.viz.collaboration.ui.prefs;
* Feb 3, 2014 2699 bclement added handle preferences
* Feb 18, 2014 2631 mpduff Add constants for room change events.
* Mar 24, 2014 2936 mpduff Remove INCLUDE_NWS_FEED_FIELD_EDITOR_ID.
* Apr 24, 2014 3070 bclement added DEFAULT_GROUPNAME_PREF
*
* </pre>
*
@ -62,6 +63,8 @@ public class CollabPrefConstants {
public static final String CUSTOM_HANDLE = "customHandle";
public static final String DEFAULT_GROUPNAME_PREF = "defaultGroupName";
public static final int AWAY_TIMEOUT_DEFAULT = 10; // ten minutes
/** Enable join events field editor id */

View file

@ -50,7 +50,7 @@ import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType;
import com.raytheon.uf.common.localization.LocalizationFile;
import com.raytheon.uf.common.localization.PathManager;
import com.raytheon.uf.common.localization.PathManagerFactory;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.CollaborationUtils;
import com.raytheon.uf.viz.collaboration.ui.data.AlertWord;

View file

@ -28,7 +28,7 @@ import org.eclipse.jface.preference.StringFieldEditor;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.prefs.CollabPrefConstants.HandleOption;

View file

@ -43,7 +43,7 @@ import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterGroup;
import com.google.common.collect.Lists;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager;
import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter;
import com.raytheon.uf.viz.collaboration.comm.provider.user.SharedGroup;

View file

@ -29,7 +29,7 @@ import org.jivesoftware.smack.packet.Presence;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.viz.collaboration.comm.identity.info.SiteConfigInformation;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserSearch;
import com.raytheon.uf.viz.collaboration.ui.Activator;

View file

@ -19,7 +19,6 @@
**/
package com.raytheon.uf.viz.collaboration.ui.prefs;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@ -27,15 +26,15 @@ import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jface.preference.IPersistentPreferenceStore;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.jivesoftware.smack.RosterGroup;
import org.jivesoftware.smack.XMPPException;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.viz.collaboration.comm.identity.roster.ISubscriptionResponder;
import com.raytheon.uf.viz.collaboration.comm.identity.roster.SubscriptionResponse;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.session.ISubscriptionRequestCompleteAction;
import com.raytheon.uf.viz.collaboration.comm.provider.account.ISubscriptionRequestCompleteAction;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserSearch;
import com.raytheon.uf.viz.collaboration.ui.Activator;
@ -52,6 +51,8 @@ import com.raytheon.uf.viz.core.VizApp;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 03, 2014 2785 mpduff Initial creation
* Apr 24, 2014 3070 bclement added default group for auto accept
* fixed auto accept known contacts
*
* </pre>
*
@ -88,15 +89,16 @@ public class SubscriptionResponderImpl implements ISubscriptionResponder {
.getPreferenceStore();
if (prefs.getBoolean(CollabPrefConstants.AUTO_ACCEPT_SUBSCRIBE)) {
rval.setAccepted(true);
rval.setGroup(prefs
.getString(CollabPrefConstants.DEFAULT_GROUPNAME_PREF));
action.executeSubscriptionRequestComplete(fromID, rval);
return;
}
CollaborationConnection conn = CollaborationConnection.getConnection();
Collection<RosterGroup> groups = conn.getContactsManager().getGroups(
fromID);
if (!groups.isEmpty()) {
// we already have this user in a group in our roster
ContactsManager cm = conn.getContactsManager();
if (cm.isContact(fromID)) {
/* we already have a subscription to this user */
rval.setAccepted(true);
action.executeSubscriptionRequestComplete(fromID, rval);
} else {

View file

@ -57,7 +57,7 @@ import com.google.common.eventbus.Subscribe;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.raytheon.uf.viz.collaboration.comm.identity.IMessage;
import com.raytheon.uf.viz.collaboration.comm.identity.user.IUser;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.CollaborationUtils;

View file

@ -21,6 +21,7 @@ package com.raytheon.uf.viz.collaboration.ui.session;
**/
import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;
@ -100,6 +101,8 @@ import com.raytheon.viz.ui.input.EditableManager;
* Mar 06, 2014 2848 bclement moved colormanager update code to session container
* Mar 11, 2014 2865 lvenable Added null checks in threads
* Mar 18, 2014 2895 njensen Fix lockAction enable/disable logic
* Apr 15, 2014 2822 bclement only allow transfer leader if participant is using shared display
* May 05, 2014 3076 bclement added clear all action
*
* </pre>
*
@ -139,6 +142,8 @@ public class CollaborationSessionView extends SessionView implements
private ActionContributionItem lockAction;
private ActionContributionItem clearAllAction;
private ControlContribution noEditorAction;
private ISharedDisplaySession session;
@ -180,6 +185,21 @@ public class CollaborationSessionView extends SessionView implements
return null;
}
/**
* @see CollaborationDrawingResource#getAllDrawingLayers()
* @return empty collection if no layers are found
*/
private Collection<DrawingToolLayer> getAllLayers() {
Collection<DrawingToolLayer> rval;
CollaborationDrawingResource resource = getCurrentDrawingResource();
if (resource != null) {
rval = resource.getAllDrawingLayers();
} else {
rval = Collections.emptyList();
}
return rval;
}
/*
* (non-Javadoc)
*
@ -353,7 +373,15 @@ public class CollaborationSessionView extends SessionView implements
lockAction.getAction().setImageDescriptor(
IconUtil.getImageDescriptor(Activator.getDefault().getBundle(),
"lock.gif"));
clearAllAction = new ActionContributionItem(new Action("Clear All") {
@Override
public void run() {
clearAllDrawingLayers();
}
});
clearAllAction.getAction().setImageDescriptor(
IconUtil.getImageDescriptor(Activator.getDefault().getBundle(),
"clear_all.gif"));
noEditorAction = new ControlContribution("noEditorAction") {
@Override
@ -382,12 +410,30 @@ public class CollaborationSessionView extends SessionView implements
mgr.insert(mgr.getSize() - 1, redoAction);
mgr.insert(mgr.getSize() - 1, clearAction);
mgr.insert(mgr.getSize() - 1, eraseAction);
mgr.insert(mgr.getSize() - 1, new Separator());
mgr.insert(mgr.getSize() - 1, lockAction);
mgr.insert(mgr.getSize() - 1, clearAllAction);
mgr.insert(mgr.getSize() - 1, new Separator());
updateToolItems();
}
/**
* Clear all drawing layers and send clear all event
*/
private void clearAllDrawingLayers() {
for (DrawingToolLayer layer : getAllLayers()) {
layer.clearAllDrawingData();
}
CollaborationDrawingResource resource = getCurrentDrawingResource();
CollaborationDrawingEvent event = new CollaborationDrawingEvent(
resource.getResourceData().getDisplayId());
event.setType(CollaborationEventType.CLEAR_ALL);
event.setUserName(resource.getMyUser());
resource.sendEvent(event);
updateToolItems();
}
private void toggleDrawMode(DrawMode mode) {
if (mode != DrawMode.NONE) {
CollaborationDrawingResource resource = getCurrentDrawingResource();
@ -410,6 +456,20 @@ public class CollaborationSessionView extends SessionView implements
}
}
/**
* @return true if any drawing layer has been drawn on
*/
private boolean anyLayerHasDrawing() {
boolean anyCanClear = false;
for (DrawingToolLayer dtl : getAllLayers()) {
if (dtl.hasDrawing()) {
anyCanClear = true;
break;
}
}
return anyCanClear;
}
public void updateToolItems() {
ToolBarManager mgr = (ToolBarManager) getViewSite().getActionBars()
.getToolBarManager();
@ -418,24 +478,21 @@ public class CollaborationSessionView extends SessionView implements
mgr.insert(0, noEditorAction);
}
CollaborationDrawingResource currentResource = getCurrentDrawingResource();
DrawingToolLayer layer = null;
if (currentResource != null) {
layer = currentResource.getDrawingLayerFor(currentResource
.getMyUser());
}
DrawingToolLayer layer = getCurrentLayer();
if (layer != null && currentResource.isSessionLeader()) {
lockAction.getAction().setEnabled(true);
clearAllAction.getAction().setEnabled(anyLayerHasDrawing());
} else {
lockAction.getAction().setEnabled(false);
clearAllAction.getAction().setEnabled(false);
}
// enable/disable toolbar buttons based on locked
if (layer != null
&& (locked == false || currentResource.isSessionLeader())) {
drawAction.getAction().setEnabled(true);
undoAction.getAction().setEnabled(layer.canUndo());
redoAction.getAction().setEnabled(layer.canRedo());
clearAction.getAction().setEnabled(layer.canClear());
clearAction.getAction().setEnabled(layer.hasDrawing());
eraseAction.getAction().setEnabled(true);
switch (layer.getDrawMode()) {
case DRAW:
@ -539,7 +596,8 @@ public class CollaborationSessionView extends SessionView implements
.getSelection();
VenueParticipant entry = (VenueParticipant) selection
.getFirstElement();
if (!entry.isSameUser(session.getUserID())) {
if (!entry.isSameUser(session.getUserID())
&& session.isSharedDisplayClient(entry)) {
manager.add(leaderChangeAction);
}
}

View file

@ -34,7 +34,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.ISession;
import com.raytheon.uf.viz.collaboration.comm.identity.ISharedDisplaySession;
import com.raytheon.uf.viz.collaboration.comm.identity.IVenueSession;
import com.raytheon.uf.viz.collaboration.comm.identity.info.SiteConfigInformation;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.session.SharedDisplaySession;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;

View file

@ -42,7 +42,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.IMessage;
import com.raytheon.uf.viz.collaboration.comm.identity.IPeerToPeer;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.RosterItem;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.ui.actions.PrintLogActionContributionItem;

Some files were not shown because too many files have changed in this diff Show more