001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.chain.impl;
018
019import java.util.Iterator;
020import java.util.Map;
021import java.util.concurrent.ConcurrentHashMap;
022
023import org.apache.commons.chain.Catalog;
024import org.apache.commons.chain.Command;
025import org.apache.commons.chain.Context;
026
027/**
028 * Simple in-memory implementation of {@link Catalog}. This class can
029 * also be used as the basis for more advanced implementations.
030 *
031 * <p>This implementation is thread-safe.</p>
032 *
033 * @param <C> Type of the context associated with this catalog
034 *
035 * @author Craig R. McClanahan
036 * @author Matthew J. Sgarlata
037 * @version $Revision$ $Date$
038 */
039public class CatalogBase<C extends Context> implements Catalog<C> {
040
041    // ----------------------------------------------------- Instance Variables
042
043    /**
044     * The map of named {@link Command}s, keyed by name.
045     */
046    private final Map<String, Command<C>> commands;
047
048    // --------------------------------------------------------- Constructors
049
050    /**
051     * Create an empty catalog.
052     */
053    public CatalogBase() {
054        commands = new ConcurrentHashMap<>();
055    }
056
057    /**
058     * Create a catalog whose commands are those specified in the given {@code Map}.
059     * All Map keys should be {@code String} and all values should be {@code Command}.
060     *
061     * @param commands Map of Commands.
062     *
063     * @since Chain 1.1
064     */
065    public CatalogBase(Map<String, Command<C>> commands) {
066        this.commands = new ConcurrentHashMap<>(commands);
067    }
068
069    // --------------------------------------------------------- Public Methods
070
071    /**
072     * Add a new name and associated {@link Command}
073     * to the set of named commands known to this {@link Catalog},
074     * replacing any previous command for that name.
075     *
076     * @param <CMD> the {@link Command} type to be added in the {@link Catalog}
077     * @param name Name of the new command
078     * @param command {@link Command} to be returned
079     *        for later lookups on this name
080     */
081    @Override
082    public <CMD extends Command<C>> void addCommand(String name, CMD command) {
083        commands.put(name, command);
084    }
085
086    /**
087     * Return the {@link Command} associated with the
088     * specified name, if any; otherwise, return {@code null}.
089     *
090     * @param <CMD> the expected {@link Command} type to be returned
091     * @param name Name for which a {@link Command}
092     *        should be retrieved
093     *
094     * @return The Command associated with the specified name.
095     */
096    @Override
097    public <CMD extends Command<C>> CMD getCommand(String name) {
098        @SuppressWarnings("unchecked") // it would throw ClassCastException if users try to cast to a different type
099        CMD command = (CMD) commands.get(name);
100        return command;
101    }
102
103    /**
104     * Return an {@code Iterator} over the set of named commands
105     * known to this {@link Catalog}. If there are no known commands,
106     * an empty Iterator is returned.
107     *
108     * @return An iterator of the names in this Catalog.
109     */
110    @Override
111    public Iterator<String> getNames() {
112        return commands.keySet().iterator();
113    }
114
115    /**
116     * Converts this Catalog to a String. Useful for debugging purposes.
117     *
118     * @return a representation of this catalog as a String
119     */
120    @Override
121    public String toString() {
122        Iterator<String> names = getNames();
123        StringBuilder str = new StringBuilder();
124        str
125            .append('[')
126            .append(this.getClass().getName())
127            .append(": ");
128
129        while (names.hasNext()) {
130            str.append(names.next());
131            if (names.hasNext()) {
132                str.append(", ");
133            }
134        }
135        str.append(']');
136
137        return str.toString();
138    }
139}