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    
020    package org.apache.isis.core.progmodel.facets.param.choices.method;
021    
022    import java.lang.reflect.Method;
023    import java.util.Collections;
024    import java.util.List;
025    
026    import org.apache.isis.core.commons.lang.ArrayUtil;
027    import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
028    import org.apache.isis.core.metamodel.adapter.map.AdapterMap;
029    import org.apache.isis.core.metamodel.adapter.util.AdapterInvokeUtils;
030    import org.apache.isis.core.metamodel.facetapi.FacetHolder;
031    import org.apache.isis.core.metamodel.facets.ImperativeFacet;
032    import org.apache.isis.core.metamodel.facets.actions.choices.ActionChoicesFacetAbstract;
033    import org.apache.isis.core.metamodel.spec.DomainModelException;
034    import org.apache.isis.core.metamodel.spec.ObjectSpecification;
035    import org.apache.isis.core.metamodel.spec.SpecificationLookup;
036    import org.apache.isis.core.progmodel.facets.CollectionUtils;
037    
038    public class ActionChoicesFacetViaMethod extends ActionChoicesFacetAbstract implements ImperativeFacet {
039    
040        private final Method method;
041        private final Class<?> choicesType;
042        private final SpecificationLookup specificationLookup;
043        private final AdapterMap adapterMap;
044    
045        public ActionChoicesFacetViaMethod(final Method method, final Class<?> choicesType, final FacetHolder holder,
046            final SpecificationLookup specificationLookup, final AdapterMap adapterManager) {
047            super(holder);
048            this.method = method;
049            this.choicesType = choicesType;
050            this.specificationLookup = specificationLookup;
051            this.adapterMap = adapterManager;
052        }
053    
054        /**
055         * Returns a singleton list of the {@link Method} provided in the constructor.
056         */
057        @Override
058        public List<Method> getMethods() {
059            return Collections.singletonList(method);
060        }
061    
062        @Override
063        public boolean impliesResolve() {
064            return true;
065        }
066    
067        @Override
068        public boolean impliesObjectChanged() {
069            return false;
070        }
071    
072        @Override
073        public Object[][] getChoices(final ObjectAdapter owningAdapter) {
074            final Object invoke = AdapterInvokeUtils.invoke(method, owningAdapter);
075            if (!(invoke instanceof Object[])) {
076                throw new DomainModelException(
077                    "Expected an array of collections (Object[]) containing choices for all parameters, but got " + invoke
078                        + " instead. Perhaps the parameter number is missing!");
079            }
080            final Object[] options = (Object[]) invoke;
081            final Object[][] results = new Object[options.length][];
082            for (int i = 0; i < results.length; i++) {
083                if (options[i] == null) {
084                    results[i] = null;
085                } else if (options[i].getClass().isArray()) {
086                    results[i] = ArrayUtil.getObjectAsObjectArray(options[i]);
087                } else {
088                    final ObjectSpecification specification = getSpecificationLookup().loadSpecification(choicesType);
089                    results[i] = CollectionUtils.getCollectionAsObjectArray(options[i], specification, getAdapterMap());
090                }
091            }
092            return results;
093        }
094    
095        @Override
096        protected String toStringValues() {
097            return "method=" + method + ",type=" + choicesType;
098        }
099    
100        // ///////////////////////////////////////////////////////
101        // Dependencies
102        // ///////////////////////////////////////////////////////
103    
104        private SpecificationLookup getSpecificationLookup() {
105            return specificationLookup;
106        }
107    
108        private AdapterMap getAdapterMap() {
109            return adapterMap;
110        }
111    
112    }