001/*
002 * (C) Copyright 2006-2010 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     bstefanescu
016 */
017package org.nuxeo.shell;
018
019import java.util.Arrays;
020import java.util.Comparator;
021import java.util.HashMap;
022import java.util.HashSet;
023import java.util.LinkedHashMap;
024import java.util.Map;
025import java.util.Set;
026import java.util.TreeSet;
027
028import org.nuxeo.shell.impl.DefaultCommandType;
029
030/**
031 * A command registry associated to a given domain name. Registries are named so each registry is using a different
032 * namespace. For example you can have a "local" and a "remote" namespace using different command registries. Commands
033 * in local namespace are working on the filesystem while the one in remote namespace are working on a remote server.
034 *
035 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
036 */
037public abstract class CommandRegistry {
038
039    protected String name;
040
041    protected CommandRegistry parent;
042
043    protected Map<String, CommandType> cmds;
044
045    public CommandRegistry(CommandRegistry parent, String name) {
046        cmds = new HashMap<String, CommandType>();
047        this.parent = parent;
048        this.name = name;
049    }
050
051    public abstract String getTitle();
052
053    public abstract String getDescription();
054
055    public String getName() {
056        return name;
057    }
058
059    public CommandRegistry getParent() {
060        return parent;
061    }
062
063    public void addCommandType(CommandType type) {
064        cmds.put(type.getName(), type);
065        String[] aliases = type.getAliases();
066        if (aliases != null && aliases.length > 0) {
067            for (String alias : aliases) {
068                cmds.put(alias, type);
069            }
070        }
071    }
072
073    public void addAnnotatedCommand(Class<? extends Runnable> clazz) {
074        addCommandType(DefaultCommandType.fromAnnotatedClass(clazz));
075    }
076
077    public CommandType getCommandType(String name) {
078        CommandType type = cmds.get(name);
079        if (type == null && parent != null) {
080            type = parent.getCommandType(name);
081        }
082        return type;
083    }
084
085    public Set<CommandType> getCommandTypeSet() {
086        HashSet<CommandType> set = new HashSet<CommandType>();
087        if (parent != null) {
088            set.addAll(parent.getCommandTypeSet());
089        }
090        set.addAll(cmds.values());
091        return set;
092    }
093
094    public CommandType[] getCommandTypes() {
095        Set<CommandType> set = getCommandTypeSet();
096        CommandType[] ar = set.toArray(new CommandType[set.size()]);
097        Arrays.sort(ar, new Comparator<CommandType>() {
098            public int compare(CommandType o1, CommandType o2) {
099                return o1.getName().compareTo(o2.getName());
100            }
101        });
102        return ar;
103    }
104
105    public CommandType[] getLocalCommandTypes() {
106        CommandType[] ar = cmds.values().toArray(new CommandType[cmds.size()]);
107        Arrays.sort(ar, new Comparator<CommandType>() {
108            public int compare(CommandType o1, CommandType o2) {
109                return o1.getName().compareTo(o2.getName());
110            }
111        });
112        return ar;
113    }
114
115    protected void collectCommandTypesByNamespace(Map<String, Set<CommandType>> map) {
116        if (parent != null) {
117            parent.collectCommandTypesByNamespace(map);
118        }
119        TreeSet<CommandType> set = new TreeSet<CommandType>();
120        for (CommandType cmd : cmds.values()) {
121            set.add(cmd);
122        }
123        map.put(getName(), set);
124    }
125
126    public Map<String, Set<CommandType>> getCommandTypesByNamespace() {
127        LinkedHashMap<String, Set<CommandType>> map = new LinkedHashMap<String, Set<CommandType>>();
128        collectCommandTypesByNamespace(map);
129        return map;
130    }
131
132    public Set<String> getCommandNameSet() {
133        HashSet<String> set = new HashSet<String>();
134        if (parent != null) {
135            set.addAll(parent.getCommandNameSet());
136        }
137        set.addAll(cmds.keySet());
138        return set;
139    }
140
141    /**
142     * Get sorted command names including aliases
143     *
144     * @return
145     */
146    public String[] getCommandNames() {
147        Set<String> set = getCommandNameSet();
148        String[] ar = set.toArray(new String[set.size()]);
149        Arrays.sort(ar);
150        return ar;
151    }
152
153    public void clear() {
154        cmds.clear();
155    }
156
157    /**
158     * Override this to provide a custom prompt for your command namespace
159     *
160     * @param shell
161     * @return
162     */
163    public String getPrompt(Shell shell) {
164        return "> ";
165    }
166
167    /**
168     * Override this to automatically run some commands at startup if needed. This is invoked by the interactive mode
169     * just after it was started on the current namespace. This way you can do some initialization for your namespace if
170     * needed - like automatically connecting to remote if connection details were filled to the application command
171     * line arguments.
172     */
173    public void autorun(Shell shell) {
174
175    }
176}