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 */
019
020package org.apache.isis.core.metamodel.consent;
021
022import static org.apache.isis.core.commons.matchers.IsisMatchers.nonEmptyStringOrNull;
023import static org.hamcrest.CoreMatchers.is;
024
025import java.io.Serializable;
026
027import org.apache.isis.core.commons.ensure.Ensure;
028
029public abstract class ConsentAbstract implements Serializable, Consent {
030
031    /**
032     * 
033     */
034    private static final long serialVersionUID = 1L;
035
036    /**
037     * Factory method.
038     * 
039     * <p>
040     * Used extensively by the DnD viewer.
041     */
042    public static Consent allowIf(final boolean allowed) {
043        return allowed ? Allow.DEFAULT : Veto.DEFAULT;
044    }
045
046    private final InteractionResult interactionResult;
047    private final String reason;
048
049    /**
050     * Can be subsequently {@link #setDescription(String) modified}, but is only
051     * a description of the event to which this consent applies and does not
052     * change whether the Consent represents an allow or a veto.
053     */
054    private String description;
055
056    private static String determineReason(final InteractionResult interactionResult) {
057        if (interactionResult == null) {
058            return null;
059        }
060        return interactionResult.getReason();
061    }
062
063    /**
064     * 
065     * @param interactionResult
066     *            - if <tt>null</tt> then defaults to an {@link #isAllowed()
067     *            allowing} {@link Consent}.
068     */
069    protected ConsentAbstract(final InteractionResult interactionResult) {
070        this(interactionResult, null, determineReason(interactionResult));
071    }
072
073    /**
074     * Enable legacy {@link Consent}s (not created using an
075     * {@link InteractionResult}) to create an {@link Consent}, specifying a
076     * {@link #getDescription() description} of the event and the
077     * {@link #getReason() reason} (if any) that the consent is vetoed.
078     * 
079     * @param description
080     *            - a description of the event to which this consent relates
081     * @param reason
082     *            - if not <tt>null</tt> and not empty, is the reason this
083     *            consent is vetoed.
084     */
085    protected ConsentAbstract(final String description, final String reason) {
086        this(null, description, reason);
087    }
088
089    private ConsentAbstract(final InteractionResult interactionResult, final String description, final String reason) {
090        this.interactionResult = interactionResult;
091        this.description = description;
092        Ensure.ensureThatArg(reason, is(nonEmptyStringOrNull()));
093        this.reason = reason;
094    }
095
096    /**
097     * The reason why this has been vetoed.
098     */
099    @Override
100    public String getReason() {
101        return isVetoed() ? this.reason : null;
102    }
103
104    @Override
105    public Consent setDescription(final String description) {
106        this.description = description;
107        return this;
108    }
109
110    /**
111     * Returns <tt>true</tt> if this object is giving permission (if the
112     * {@link #getReason() reason} is <tt>null</tt> or empty.
113     * 
114     * @see #getReason()
115     */
116    @Override
117    public boolean isAllowed() {
118        return this.reason == null || this.reason.equals("");
119    }
120
121    /**
122     * Returns true if this object is NOT giving permission.
123     * 
124     * @see #isAllowed()
125     */
126    @Override
127    public boolean isVetoed() {
128        return !isAllowed();
129    }
130
131    /**
132     * Underlying {@link InteractionResult} that created this {@link Consent}
133     * (may be <tt>null</tt>).
134     * 
135     */
136    @Override
137    public InteractionResult getInteractionResult() {
138        return interactionResult;
139    }
140
141    /**
142     * Description of the action allowed by this event.
143     * 
144     * <p>
145     * (Previously, {@link Allow} consents overloaded the {@link #getReason()
146     * reason} property with a description of the event. This has now been
147     * changed so that a non-<tt>null</tt> reason always implies a {@link Veto}.
148     * This property captures the description.
149     * 
150     * @return
151     */
152    @Override
153    public String getDescription() {
154        return description;
155    }
156
157    @Override
158    public String toString() {
159        return (isVetoed() ? "VETOED" : "ALLOWED") + ", reason=" + reason;
160    }
161
162}