001/*
002 *  Copyright 2018 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.runtime.model;
017
018import java.util.Collection;
019
020import org.apache.commons.lang3.StringUtils;
021
022import org.ametys.runtime.model.exception.UndefinedItemPathException;
023
024/**
025 * Interface for model item containers
026 */
027public interface ModelItemContainer
028{
029    /**
030     * Retrieves the child model item with the given name
031     * @param childName name of the model item child to retrieve
032     * @return the child with the given name, or <code>null</code> if no child is found
033     */
034    public default ModelItem getChild(String childName)
035    {
036        for (ModelItem child : getModelItems())
037        {
038            if (child.getName().equals(childName))
039            {
040                return child;
041            }
042        }
043
044        return null;
045    }
046    
047    /**
048     * Retrieves the model item at given path
049     * @param itemPath the item path
050     * @return the model item.
051     * @throws UndefinedItemPathException if there is no item defined at the given path 
052     */
053    public default ModelItem getModelItem(String itemPath) throws UndefinedItemPathException
054    {
055        String[] pathSegments = StringUtils.split(itemPath, ModelItem.ITEM_PATH_SEPARATOR);
056        
057        if (pathSegments.length > 0)
058        {
059            ModelItemContainer currentContainer = this;
060            ModelItem child = null;
061            for (int i = 0; i < pathSegments.length; i++)
062            {
063                child = currentContainer.getChild(pathSegments[i]);
064
065                if (child == null)
066                {
067                    throw new UndefinedItemPathException("The item at path '" + itemPath + "' is not defined in the model item container '" + toString() + "'.");
068                }
069                else if (i < pathSegments.length - 1 && !(child instanceof ModelItemContainer))
070                {
071                    String currentContainerPath = StringUtils.join(pathSegments, ModelItem.ITEM_PATH_SEPARATOR, 0, i + 1);
072                    String subItemPath = StringUtils.join(pathSegments, ModelItem.ITEM_PATH_SEPARATOR, i + 1, pathSegments.length);
073                    throw new UndefinedItemPathException("In the model item container '" + toString() + "', the item at path '" + currentContainerPath + "' is not a model item container. So it can not contain a sub item with path '" + subItemPath + "'.");
074                }
075                else if (child instanceof ModelItemContainer)
076                {
077                    currentContainer = (ModelItemContainer) child;
078                }
079            }
080            
081            return child;
082        }
083        else
084        {
085            throw new UndefinedItemPathException("The item at path '" + itemPath + "' is not defined in the model item container '" + toString() + "'.");
086        }
087    }
088    
089    /**
090     * Checks if there is an item defined with the given path
091     * @param itemPath path of the item
092     * @return <code>true</code> if there is an item, <code>false</code> otherwise
093     */
094    public default boolean hasModelItem(String itemPath)
095    {
096        try
097        {
098            getModelItem(itemPath);
099            return true;
100        }
101        catch (UndefinedItemPathException e)
102        {
103            // The getModelItem method throws an UndefinedItemPathException if there is no model item defined with the given path 
104            return false;
105        }
106    }
107    
108    /**
109     * Retrieves all the model items of this container
110     * @return the model items
111     */
112    public Collection<? extends ModelItem> getModelItems();
113}