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.object.autocomplete;
021
022import java.util.Collections;
023import java.util.List;
024
025import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
026import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
027import org.apache.isis.core.metamodel.facetapi.Facet;
028import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
029import org.apache.isis.core.metamodel.facetapi.FacetHolder;
030import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacetUtils;
031import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
032import org.apache.isis.core.metamodel.spec.ActionType;
033import org.apache.isis.core.metamodel.spec.ObjectSpecification;
034import org.apache.isis.core.metamodel.spec.SpecificationLoader;
035import org.apache.isis.core.metamodel.spec.feature.Contributed;
036import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
037
038public abstract class AutoCompleteFacetAbstract extends FacetAbstract implements AutoCompleteFacet {
039
040    public static Class<? extends Facet> type() {
041        return AutoCompleteFacet.class;
042    }
043
044    private final Class<?> repositoryClass;
045    private final String actionName;
046
047    private final SpecificationLoader specificationLoader;
048    private final AdapterManager adapterManager;
049    private final ServicesInjector servicesInjector;
050
051    /**
052     * cached once searched for
053     */
054    private ObjectAction repositoryAction;
055    private boolean cachedRepositoryAction = false;
056    
057    private boolean cachedRepositoryObject = false;
058    private Object repository;
059
060    public AutoCompleteFacetAbstract(FacetHolder holder, Class<?> repositoryClass, String actionName, SpecificationLoader specificationLoader, AdapterManager adapterManager, ServicesInjector servicesInjector) {
061        super(type(), holder, Derivation.NOT_DERIVED);
062        this.repositoryClass = repositoryClass;
063        this.actionName = actionName;
064        this.specificationLoader = specificationLoader;
065        this.adapterManager = adapterManager;
066        this.servicesInjector = servicesInjector;
067    }
068
069    @Override
070    public List<ObjectAdapter> execute(final String search) {
071
072        cacheRepositoryAndRepositoryActionIfRequired();
073        if(repositoryAction == null || repository == null) {
074            return Collections.emptyList();
075        }
076        
077        final ObjectAdapter repositoryAdapter = adapterManager.getAdapterFor(repository);
078        final ObjectAdapter searchAdapter = adapterManager.adapterFor(search);
079        final ObjectAdapter resultAdapter = repositoryAction.execute(repositoryAdapter, new ObjectAdapter[] { searchAdapter} );
080        // check a collection was returned
081        if(CollectionFacetUtils.getCollectionFacetFromSpec(resultAdapter) == null) {
082            return Collections.emptyList();
083        }
084        return CollectionFacetUtils.convertToAdapterList(resultAdapter);
085    }
086
087    private void cacheRepositoryAndRepositoryActionIfRequired() {
088        if(!cachedRepositoryAction) {
089            cacheRepositoryAction();
090        }
091        if(!cachedRepositoryObject) {
092            cacheRepositoryObject();
093        }
094    }
095
096    private void cacheRepositoryAction() {
097        try {
098            final ObjectSpecification repositorySpec = specificationLoader.loadSpecification(repositoryClass);
099            final List<ObjectAction> objectActions = repositorySpec.getObjectActions(ActionType.USER, Contributed.EXCLUDED, ObjectAction.Filters.withId(actionName));
100
101            repositoryAction = objectActions.size() == 1? objectActions.get(0): null;
102        } finally {
103            cachedRepositoryAction = true;
104        }
105    }
106
107    private void cacheRepositoryObject() {
108        repository = servicesInjector.lookupService(repositoryClass);
109        cachedRepositoryObject = true;
110    }
111
112}