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.automation.cmds;
018
019import java.io.File;
020import java.util.ArrayList;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024
025import jline.Completor;
026
027import org.nuxeo.ecm.automation.client.model.DocRef;
028import org.nuxeo.ecm.automation.client.model.FileBlob;
029import org.nuxeo.ecm.automation.client.model.OperationDocumentation;
030import org.nuxeo.ecm.automation.client.model.OperationDocumentation.Param;
031import org.nuxeo.ecm.automation.client.model.OperationInput;
032import org.nuxeo.shell.Shell;
033import org.nuxeo.shell.ShellException;
034import org.nuxeo.shell.automation.DocRefCompletor;
035import org.nuxeo.shell.fs.FileCompletor;
036import org.nuxeo.shell.impl.AbstractCommandType;
037
038/**
039 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
040 */
041public class OperationCommandType extends AbstractCommandType {
042
043    public static final int TYPE_VOID = 0;
044
045    public static final int TYPE_DOC = 1;
046
047    public static final int TYPE_BLOB = 2;
048
049    public static final int TYPE_DOCS = 3;
050
051    public static final int TYPE_BLOBS = 4;
052
053    protected OperationDocumentation op;
054
055    protected int inputType = 0;
056
057    public boolean hasVoidInput() {
058        return inputType == 0;
059    }
060
061    public boolean hasBlobInput() {
062        return inputType == 2;
063    }
064
065    public boolean hasDocumentInput() {
066        return inputType == 1;
067    }
068
069    public int getInputType() {
070        return inputType;
071    }
072
073    public static OperationCommandType fromOperation(OperationDocumentation op) {
074        int inputType = 0;
075        HashMap<String, Token> params = new HashMap<String, Token>();
076        ArrayList<Token> args = new ArrayList<Token>();
077
078        Token tok = new Token();
079        tok.name = "-void";
080        tok.help = "If void the server will not return the result back";
081        tok.isRequired = false;
082        tok.setter = new OperationParamSetter(tok.name, "boolean");
083        params.put(tok.name, tok);
084        tok = new Token();
085        tok.name = "-ctx";
086        tok.help = "Can be used to inject context properties in Java properties format";
087        tok.isRequired = true;
088        tok.setter = new OperationParamSetter(tok.name, "string");
089        params.put(tok.name, tok);
090
091        for (Param param : op.getParams()) {
092            tok = new Token();
093            tok.name = "-" + param.name;
094            tok.help = "";
095            tok.isRequired = true;
096            OperationParamSetter os = new OperationParamSetter(param.name, param.getType());
097            tok.setter = os;
098            tok.completor = os.completor;
099            params.put(tok.name, tok);
100        }
101
102        inputType = getOperationInputType(op);
103        if (inputType == TYPE_DOC || inputType == TYPE_DOCS) {
104            tok = new Token();
105            tok.index = 0;
106            tok.isRequired = false;
107            tok.name = "the input document(s)";
108            tok.setter = new DocInputSetter();
109            tok.completor = DocRefCompletor.class;
110            args.add(tok);
111        } else if (inputType == TYPE_BLOB || inputType == TYPE_BLOBS) {
112            tok = new Token();
113            tok.index = 0;
114            tok.isRequired = true;
115            tok.name = "the input file(s)";
116            tok.setter = new BlobInputSetter();
117            tok.completor = FileCompletor.class;
118            args.add(tok);
119        }
120        return new OperationCommandType(inputType, op, params, args);
121    }
122
123    public static int getOperationInputType(OperationDocumentation op) {
124        for (int i = 0; i < op.signature.length; i += 2) {
125            if ("void".equals(op.signature[i])) {
126                return TYPE_VOID;
127            }
128            if ("document".equals(op.signature[i])) {
129                return TYPE_DOC;
130            }
131            if ("blob".equals(op.signature[i])) {
132                return TYPE_BLOB;
133            }
134            if ("documents".equals(op.signature[i])) {
135                return TYPE_DOCS;
136            }
137            if ("bloblist".equals(op.signature[i])) {
138                return TYPE_BLOBS;
139            }
140        }
141        return TYPE_VOID;
142    }
143
144    public OperationCommandType(int inputType, OperationDocumentation op, Map<String, Token> params, List<Token> args) {
145        super(OperationCommand.class, null, params, args);
146        this.op = op;
147        this.inputType = inputType;
148    }
149
150    public String getHelp() {
151        return op.description;
152    }
153
154    public String[] getAliases() {
155        return new String[0];
156    }
157
158    public String getName() {
159        return op.id;
160    }
161
162    @Override
163    protected Runnable createInstance(Shell shell) throws Exception {
164        OperationCommand cmd = (OperationCommand) cmdClass.newInstance();
165        cmd.init(this, shell, op);
166        return cmd;
167    }
168
169    public static class OperationParamSetter implements Setter {
170        protected String name;
171
172        protected Class<?> type;
173
174        protected Class<? extends Completor> completor;
175
176        public OperationParamSetter(String name, String type) {
177            this.name = name;
178            if ("document".equals(type)) {
179                this.type = DocRef.class;
180                this.completor = DocRefCompletor.class;
181            } else if ("blob".equals(type)) {
182                this.type = File.class;
183                this.completor = FileCompletor.class;
184            } else {
185                this.type = String.class;
186            }
187        }
188
189        public Class<?> getType() {
190            return type;
191        }
192
193        public void set(Object obj, Object value) throws ShellException {
194            if (value instanceof File) {
195                value = new FileBlob((File) value);
196            }
197            ((OperationCommand) obj).setParam(name, value);
198        }
199    }
200
201    public static class DocInputSetter implements Setter {
202
203        public Class<?> getType() {
204            return DocRef.class;
205        }
206
207        public void set(Object obj, Object value) throws ShellException {
208            ((OperationCommand) obj).request.setInput((OperationInput) value);
209        }
210    }
211
212    public static class BlobInputSetter implements Setter {
213        public Class<?> getType() {
214            return File.class;
215        }
216
217        public void set(Object obj, Object value) throws ShellException {
218            ((OperationCommand) obj).request.setInput(new FileBlob((File) value));
219        }
220
221    }
222
223}