modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTab.java
| 47 ++++
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTabSet.java
| 111 +++++++++-
modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_de.properties
| 2
modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ja.properties
| 2
modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_pt.properties
| 2
modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_zh.properties
| 2
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/auth/test/SubjectManagerBeanTest.java
| 105 +++++++++
7 files changed, 263 insertions(+), 8 deletions(-)
New commits:
commit 1e1b14ece1d3763b2e92ec54d15bf70537068bcc
Merge: d1c93e1 4ad3670
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Tue Feb 21 14:28:40 2012 -0500
Merge remote-tracking branch 'origin/master' into bug/747925
commit 4ad367088998fcb67b0a058c4fb8bd5ed4133838
Author: John Sanda <jsanda(a)redhat.com>
Date: Tue Feb 21 13:46:19 2012 -0500
[BZ 781602] Adding logic to keep order of tabs consistent
The set of visible tabs can vary from one resource to another; however,
the order of tabs relative to one another is fixed. For example, the
Operations tab could appear as the 3rd or 4th tab, and it could be the
last tab. Note that it should always appear after the summary,
inventory, monitoring, and events tabs in that order. So if the
monitoring and events tabs are not visible, then the order should be
summary, inventory, operations, etc.
This commit adds an internal data structure to TwoLevelTabSet, similar
to a singly linked list a tab is a list node. Each node maintains two
pointers - one to the next visible tab and one to the next actual tab.
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTab.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTab.java
index fa62e45..79afade 100644
---
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTab.java
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTab.java
@@ -23,11 +23,14 @@ import com.smartgwt.client.widgets.Canvas;
import org.rhq.enterprise.gui.coregui.client.components.view.ViewName;
/**
- * @author Greg Hinkle
+ * @author John Sanda
* @author Jay Shaughnessy
*/
public class TwoLevelTab extends NamedTab {
private SubTabLayout layout;
+
+ private TwoLevelTab actualNext;
+ private TwoLevelTab visibleNext;
public TwoLevelTab(String locatorId, ViewName viewName, String icon) {
super(locatorId, viewName, icon);
@@ -78,6 +81,48 @@ public class TwoLevelTab extends NamedTab {
return layout;
}
+ /**
+ * This is the successor or tab immediately to the right of this tab when all tabs
+ * are visible. The tab to which actualNext refers does not change whereas the tab
to
+ * which {@link #getVisibleNext visibleNext} refers can change.
+ *
+ * @return The successor or tab immediately to the right of this tab when all tabs
are
+ * visible.
+ */
+ public TwoLevelTab getActualNext() {
+ return actualNext;
+ }
+
+ /**
+ * @param actualNext The successor or tab immediately to the right of this tab when
all
+ * tabs are visible. The tab to which actualNext refers does not change whereas the
tab
+ * to which {@link #getVisibleNext visibleNext} refers can change.
+ */
+ public void setActualNext(TwoLevelTab actualNext) {
+ this.actualNext = actualNext;
+ }
+
+ /**
+ * The successor or tab immediately to the right of this tab among the set of
visible
+ * tabs. The tab to which visibleNext refers can change whereas the tab to which
+ * {@link #getActualNext actualNext} refers will not change.
+ *
+ * @return The successor or tab immediately to the right of this tab among the set
of
+ * visible tabs.
+ */
+ public TwoLevelTab getVisibleNext() {
+ return visibleNext;
+ }
+
+ /**
+ * @param visibleNext The successor or tab immediately to the right of this tab
among
+ * the set of visible tabs. The tab to which visibleNext refers can change whereas
the
+ * tab to which {@link #getActualNext actualNext} refers will not change.
+ */
+ public void setVisibleNext(TwoLevelTab visibleNext) {
+ this.visibleNext = visibleNext;
+ }
+
@Override
public String toString() {
return "TwoLevelTab[title=" + getTitle() + ", locatorId=" +
getLocatorId() + "]";
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTabSet.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTabSet.java
index 572f035..573c543 100644
---
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTabSet.java
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tab/TwoLevelTabSet.java
@@ -39,9 +39,19 @@ public class TwoLevelTabSet extends NamedTabSet implements
TabSelectedHandler, T
private Map<String, TwoLevelTab> hiddenTabs = new LinkedHashMap<String,
TwoLevelTab>();
private boolean ignoreSelectEvents = false;
+
+ private TwoLevelTab head;
+
+ /**
+ * This is the visible tail. Because the actual order of tabs is fixed we know that
the
+ * actual tail will always be the content tab.
+ */
+ private TwoLevelTab tail;
public TwoLevelTabSet(String locatorId) {
super(locatorId);
+ // Need to set destroyPanes property to false so that we do not lose tab
+ // content when hiding a tab.
setDestroyPanes(false);
}
@@ -51,10 +61,29 @@ public class TwoLevelTabSet extends NamedTabSet implements
TabSelectedHandler, T
tab.getLayout().addTwoLevelTabSelectedHandler(this);
updateTab(tab, tab.getPane());
}
-
+ buildTabList();
addTabSelectedHandler(this);
}
+ /**
+ * This method initializes the head and tail pointers. Then it initializes the
+ * {@link TwoLevelTab#getActualNext actualNext} and {@link TwoLevelTab#getVisibleNext
visibleNext}
+ * properties of each tab. This list is built so that when hiding and showing tabs,
the
+ * tab order remains consistent. The order of the list is the same as the order of
the
+ * tabs passed to {@link #setTabs(TwoLevelTab...)}
+ */
+ private void buildTabList() {
+ TwoLevelTab[] tabs = getTabs();
+ head = tabs[0];
+ tail = tabs[tabs.length - 1];
+ TwoLevelTab current = head;
+ for (int i = 1; i < tabs.length; ++i) {
+ current.setActualNext(tabs[i]);
+ current.setVisibleNext(tabs[i]);
+ current = tabs[i];
+ }
+ }
+
public TwoLevelTab[] getTabs() {
Tab[] tabs = super.getTabs();
TwoLevelTab[] twoLevelTabs = new TwoLevelTab[tabs.length];
@@ -75,9 +104,29 @@ public class TwoLevelTabSet extends NamedTabSet implements
TabSelectedHandler, T
if (hiddenTabs.containsKey(tab.getLocatorId())) {
return;
}
+
+ TwoLevelTab visiblePrevious = findClosestVisiblePredecessor(tab);
+ if (visiblePrevious == null) {
+ // if visiblePrevious is null then that means we are updating
+ // then head. Note that as of now (02/21/2012), the visible head,
+ // the summary tab, is fixed, so we don't really need to worry
+ // about updating the head; however, doing so will make it easier
+ // to support things like hiding arbitrary tabs or reordering tabs.
+ head = tab.getVisibleNext();
+
+ } else {
+ visiblePrevious.setVisibleNext(tab.getVisibleNext());
+ // check to see if the tail needs to be updated. If the
+ // following check is true, then that means visiblePrevious is
+ // now the tail.
+ if (visiblePrevious.getVisibleNext() == null) {
+ tail = visiblePrevious;
+ }
+ }
+ tab.setVisibleNext(null);
// Note that removing the tab does *not* destroy its content pane
// since we set the destroyPanes property to false in the
- removeTab(tab);
+ removeTab(tab);
hiddenTabs.put(tab.getLocatorId(), tab);
} else {
if (!hiddenTabs.containsKey(tab.getLocatorId())) {
@@ -85,10 +134,66 @@ public class TwoLevelTabSet extends NamedTabSet implements
TabSelectedHandler, T
}
hiddenTabs.remove(tab.getLocatorId());
- addTab(tab);
+ TwoLevelTab successor = findClosestVisibleSuccessor(tab);
+ if (successor == null) {
+ // if successor is null then that means we are updating the tail
+ tail.setVisibleNext(tab);
+ tail = tab;
+ addTab(tab);
+ } else {
+ TwoLevelTab visiblePrevious = findClosestVisiblePredecessor(successor);
+ tab.setVisibleNext(visiblePrevious.getVisibleNext());
+ visiblePrevious.setVisibleNext(tab);
+ addTab(tab, (getTabNumber(visiblePrevious.getID()) + 1));
+ }
}
}
+ /**
+ * Walks the list of tabs to find the closest, visible predecessor.
+ *
+ * @param tab A {@link TwoLevelTab tab} that is currently visible
+ * @return The closest, visible predecessor or null if have the head
+ */
+ private TwoLevelTab findClosestVisiblePredecessor(TwoLevelTab tab) {
+ if (tab == head) {
+ return null;
+ }
+
+ TwoLevelTab current = head;
+ while (current != tab) {
+ // if we have reached the visible tail or the immediate predecessor
+ // of the tab, then return it.
+ if (current.getVisibleNext() == null || current.getVisibleNext() == tab) {
+ return current;
+ }
+ current = current.getVisibleNext();
+ }
+ // Not sure what we should do if we get here. return null for now
+ return null;
+ }
+
+ /**
+ * Walks the list to find the closest, visible successor.
+ *
+ * @param tab A {@link TwoLevelTab tab} that is currently hidden
+ * @return The closest, visisble successor or null if the insertion point
+ * is the tail.
+ */
+ private TwoLevelTab findClosestVisibleSuccessor(TwoLevelTab tab) {
+ TwoLevelTab current = tab;
+ while (current != null) {
+ // Walk the list of tabs until we reach a visible successor or the tail
+ if (current.getVisibleNext() == null && current != tail) {
+ current = current.getActualNext();
+ } else {
+ return current;
+ }
+ }
+ // if we reach this point then that means we will be inserting at the tail
+ return null;
+ }
+
public void destroyViews() {
for (TwoLevelTab tab : getTabs()) {
tab.getLayout().destroyViews();
commit 223f5fdfd7b7c3fbb5510b457a9892fc329fba1b
Merge: fd854c8 03737b1
Author: Mike Thompson <mithomps(a)redhat.com>
Date: Tue Feb 21 09:40:41 2012 -0800
Merge branch 'BZ691544'
commit 03737b1598b62d8334e1c85391736d9cc66e6d1c
Author: Mike Thompson <mithomps(a)redhat.com>
Date: Tue Feb 21 09:39:30 2012 -0800
[BZ691544 - Entering very large numbers in Dynagroups Recalculate Interval field
causes stack trace] Forgot to comment out foreign resource bundle keys for translation.
diff --git
a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_de.properties
b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_de.properties
index a42707d..c6e8b99 100644
---
a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_de.properties
+++
b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_de.properties
@@ -1133,7 +1133,7 @@ view_dynagroup_permDenied = Sie haben nicht das Recht die Gruppen
Definitionen a
##view_dynagroup_recalcSuccessful = You have successfully recalculated this group
definition
##view_dynagroup_recalcSuccessfulSelection = You have successfully recalculated [{0}]
group definitions
view_dynagroup_recalculate = Neu berechnen
-##view_dynagroup_recalculationInterval = Recalculation Interval
+##view_dynagroup_recalculationInterval = Recalculation Interval (min)
view_dynagroup_recursive = Rekursiv
view_dynagroup_saveAndRecalculate = Speichern & neu berechnen
##view_dynagroup_saveFailure = Failed to save the group definition named [{0}]
diff --git
a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ja.properties
b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ja.properties
index 41a33be..40d61a4a 100644
---
a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ja.properties
+++
b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ja.properties
@@ -1317,7 +1317,7 @@ view_dynagroup_recalcFailureSelection = 選択されたグループ定義を再
view_dynagroup_recalcSuccessful = このグループ定義の再計算が成功しました
view_dynagroup_recalcSuccessfulSelection = [{0}] グループ定義の再計算が成功しました
view_dynagroup_recalculate = 再計算
-view_dynagroup_recalculationInterval = 再計算間隔 (ms)
+#view_dynagroup_recalculationInterval = 再計算間隔 (min)
view_dynagroup_recursive = 再帰
view_dynagroup_saveAndRecalculate = 保存 & 再計算
view_dynagroup_saveFailure = グループ定義名 [{0}] の保存に失敗しました
diff --git
a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_pt.properties
b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_pt.properties
index 3a60da7..95903f0 100644
---
a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_pt.properties
+++
b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_pt.properties
@@ -1348,7 +1348,7 @@ view_dynagroup_recalcFailureSelection = Falha ao recalcular as
defini��es de
view_dynagroup_recalcSuccessful = Recalculo da defini��o grupo realizado com sucesso!
view_dynagroup_recalcSuccessfulSelection = As defini��es dos grupos [{0}] foram
recalculadas com com sucesso!
view_dynagroup_recalculate = Recalcular
-view_dynagroup_recalculationInterval = Intervalo para Recalculo
+#view_dynagroup_recalculationInterval = Intervalo para Recalculo
view_dynagroup_recursive = Recursivo
view_dynagroup_saveAndRecalculate = Salvar e Recalcular
view_dynagroup_saveFailure = Falha ao salvar a defini��o do grupo [{0}]
diff --git
a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_zh.properties
b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_zh.properties
index 7e4da98..0bb6308 100644
---
a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_zh.properties
+++
b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_zh.properties
@@ -1328,7 +1328,7 @@ view_dynagroup_recalcFailureSelection = Failed to recalculated the
selected grou
view_dynagroup_recalcSuccessful = \u7ec4\u5b9a\u4e49\u5df2\u7ecf\u91cd\u65b0\u8ba1\u7b97
view_dynagroup_recalcSuccessfulSelection = You have successfully recalculated [{0}] group
definitions
view_dynagroup_recalculate = \u91cd\u7b97
-view_dynagroup_recalculationInterval = \u91cd\u7b97\u95f4\u9694 (ms)
+#view_dynagroup_recalculationInterval = \u91cd\u7b97\u95f4\u9694 (ms)
view_dynagroup_recursive = \u9012\u5f52
view_dynagroup_saveAndRecalculate = \u4fdd\u5b58&\u91cd\u7b97
view_dynagroup_saveFailure =
\u4fdd\u5b58\u540d\u79f0\u4e3a[{0}]\u7684\u7ec4\u5b9a\u4e49\u5931\u8d25
commit fd854c837ed2e549c039a794c5f1cf739ad9fe2a
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Tue Feb 21 11:33:06 2012 -0500
[BZ 786159] add functional tests for the new VIEW_USERS global permission
(
https://bugzilla.redhat.com/show_bug.cgi?id=786159)
diff --git
a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/auth/test/SubjectManagerBeanTest.java
b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/auth/test/SubjectManagerBeanTest.java
index b9fe4df..8426843 100644
---
a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/auth/test/SubjectManagerBeanTest.java
+++
b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/auth/test/SubjectManagerBeanTest.java
@@ -20,7 +20,10 @@ package org.rhq.enterprise.server.auth.test;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
+import java.util.UUID;
import javax.security.auth.login.LoginException;
@@ -50,8 +53,10 @@ import org.rhq.enterprise.server.util.LookupUtil;
*/
@Test
public class SubjectManagerBeanTest extends AbstractEJB3Test {
+
private SubjectManagerLocal subjectManager;
private AuthorizationManagerLocal authorizationManager;
+ private RoleManagerLocal roleManager;
/**
* Prepares things for the entire test class.
@@ -60,6 +65,7 @@ public class SubjectManagerBeanTest extends AbstractEJB3Test {
public void beforeClass() {
subjectManager = LookupUtil.getSubjectManager();
authorizationManager = LookupUtil.getAuthorizationManager();
+ roleManager = LookupUtil.getRoleManager();
}
/**
@@ -463,4 +469,103 @@ public class SubjectManagerBeanTest extends AbstractEJB3Test {
}
}
+
+ public void testViewUsersPermission_subjectWithViewUsersRoleCanViewOtherUsers()
throws Exception {
+ getTransactionManager().begin();
+
+ try {
+ Subject overlord = subjectManager.getOverlord();
+ Subject rhqadmin = subjectManager.getSubjectByName("rhqadmin");
+
+ Role roleWithViewUsersPerm = new Role("role" + UUID.randomUUID());
+ roleWithViewUsersPerm.addPermission(Permission.VIEW_USERS);
+ roleWithViewUsersPerm = roleManager.createRole(overlord,
roleWithViewUsersPerm);
+
+ Subject subjectWithViewUsersRole = new Subject("subject" +
UUID.randomUUID(), true, false);
+ subjectWithViewUsersRole.addRole(roleWithViewUsersPerm);
+ subjectWithViewUsersRole = subjectManager.createSubject(overlord,
subjectWithViewUsersRole, "password");
+ subjectWithViewUsersRole =
subjectManager.loginUnauthenticated(subjectWithViewUsersRole.getName());
+
+ Subject anotherSubject = new Subject("subject" + UUID.randomUUID(),
true, false);
+ anotherSubject = subjectManager.createSubject(overlord, anotherSubject,
"password");
+
+ PageList<Subject> subjects =
subjectManager.findSubjectsByCriteria(subjectWithViewUsersRole, new SubjectCriteria());
+ Set<Subject> subjectSet = new HashSet<Subject>(subjects);
+ assertTrue(subjectSet.contains(subjectWithViewUsersRole));
+ assertTrue(subjectSet.contains(anotherSubject));
+ assertTrue(subjectSet.contains(rhqadmin));
+ } finally {
+ getTransactionManager().rollback();
+ }
+ }
+
+ public void testViewUsersPermission_rhqadminCanViewOtherUsers() throws Exception {
+ getTransactionManager().begin();
+
+ try {
+ Subject overlord = subjectManager.getOverlord();
+
+ Subject rhqadmin = subjectManager.getSubjectByName("rhqadmin");
+ rhqadmin = subjectManager.loginUnauthenticated(rhqadmin.getName());
+
+ Subject anotherSubject = new Subject("subject" + UUID.randomUUID(),
true, false);
+ anotherSubject = subjectManager.createSubject(overlord, anotherSubject,
"password");
+
+ PageList<Subject> subjects =
subjectManager.findSubjectsByCriteria(rhqadmin, new SubjectCriteria());
+ Set<Subject> subjectSet = new HashSet<Subject>(subjects);
+ assertTrue(subjectSet.contains(anotherSubject));
+ assertTrue(subjectSet.contains(rhqadmin));
+ } finally {
+ getTransactionManager().rollback();
+ }
+ }
+
+ public void testViewUsersPermission_subjectWithNonViewUsersRoleCannotViewOtherUsers()
throws Exception {
+ getTransactionManager().begin();
+
+ try {
+ Subject overlord = subjectManager.getOverlord();
+
+ Role roleWithoutViewUsersPerm = new Role("role" +
UUID.randomUUID());
+ roleWithoutViewUsersPerm = roleManager.createRole(overlord,
roleWithoutViewUsersPerm);
+
+ Subject subjectWithNonViewUsersRole = new Subject("subject" +
UUID.randomUUID(), true, false);
+ subjectWithNonViewUsersRole.addRole(roleWithoutViewUsersPerm);
+ subjectWithNonViewUsersRole = subjectManager.createSubject(overlord,
subjectWithNonViewUsersRole, "password");
+ subjectWithNonViewUsersRole =
subjectManager.loginUnauthenticated(subjectWithNonViewUsersRole.getName());
+
+ Subject anotherSubject = new Subject("subject" + UUID.randomUUID(),
true, false);
+ anotherSubject = subjectManager.createSubject(overlord, anotherSubject,
"password");
+
+ PageList<Subject> subjects =
subjectManager.findSubjectsByCriteria(subjectWithNonViewUsersRole, new
SubjectCriteria());
+ Set<Subject> subjectSet = new HashSet<Subject>(subjects);
+ assertEquals(1, subjectSet.size());
+ assertTrue(subjectSet.contains(subjectWithNonViewUsersRole));
+ } finally {
+ getTransactionManager().rollback();
+ }
+ }
+
+ public void testViewUsersPermission_subjectWithNoRolesCannotViewOtherUsers() throws
Exception {
+ getTransactionManager().begin();
+
+ try {
+ Subject overlord = subjectManager.getOverlord();
+
+ Subject subjectWithNoRoles = new Subject("subject" +
UUID.randomUUID(), true, false);
+ subjectWithNoRoles = subjectManager.createSubject(overlord,
subjectWithNoRoles, "password");
+ subjectWithNoRoles =
subjectManager.loginUnauthenticated(subjectWithNoRoles.getName());
+
+ Subject anotherSubject = new Subject("subject" + UUID.randomUUID(),
true, false);
+ anotherSubject = subjectManager.createSubject(overlord, anotherSubject,
"password");
+
+ PageList<Subject> subjects =
subjectManager.findSubjectsByCriteria(subjectWithNoRoles, new SubjectCriteria());
+ Set<Subject> subjectSet = new HashSet<Subject>(subjects);
+ assertEquals(1, subjectSet.size());
+ assertTrue(subjectSet.contains(subjectWithNoRoles));
+ } finally {
+ getTransactionManager().rollback();
+ }
+ }
+
}
\ No newline at end of file