001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *        http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 */
019package org.apache.isis.extensions.secman.api.permission;
020
021import java.io.Serializable;
022import java.util.Comparator;
023import java.util.List;
024
025import org.apache.isis.applib.annotation.Programmatic;
026import org.apache.isis.applib.util.ObjectContracts;
027import org.apache.isis.applib.util.ToString;
028import org.apache.isis.core.metamodel.services.appfeat.ApplicationFeatureId;
029
030/**
031 * A serializable value object representing an (anonymized)
032 * {@link org.apache.isis.extensions.security.manager.jdo.dom.permission.ApplicationPermission}.
033 *
034 * <p>
035 *     Intended for value type arithmetic and also for caching.  No user/role information is held because that information
036 *     is not required to perform the arithmetic.
037 * </p>
038 */
039public class ApplicationPermissionValue implements Comparable<ApplicationPermissionValue>, Serializable {
040
041    private static final long serialVersionUID = 1L;
042
043    // -- constructor
044    public ApplicationPermissionValue(
045            final ApplicationFeatureId featureId,
046            final ApplicationPermissionRule rule,
047            final ApplicationPermissionMode mode) {
048        this.featureId = featureId;
049        this.rule = rule;
050        this.mode = mode;
051    }
052
053
054    // -- featureId
055    private final ApplicationFeatureId featureId;
056    @Programmatic
057    public ApplicationFeatureId getFeatureId() {
058        return featureId;
059    }
060
061
062    // -- rule
063    private final ApplicationPermissionRule rule;
064    @Programmatic
065    public ApplicationPermissionRule getRule() {
066        return rule;
067    }
068
069
070    // -- mode
071    private final ApplicationPermissionMode mode;
072    @Programmatic
073    public ApplicationPermissionMode getMode() {
074        return mode;
075    }
076
077
078    // -- implies, refutes
079    @Programmatic
080    public boolean implies(final ApplicationFeatureId featureId, final ApplicationPermissionMode mode) {
081        if(getRule() != ApplicationPermissionRule.ALLOW) {
082            // only allow rules can imply
083            return false;
084        }
085        if(getMode() == ApplicationPermissionMode.VIEWING && mode == ApplicationPermissionMode.CHANGING) {
086            // an "allow viewing" permission does not imply ability to change
087            return false;
088        }
089
090        // determine if this permission is on the path (ie the feature or one of its parents)
091        return onPathOf(featureId);
092    }
093
094    @Programmatic
095    public boolean refutes(final ApplicationFeatureId featureId, final ApplicationPermissionMode mode) {
096        if(getRule() != ApplicationPermissionRule.VETO) {
097            // only veto rules can refute
098            return false;
099        }
100        if(getMode() == ApplicationPermissionMode.CHANGING && mode == ApplicationPermissionMode.VIEWING) {
101            // an "veto changing" permission does not refute ability to view
102            return false;
103        }
104        // determine if this permission is on the path (ie the feature or one of its parents)
105        return onPathOf(featureId);
106    }
107
108    private boolean onPathOf(final ApplicationFeatureId featureId) {
109
110        final List<ApplicationFeatureId> pathIds = featureId.getPathIds();
111        for (final ApplicationFeatureId pathId : pathIds) {
112            if(getFeatureId().equals(pathId)) {
113                return true;
114            }
115        }
116
117        return false;
118    }
119
120
121
122    // -- Comparators
123    public static final class Comparators {
124        private Comparators(){}
125        public static Comparator<ApplicationPermissionValue> natural() {
126            return new ApplicationPermissionValueComparator();
127        }
128
129        static class ApplicationPermissionValueComparator implements Comparator<ApplicationPermissionValue>, Serializable {
130            private static final long serialVersionUID = 1L;
131
132            @Override
133            public int compare(final ApplicationPermissionValue o1, final ApplicationPermissionValue o2) {
134                return o1.compareTo(o2);
135            }
136        }
137    }
138
139
140    // -- CONTRACT
141
142    private static final Comparator<ApplicationPermissionValue> comparator =
143            Comparator.comparing(ApplicationPermissionValue::getRule)
144            .thenComparing(ApplicationPermissionValue::getMode)
145            .thenComparing(ApplicationPermissionValue::getFeatureId);
146
147    private static final ToString<ApplicationPermissionValue> toString =
148            ObjectContracts.toString("name", ApplicationPermissionValue::getRule)
149            .thenToString("mode", ApplicationPermissionValue::getMode)
150            .thenToString("featureId", ApplicationPermissionValue::getFeatureId);
151
152
153    @Override
154    public int compareTo(final ApplicationPermissionValue o) {
155        return comparator.compare(this, o);
156    }
157
158    @Override
159    public boolean equals(final Object o) {
160        // not using because trying to be efficient.  Premature optimization?
161        // return ObjectContracts.equals(this, obj, propertyNames);
162        if (this == o) return true;
163        if (o == null || getClass() != o.getClass()) return false;
164
165        final ApplicationPermissionValue that = (ApplicationPermissionValue) o;
166
167        if (featureId != null ? !featureId.equals(that.featureId) : that.featureId != null) return false;
168        if (mode != that.mode) return false;
169        if (rule != that.rule) return false;
170
171        return true;
172    }
173
174    @Override
175    public int hashCode() {
176        // not using because trying to be efficient.  Premature optimization?
177        // return ObjectContracts.hashCode(this, propertyNames);
178        int result = featureId != null ? featureId.hashCode() : 0;
179        result = 31 * result + (rule != null ? rule.hashCode() : 0);
180        result = 31 * result + (mode != null ? mode.hashCode() : 0);
181        return result;
182    }
183
184    @Override
185    public String toString() {
186        return toString.toString(this);
187    }
188
189
190}