/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.isis.core.metamodel.spec.feature; import java.util.Comparator; import java.util.HashMap; import java.util.List; import javax.annotation.Nullable; import com.google.common.base.Function; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import org.apache.isis.applib.annotation.When; import org.apache.isis.applib.annotation.Where; import org.apache.isis.core.metamodel.adapter.ObjectAdapter; import org.apache.isis.core.metamodel.consent.Consent; import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy; import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet; import org.apache.isis.core.metamodel.facets.members.order.MemberOrderFacet; import org.apache.isis.core.metamodel.util.DeweyOrderComparator; /** * Provides reflective access to an action or a field on a domain object. */ public interface ObjectMember extends ObjectFeature { // ///////////////////////////////////////////////////////////// // Name, Description, Help (convenience for facets) // ///////////////////////////////////////////////////////////// /** * Return the help text for this member - the field or action - to * complement the description. * * @see #getDescription() */ String getHelp(); // ///////////////////////////////////////////////////////////// // Hidden (or visible) // ///////////////////////////////////////////////////////////// /** * When the member is always hidden. * * <p> * Determined as per the {@link HiddenFacet} being present and * {@link HiddenFacet#when()} returning {@link When#ALWAYS}, and * {@link HiddenFacet#where()} returning {@link When#ANYWHERE}. */ boolean isAlwaysHidden(); /** * Determines if this member is visible, represented as a {@link Consent}. * @param target * may be <tt>null</tt> if just checking for authorization. * @param interactionInitiatedBy * @param where */ Consent isVisible( final ObjectAdapter target, final InteractionInitiatedBy interactionInitiatedBy, final Where where); // ///////////////////////////////////////////////////////////// // Disabled (or enabled) // ///////////////////////////////////////////////////////////// /** * Determines whether this member is usable, represented as a * {@link Consent}. * @param target * may be <tt>null</tt> if just checking for authorization. * @param interactionInitiatedBy * @param where */ Consent isUsable( final ObjectAdapter target, final InteractionInitiatedBy interactionInitiatedBy, final Where where); // ///////////////////////////////////////////////////////////// // isAssociation, isAction // ///////////////////////////////////////////////////////////// /** * Whether this member represents a {@link ObjectAssociation}. * * <p> * If so, can be safely downcast to {@link ObjectAssociation}. */ boolean isPropertyOrCollection(); /** * Whether this member represents a {@link OneToManyAssociation}. * * <p> * If so, can be safely downcast to {@link OneToManyAssociation}. */ boolean isOneToManyAssociation(); /** * Whether this member represents a {@link OneToOneAssociation}. * * <p> * If so, can be safely downcast to {@link OneToOneAssociation}. */ boolean isOneToOneAssociation(); /** * Whether this member represents a {@link ObjectAction}. * * <p> * If so, can be safely downcast to {@link ObjectAction}. */ boolean isAction(); // ///////////////////////////////////////////////////////////// // Debugging // ///////////////////////////////////////////////////////////// /** * Thrown if the user is not authorized to access an action or any property/collection of an entity. * * <p> * For the former case, is thrown by * {@link ObjectAction#executeWithRuleChecking(org.apache.isis.core.metamodel.adapter.ObjectAdapter, org.apache.isis.core.metamodel.adapter.ObjectAdapter[], org.apache.isis.core.commons.authentication.AuthenticationSession, org.apache.isis.applib.annotation.Where)} * when the action being executed is not visible or not usable for the specified session. One reason this * might occur if there was an attempt to construct a URL (eg a bookmarked action) and invoke in an unauthenticated session. * </p> * * <p> * For the latter case, is thrown by <tt>EntityPage</tt> * * </p> */ class AuthorizationException extends RuntimeException { public AuthorizationException() { this(null); } public AuthorizationException(final RuntimeException ex) { super("Not authorized or no such object", ex); } } class Functions { private Functions(){} public static Function<ObjectMember, String> getId() { return new Function<ObjectMember, String>() { @Nullable @Override public String apply(@Nullable final ObjectMember oneToOneAssociation) { return oneToOneAssociation.getId(); } }; } } class Util { private Util(){} public static <T extends ObjectMember> HashMap<String, T> mapById(final List<T> members) { // fails if there are multiple members with the same id... // return Maps.newHashMap(Maps.uniqueIndex(members, ObjectMember.Functions.getId())); final HashMap<String, T> memberById = Maps.newLinkedHashMap(); for (T member : members) { final String id = Functions.getId().apply(member); // if there are multiple members with same id, just disregard memberById.put(id, member); } return memberById; } } // ////////////////////////////////////////////////////// // Comparators // ////////////////////////////////////////////////////// public static class Comparators { public static Comparator<ObjectMember> byMemberOrderSequence() { return new Comparator<ObjectMember>() { private final DeweyOrderComparator deweyOrderComparator = new DeweyOrderComparator(); @Override public int compare(final ObjectMember o1, final ObjectMember o2) { final MemberOrderFacet o1Facet = o1.getFacet(MemberOrderFacet.class); final MemberOrderFacet o2Facet = o2.getFacet(MemberOrderFacet.class); String memberId1 = o1.getId(); String memberId2 = o2.getId(); String o1Sequence = o1Facet != null ? o1Facet.sequence() : "0"; String o2Sequence = o2Facet != null ? o2Facet.sequence() : "0"; return o1Facet == null? +1: o2Facet == null? -1: deweyOrderComparator.compare(o1Sequence, o2Sequence); } }; } } }