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.progmodel.facets.object.bounded;
021
022import java.util.Arrays;
023import java.util.List;
024
025import com.google.common.collect.Lists;
026
027import org.apache.isis.applib.events.UsabilityEvent;
028import org.apache.isis.applib.events.ValidityEvent;
029import org.apache.isis.applib.marker.Bounded;
030import org.apache.isis.applib.query.Query;
031import org.apache.isis.applib.query.QueryFindAllInstances;
032import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
033import org.apache.isis.core.metamodel.adapter.QuerySubmitter;
034import org.apache.isis.core.metamodel.facetapi.Facet;
035import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
036import org.apache.isis.core.metamodel.facetapi.FacetHolder;
037import org.apache.isis.core.metamodel.facets.choices.ChoicesFacet;
038import org.apache.isis.core.metamodel.interactions.DisablingInteractionAdvisor;
039import org.apache.isis.core.metamodel.interactions.ObjectValidityContext;
040import org.apache.isis.core.metamodel.interactions.UsabilityContext;
041import org.apache.isis.core.metamodel.interactions.ValidatingInteractionAdvisor;
042import org.apache.isis.core.metamodel.interactions.ValidityContext;
043import org.apache.isis.core.metamodel.spec.ObjectAdapterUtils;
044import org.apache.isis.core.metamodel.spec.ObjectSpecification;
045
046/**
047 * A fixed number of choices because the number of instances of this class is bounded.
048 * 
049 * <p>
050 * Typically viewers will interpret this information by displaying all instances
051 * of the class in a drop-down list box or similar widget.
052 * 
053 * <p>
054 * In the standard Apache Isis Programming Model, corresponds to annotating the
055 * member with {@link org.apache.isis.applib.annotation.Bounded Bounded} annotation
056 * or implementing the {@link Bounded} marker interface.
057 */
058public abstract class ChoicesFacetFromBoundedAbstract extends FacetAbstract implements ChoicesFacet, DisablingInteractionAdvisor, ValidatingInteractionAdvisor {
059
060    public static Class<? extends Facet> type() {
061        return ChoicesFacet.class;
062    }
063
064    private final QuerySubmitter querySubmitter;
065    
066    public ChoicesFacetFromBoundedAbstract(final FacetHolder holder, final QuerySubmitter querySubmitter) {
067        super(type(), holder, Derivation.NOT_DERIVED);
068        this.querySubmitter = querySubmitter;
069    }
070
071    protected QuerySubmitter getQuerySubmitter() {
072        return querySubmitter;
073    }
074
075    @Override
076    public String invalidates(final ValidityContext<? extends ValidityEvent> context) {
077        if (!(context instanceof ObjectValidityContext)) {
078            return null;
079        }
080        final ObjectAdapter target = context.getTarget();
081        if(target == null) {
082            return null;
083        }
084        
085        // ensure that the target is of the correct type
086        if(!(getFacetHolder() instanceof ObjectSpecification)) {
087            // should never be the case
088            return null;
089        }
090        
091        final ObjectSpecification objectSpec = getObjectSpecification();
092        return objectSpec == target.getSpecification()? null: "Invalid type";
093    }
094
095    private ObjectSpecification getObjectSpecification() {
096        return (ObjectSpecification) getFacetHolder();
097    }
098
099    @Override
100    public String disables(final UsabilityContext<? extends UsabilityEvent> context) {
101        final ObjectAdapter target = context.getTarget();
102        return disabledReason(target);
103    }
104
105    /**
106     * Optional hook method for subclasses to override.
107     */
108    public String disabledReason(final ObjectAdapter inObject) {
109        return "Bounded";
110    }
111
112    @SuppressWarnings({ "rawtypes", "unchecked" })
113    @Override
114    public Object[] getChoices(ObjectAdapter adapter) {
115        final Query query = new QueryFindAllInstances(getObjectSpecification().getFullIdentifier());
116        final List<ObjectAdapter> allInstancesAdapter = getQuerySubmitter().allMatchingQuery(query);
117        final List<ObjectAdapter> adapters = Lists.newArrayList(allInstancesAdapter.iterator());
118        final List<Object> pojos = Lists.transform(adapters, ObjectAdapter.Functions.getObject());
119        return Lists.newArrayList(pojos).toArray();
120    }
121
122
123
124}