001/*
002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
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 *
016 * Contributors:
017 *     bstefanescu
018 */
019package org.nuxeo.ecm.automation.client.jaxrs.spi;
020
021import java.io.IOException;
022import java.text.SimpleDateFormat;
023import java.util.ArrayList;
024import java.util.Calendar;
025import java.util.Date;
026import java.util.HashMap;
027import java.util.List;
028import java.util.Map;
029
030import org.nuxeo.ecm.automation.client.OperationRequest;
031import org.nuxeo.ecm.automation.client.model.DateUtils;
032import org.nuxeo.ecm.automation.client.model.Document;
033import org.nuxeo.ecm.automation.client.model.OperationDocumentation;
034import org.nuxeo.ecm.automation.client.model.OperationDocumentation.Param;
035import org.nuxeo.ecm.automation.client.model.OperationInput;
036
037/**
038 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
039 */
040public class DefaultOperationRequest implements OperationRequest {
041
042    protected final OperationDocumentation op;
043
044    protected final DefaultSession session;
045
046    protected final Map<String, Object> params;
047
048    protected final Map<String, Object> ctx;
049
050    protected final Map<String, String> headers;
051
052    protected Object input;
053
054    public DefaultOperationRequest(DefaultSession session, OperationDocumentation op) {
055        this(session, op, new HashMap<String, Object>());
056    }
057
058    public DefaultOperationRequest(DefaultSession session, OperationDocumentation op, Map<String, Object> ctx) {
059        this.session = session;
060        this.op = op;
061        params = new HashMap<String, Object>();
062        headers = new HashMap<String, String>();
063        this.ctx = ctx;
064    }
065
066    public DefaultSession getSession() {
067        return session;
068    }
069
070    protected final boolean acceptInput(String type) {
071        for (int i = 0, size = op.signature.length; i < size; i += 2) {
072            if ("void".equals(op.signature[i])) {
073                return true;
074            }
075            if (type.equals(op.signature[i])) {
076                return true;
077            }
078        }
079        return false;
080    }
081
082    protected final void checkInput(String type) {
083        if (!acceptInput(type)) {
084            throw new IllegalArgumentException("Input not supported: " + type + " for the operation: " + op.id);
085        }
086    }
087
088    public List<String> getParamNames() {
089        List<String> result = new ArrayList<String>();
090        for (Param param : op.params) {
091            result.add(param.name);
092        }
093        return result;
094    }
095
096    public Param getParam(String key) {
097        for (Param param : op.params) {
098            if (key.equals(param.name)) {
099                return param;
100            }
101        }
102        return null;
103    }
104
105    public OperationRequest setInput(Object input) {
106        if (input == null) {
107            checkInput("void");
108        } else if (input instanceof OperationInput) {
109            checkInput(((OperationInput) input).getInputType());
110        }
111        this.input = input;
112        return this;
113    }
114
115    public Object getInput() {
116        return input;
117    }
118
119    public String getUrl() {
120        return session.getClient().getBaseUrl() + op.url;
121    }
122
123    public OperationRequest set(String key, Object value) {
124        Param param = getParam(key);
125        if (param == null) {
126            throw new IllegalArgumentException("No such parameter '" + key + "' for operation " + op.id
127                    + ".\n\tAvailable params: " + getParamNames());
128        }
129        if (value == null) {
130            params.remove(key);
131            return this;
132        }
133        // handle strings and primitive differently
134        // TODO
135        // if (!param.type.equals(value.getParamType())) {
136        // throw new
137        // IllegalArgumentException("Invalid parameter type:
138        // "+value.getParamType());
139        // }
140        if (value.getClass() == Date.class) {
141            params.put(key, DateUtils.formatDate((Date) value));
142        } else if (value instanceof Calendar){
143            params.put(key, DateUtils.formatDate(((Calendar) value).getTime()));
144        } else if ("properties".equals(key) && value instanceof Document) {
145            // Handle document parameter in case of properties - and bind it to
146            // properties
147            List<Param> parameters = op.getParams();
148            for (Param parameter : parameters) {
149                // Check if one of params has the Properties type
150                if ("properties".equals(parameter.getType())) {
151                    params.put("properties", ((Document) value).getDirties().toString());
152                }
153            }
154        } else {
155            params.put(key, value);
156        }
157        return this;
158    }
159
160    public OperationRequest setContextProperty(String key, Object value) {
161        ctx.put(key, value);
162        return this;
163    }
164
165    public Map<String, Object> getContextParameters() {
166        return ctx;
167    }
168
169    public Map<String, Object> getParameters() {
170        return params;
171    }
172
173    public Object execute() throws IOException {
174        return session.execute(this);
175    }
176
177    public OperationRequest setHeader(String key, String value) {
178        headers.put(key, value);
179        return this;
180    }
181
182    public Map<String, String> getHeaders() {
183        return headers;
184    }
185
186    @Override
187    public OperationDocumentation getOperation() {
188        return op;
189    }
190}