001    /*
002     * Copyright (C) 2012 eXo Platform SAS.
003     *
004     * This is free software; you can redistribute it and/or modify it
005     * under the terms of the GNU Lesser General Public License as
006     * published by the Free Software Foundation; either version 2.1 of
007     * the License, or (at your option) any later version.
008     *
009     * This software 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     * You should have received a copy of the GNU Lesser General Public
015     * License along with this software; if not, write to the Free
016     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018     */
019    package org.crsh.lang.impl.groovy.closure;
020    
021    import org.crsh.shell.impl.command.spi.Command;
022    import org.crsh.shell.impl.command.spi.CommandException;
023    import org.crsh.shell.impl.command.spi.CommandInvoker;
024    
025    import java.util.ArrayList;
026    import java.util.HashMap;
027    import java.util.Iterator;
028    import java.util.List;
029    import java.util.Map;
030    
031    /** @author Julien Viet */
032    class CommandElement extends PipeLineElement {
033    
034      /** . */
035      final String commandName;
036    
037      /** . */
038      final Command<?> command;
039    
040      /** . */
041      final Map<String, Object> options;
042    
043      /** . */
044      final String subordinate;
045    
046      /** . */
047      final Map<String, Object> subordinateOptions;
048    
049      /** . */
050      final List<Object> args;
051    
052      public CommandElement(String commandName, Command<?> command, Map<String, Object> options) {
053        this.commandName = commandName;
054        this.command = command;
055        this.options = options;
056        this.subordinate = null;
057        this.subordinateOptions = null;
058        this.args = null;
059      }
060    
061      public CommandElement subordinate(String name) {
062        return new CommandElement(
063            this.commandName + "." + name,
064            this.command,
065            this.options,
066            name,
067            this.subordinateOptions,
068            this.args);
069      }
070    
071      public CommandElement merge(Map<String, ?> options, List<?> arguments) {
072    
073        // We merge options
074        Map<String, Object> nextOptions;
075        if (subordinate == null) {
076          nextOptions = this.options;
077        } else {
078          nextOptions = this.subordinateOptions;
079        }
080        if (options != null && options.size() > 0) {
081          if (nextOptions == null) {
082            nextOptions = new HashMap<String, Object>();
083          } else {
084            nextOptions = new HashMap<String, Object>(options);
085          }
086          for (Map.Entry<?, ?> arg : options.entrySet()) {
087            nextOptions.put(arg.getKey().toString(), arg.getValue());
088          }
089        }
090    
091        // We merge arguments
092        List<Object> nextArgs;
093        if (arguments != null) {
094          nextArgs = new ArrayList<Object>();
095          if (this.args != null) {
096            nextArgs.addAll(this.args);
097          }
098          nextArgs.addAll(arguments);
099        } else {
100          nextArgs = this.args;
101        }
102    
103        //
104        if (subordinate == null) {
105          return new CommandElement(this.commandName, this.command, nextOptions, null, null, nextArgs);
106        } else {
107          return new CommandElement(this.commandName, this.command, this.options, subordinate, nextOptions, nextArgs);
108        }
109      }
110    
111      private CommandElement(String commandName, Command<?> command, Map<String, Object> options, String subordinate, Map<String, Object> subordinateOptions, List<Object> args) {
112        this.commandName = commandName;
113        this.command = command;
114        this.options = options;
115        this.subordinate = subordinate;
116        this.subordinateOptions = subordinateOptions;
117        this.args = args;
118      }
119    
120      @Override
121      CommandInvoker create() throws CommandException {
122        return command.resolveCommand(options, subordinate, subordinateOptions, args).getInvoker();
123      }
124    
125      private void format(Object o, StringBuilder buffer) {
126        if (o instanceof String) {
127          buffer.append('"').append(o).append('"');
128        } else if (o instanceof Boolean || o instanceof Number) {
129          buffer.append(o);
130        } else {
131          buffer.append('<').append(o).append('>');
132        }
133      }
134    
135      void toString(StringBuilder buffer) {
136        buffer.append(commandName);
137        boolean hasOptions = subordinateOptions != null && subordinateOptions.size() > 0;
138        boolean hasArguments = args != null && args.size() > 0;
139        if (hasOptions || hasArguments) {
140          buffer.append(" {");
141          if (hasOptions) {
142            for (Iterator<Map.Entry<String, Object>> i = subordinateOptions.entrySet().iterator();i.hasNext();) {
143              Map.Entry<String, Object> option = i.next();
144              buffer.append(' ').append(option.getKey()).append('=');
145              format(option.getValue(), buffer);
146              if (i.hasNext()) {
147                buffer.append(";");
148              }
149            }
150            if (hasArguments) {
151              buffer.append(";");
152            }
153          }
154          if (hasArguments) {
155            buffer.append(" [");
156            for (Iterator<Object> i = args.iterator();i.hasNext();) {
157              Object arg = i.next();
158              format(arg, buffer);
159              if (i.hasNext()) {
160                buffer.append(", ");
161              }
162            }
163            buffer.append("]");
164          }
165          buffer.append(" }");
166        }
167      }
168    }