You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2015/01/07 01:54:37 UTC

isis git commit: ISIS-985: new VisibilityContext at object level, fired when rendering objects in table (and also an object on a page), in support of multi-tenancy (as implemented by isisaddons' security module).

Repository: isis
Updated Branches:
  refs/heads/ISIS-985 f0e895a3f -> d1ed04ece


ISIS-985: new VisibilityContext at object level, fired when rendering objects in table (and also an object on a page), in support of multi-tenancy (as implemented by isisaddons' security module).


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

Branch: refs/heads/ISIS-985
Commit: d1ed04eceb8bd0799801dda24ce9b4b82125e38d
Parents: f0e895a
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Wed Jan 7 00:54:30 2015 +0000
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Wed Jan 7 00:54:30 2015 +0000

----------------------------------------------------------------------
 .../CollectionContentsSortableDataProvider.java | 82 ++++++++++++--------
 .../entity/properties/EntityPropertiesForm.java |  6 +-
 .../wicket/ui/pages/entity/EntityPage.java      | 47 +++++++++--
 .../standard/AuthorizationManagerStandard.java  |  6 ++
 4 files changed, 100 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/d1ed04ec/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsSortableDataProvider.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsSortableDataProvider.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsSortableDataProvider.java
index 985da69..8b9641c 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsSortableDataProvider.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsSortableDataProvider.java
@@ -59,19 +59,6 @@ public class CollectionContentsSortableDataProvider extends SortableDataProvider
     }
 
     @Override
-    public Iterator<ObjectAdapter> iterator(final long first, final long count) {
-        final List<ObjectAdapter> unfilteredAdapters = model.getObject();
-
-        final List<ObjectAdapter> filteredAdapters = Lists.newArrayList(Iterables.filter(unfilteredAdapters, ignoreHidden()));
-
-        List<ObjectAdapter> adapters = sortedIfRequired(filteredAdapters, this.getSort());
-
-        final int from = (int) first;
-        final int toIndex = Math.min((int) (first + count), adapters.size());
-        return adapters.subList(from, toIndex).iterator();
-    }
-
-    @Override
     public IModel<ObjectAdapter> model(final ObjectAdapter adapter) {
         return new EntityModel(adapter);
     }
@@ -87,28 +74,62 @@ public class CollectionContentsSortableDataProvider extends SortableDataProvider
         model.detach();
     }
 
-    
-    private List<ObjectAdapter> sortedIfRequired(List<ObjectAdapter> adapters, final SortParam<String> sort) {
+    @Override
+    public Iterator<ObjectAdapter> iterator(final long first, final long count) {
+
+        final List<ObjectAdapter> adapters = model.getObject();
+
+        final Iterable<ObjectAdapter> visibleAdapters =
+                Iterables.filter(adapters, ignoreHidden());
+
+        // need to create a list from the iterable, then back to an iterable
+        // because guava's Ordering class doesn't support sorting of iterable -> iterable
+        final List<ObjectAdapter> sortedVisibleAdapters = sortedCopy(visibleAdapters, getSort());
+        final List<ObjectAdapter> pagedAdapters = subList(first, count, sortedVisibleAdapters);
+        return pagedAdapters.iterator();
+    }
+
+    private static List<ObjectAdapter> subList(
+            final long first,
+            final long count,
+            final List<ObjectAdapter> objectAdapters) {
+
+        final int fromIndex = (int) first;
+        // if adapters where filter out (as invisible), then make sure don't run off the end
+        final int toIndex = Math.min((int) (first + count), objectAdapters.size());
+
+        return objectAdapters.subList(fromIndex, toIndex);
+    }
+
+    private List<ObjectAdapter> sortedCopy(
+            final Iterable<ObjectAdapter> adapters,
+            final SortParam<String> sort) {
+
+        final ObjectAssociation sortProperty = lookupAssociationFor(sort);
+        if(sortProperty == null) {
+            return Lists.newArrayList(adapters);
+        }
+
+        final Ordering<ObjectAdapter> ordering =
+                orderingBy(sortProperty, sort.isAscending());
+        return ordering.sortedCopy(adapters);
+    }
+
+    private ObjectAssociation lookupAssociationFor(final SortParam<String> sort) {
 
         if(sort == null) {
-            return adapters;
+            return null;
         }
-        
+
         final ObjectSpecification elementSpec = model.getTypeOfSpecification();
-        
         final String sortPropertyId = sort.getProperty();
-        try {
-            final ObjectAssociation sortProperty = elementSpec.getAssociation(sortPropertyId);
-            if(sortProperty == null) {
-                return adapters;
-            }
-            
-            Ordering<ObjectAdapter> ordering = orderingBy(sortProperty, sort.isAscending());
 
-            return ordering.sortedCopy(adapters);
+        try {
+            // might be null, or throw ex
+            return elementSpec.getAssociation(sortPropertyId);
         } catch(ObjectSpecificationException ex) {
             // eg invalid propertyId
-            return adapters;
+            return null;
         }
     }
 
@@ -132,8 +153,7 @@ public class CollectionContentsSortableDataProvider extends SortableDataProvider
                 Where.ALL_TABLES);
     }
 
-
-    public static Ordering<ObjectAdapter> orderingBy(final ObjectAssociation sortProperty, final boolean ascending) {
+    private static Ordering<ObjectAdapter> orderingBy(final ObjectAssociation sortProperty, final boolean ascending) {
         final Ordering<ObjectAdapter> ordering = new Ordering<ObjectAdapter>(){
     
             @Override
@@ -150,7 +170,7 @@ public class CollectionContentsSortableDataProvider extends SortableDataProvider
         return ascending?ordering:ordering.reverse();
     }
 
-    public static Ordering<ObjectAdapter> ORDERING_BY_NATURAL = new Ordering<ObjectAdapter>(){
+    private static Ordering<ObjectAdapter> ORDERING_BY_NATURAL = new Ordering<ObjectAdapter>(){
         @Override
         public int compare(final ObjectAdapter p, final ObjectAdapter q) {
             final Object pPojo = p.getObject();
@@ -168,8 +188,6 @@ public class CollectionContentsSortableDataProvider extends SortableDataProvider
         }
     };
 
-
-
     // //////////////////////////////////////
 
     protected AuthenticationSession getAuthenticationSession() {

http://git-wip-us.apache.org/repos/asf/isis/blob/d1ed04ec/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityPropertiesForm.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityPropertiesForm.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityPropertiesForm.java
index b7f1127..cb2dc45 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityPropertiesForm.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityPropertiesForm.java
@@ -122,7 +122,11 @@ public class EntityPropertiesForm extends FormAbstract<ObjectAdapter> implements
     
     private boolean renderedFirstField;
 
-    public EntityPropertiesForm(final String id, final EntityModel entityModel, final Component owningPanel) {
+    public EntityPropertiesForm(
+            final String id,
+            final EntityModel entityModel,
+            final Component owningPanel) {
+
         super(id, entityModel);
         this.owningPanel = owningPanel; // for repainting
 

http://git-wip-us.apache.org/repos/asf/isis/blob/d1ed04ec/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java
index 5ca6c24..64a18cc 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java
@@ -29,6 +29,12 @@ import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
 import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
+import org.apache.isis.core.metamodel.consent.InteractionInvocationMethod;
+import org.apache.isis.core.metamodel.consent.InteractionResult;
+import org.apache.isis.core.metamodel.deployment.DeploymentCategory;
+import org.apache.isis.core.metamodel.interactions.InteractionUtils;
+import org.apache.isis.core.metamodel.interactions.ObjectVisibilityContext;
+import org.apache.isis.core.metamodel.interactions.VisibilityContext;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.Contributed;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
@@ -72,14 +78,14 @@ public class EntityPage extends PageAbstract {
      * Ensure that any {@link ConcurrencyException} that might have occurred already
      * (eg from an action invocation) is show.
      */
-    public EntityPage(ObjectAdapter adapter, ConcurrencyException exIfAny) {
+    public EntityPage(final ObjectAdapter adapter, final ConcurrencyException exIfAny) {
         this(new PageParameters(), newEntityModel(adapter, exIfAny));
     }
 
     private static EntityModel newEntityModel(
             final ObjectAdapter adapter,
             final ConcurrencyException exIfAny) {
-        EntityModel model = new EntityModel(adapter);
+        final EntityModel model = new EntityModel(adapter);
         model.setException(exIfAny);
         return model;
     }
@@ -96,7 +102,7 @@ public class EntityPage extends PageAbstract {
         try {
             // check object still exists
             objectAdapter = entityModel.getObject();
-        } catch(RuntimeException ex) {
+        } catch(final RuntimeException ex) {
             removeAnyBookmark(model);
             removeAnyBreadcrumb(model);
 
@@ -104,7 +110,12 @@ public class EntityPage extends PageAbstract {
             throw new ObjectMember.AuthorizationException(ex);
         }
 
-        // check that at least one property of the entity can be viewed.
+        // check that the entity overall can be viewed.
+        if(!isVisible(objectAdapter)) {
+            throw new ObjectMember.AuthorizationException();
+        }
+
+        // belt-n-braces: check that at least one property of the entity can be viewed.
         final AuthenticationSession session = getAuthenticationSession();
         final ObjectSpecification specification = objectAdapter.getSpecification();
         final List<ObjectAssociation> visibleAssociation = specification.getAssociations(Contributed.INCLUDED, ObjectAssociation.Filters.dynamicallyVisible(session, objectAdapter, Where.NOWHERE));
@@ -114,7 +125,7 @@ public class EntityPage extends PageAbstract {
         }
 
 
-        // this is a work-around for JRebel integration...
+        // the next bit is a work-around for JRebel integration...
         // ... even though the IsisJRebelPlugin calls invalidateCache, it seems that there is 
         // some caching elsewhere in the Wicket viewer meaning that stale metadata is referenced.
         // doing an additional call here seems to be sufficient, though not exactly sure why... :-(
@@ -123,7 +134,7 @@ public class EntityPage extends PageAbstract {
         }
 
         if(titleString == null) {
-            String titleStr = objectAdapter.titleString(null);
+            final String titleStr = objectAdapter.titleString(null);
             setTitle(titleStr);
         }
         
@@ -135,6 +146,7 @@ public class EntityPage extends PageAbstract {
 
         addBookmarkedPages();
 
+
         // TODO mgrigorov: Zero Clipboard has been moved to EntityIconAndTitlePanel where the entity model is available.
         // Is this still needed for something else ?!
         //
@@ -142,14 +154,30 @@ public class EntityPage extends PageAbstract {
         send(this, Broadcast.BREADTH, new IsisUiHintEvent(entityModel, null));
     }
 
+    private boolean isVisible(final ObjectAdapter input) {
+        final InteractionResult visibleResult = InteractionUtils.isVisibleResult(input.getSpecification(), createVisibleInteractionContext(input));
+        return visibleResult.isNotVetoing();
+    }
+
+    private VisibilityContext<?> createVisibleInteractionContext(final ObjectAdapter objectAdapter) {
+        return new ObjectVisibilityContext(
+                getDeploymentCategory(),
+                getAuthenticationSession(),
+                InteractionInvocationMethod.BY_USER,
+                objectAdapter,
+                objectAdapter.getSpecification().getIdentifier(),
+                Where.OBJECT_FORMS);
+    }
+
 
-    private void addBreadcrumb(EntityModel entityModel) {
+
+    private void addBreadcrumb(final EntityModel entityModel) {
         final BreadcrumbModelProvider session = (BreadcrumbModelProvider) getSession();
         final BreadcrumbModel breadcrumbModel = session.getBreadcrumbModel();
         breadcrumbModel.visited(entityModel);
     }
 
-    private void removeAnyBreadcrumb(EntityModel entityModel) {
+    private void removeAnyBreadcrumb(final EntityModel entityModel) {
         final BreadcrumbModelProvider session = (BreadcrumbModelProvider) getSession();
         final BreadcrumbModel breadcrumbModel = session.getBreadcrumbModel();
         breadcrumbModel.remove(entityModel);
@@ -172,6 +200,9 @@ public class EntityPage extends PageAbstract {
         return IsisContext.getDeploymentType();
     }
 
+    protected DeploymentCategory getDeploymentCategory() {
+        return getDeploymentType().getDeploymentCategory();
+    }
 
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/d1ed04ec/core/metamodel/src/main/java/org/apache/isis/core/runtime/authorization/standard/AuthorizationManagerStandard.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/runtime/authorization/standard/AuthorizationManagerStandard.java b/core/metamodel/src/main/java/org/apache/isis/core/runtime/authorization/standard/AuthorizationManagerStandard.java
index 836c7fa..d9d0f36 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/runtime/authorization/standard/AuthorizationManagerStandard.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/runtime/authorization/standard/AuthorizationManagerStandard.java
@@ -111,6 +111,12 @@ public class AuthorizationManagerStandard extends AuthorizationManagerAbstract i
         if (isPerspectiveMember(identifier)) {
             return true;
         }
+
+        // no-op if is visibility context check at object-level
+        if (identifier.getMemberName().equals("")) {
+            return true;
+        }
+
         if (authorizor.isVisibleInAnyRole(identifier)) {
             return true;
         }