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.facets.mandatory;
021
022import org.apache.isis.applib.events.ValidityEvent;
023import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
024import org.apache.isis.core.metamodel.facetapi.Facet;
025import org.apache.isis.core.metamodel.facetapi.FacetHolder;
026import org.apache.isis.core.metamodel.facets.MarkerFacetAbstract;
027import org.apache.isis.core.metamodel.facets.named.NamedFacet;
028import org.apache.isis.core.metamodel.interactions.ActionArgumentContext;
029import org.apache.isis.core.metamodel.interactions.PropertyModifyContext;
030import org.apache.isis.core.metamodel.interactions.ProposedHolder;
031import org.apache.isis.core.metamodel.interactions.ValidityContext;
032import org.apache.isis.core.metamodel.spec.ObjectAdapterUtils;
033
034public abstract class MandatoryFacetAbstract extends MarkerFacetAbstract implements MandatoryFacet {
035
036    public static Class<? extends Facet> type() {
037        return MandatoryFacet.class;
038    }
039    
040    public enum Semantics {
041        REQUIRED,
042        OPTIONAL;
043
044        public static Semantics of(boolean required) {
045            return required ? REQUIRED: OPTIONAL;
046        }
047    }
048
049    private Semantics semantics;
050
051    public MandatoryFacetAbstract(final FacetHolder holder, final Semantics semantics) {
052        super(type(), holder);
053        this.semantics = semantics;
054    }
055
056    /**
057     * If not specified or, if a string, then zero length.
058     */
059    @Override
060    public final boolean isRequiredButNull(final ObjectAdapter adapter) {
061        if(!isInvertedSemantics()) {
062            final Object object = ObjectAdapter.Util.unwrap(adapter);
063            if (object == null) {
064                return true;
065            }
066            // special case string handling.
067            final String str = ObjectAdapter.Util.unwrapAsString(adapter);
068            return str != null && str.length() == 0;
069        } else {
070            return false;
071        }
072    }
073    
074    @Override
075    public boolean isInvertedSemantics() {
076        return this.semantics == Semantics.OPTIONAL;
077    }
078
079    @Override
080    public String invalidates(final ValidityContext<? extends ValidityEvent> context) {
081        if (!(context instanceof PropertyModifyContext) && !(context instanceof ActionArgumentContext)) {
082            return null;
083        }
084        if (!(context instanceof ProposedHolder)) {
085            // shouldn't happen, since both the above should hold a proposed
086            // value/argument
087            return null;
088        }
089        final ProposedHolder proposedHolder = (ProposedHolder) context;
090        final boolean required = isRequiredButNull(proposedHolder.getProposed());
091        if (!required) {
092            return null;
093        }
094        final NamedFacet namedFacet = getFacetHolder().getFacet(NamedFacet.class);
095        final String name = namedFacet != null? namedFacet.value(): null;
096        return name != null? "'" + name + "' is mandatory":"Mandatory";
097    }
098}