001/*
002 * (C) Copyright 2006-2010 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.jaxrs.io;
020
021import java.io.ByteArrayOutputStream;
022import java.io.IOException;
023import java.io.OutputStream;
024import java.util.Arrays;
025import java.util.List;
026
027import org.codehaus.jackson.JsonEncoding;
028import org.codehaus.jackson.JsonFactory;
029import org.codehaus.jackson.JsonGenerator;
030import org.nuxeo.ecm.automation.AutomationService;
031import org.nuxeo.ecm.automation.OperationDocumentation;
032import org.nuxeo.ecm.automation.OperationDocumentation.Param;
033import org.nuxeo.ecm.automation.OperationException;
034import org.nuxeo.ecm.automation.core.Constants;
035import org.nuxeo.ecm.automation.io.services.codec.ObjectCodec;
036import org.nuxeo.ecm.automation.io.services.codec.ObjectCodecService;
037import org.nuxeo.ecm.automation.jaxrs.LoginInfo;
038import org.nuxeo.ecm.automation.jaxrs.io.operations.AutomationInfo;
039import org.nuxeo.ecm.platform.forms.layout.api.WidgetDefinition;
040import org.nuxeo.ecm.platform.forms.layout.io.JSONLayoutExporter;
041import org.nuxeo.ecm.webengine.JsonFactoryManager;
042import org.nuxeo.runtime.api.Framework;
043
044/**
045 * Json writer for operations export.
046 *
047 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
048 * @author <a href="mailto:grenard@nuxeo.com">Guillaume Renard</a>
049 */
050public class JsonWriter {
051
052    private static JsonFactory getFactory() {
053        return Framework.getService(JsonFactoryManager.class).getJsonFactory();
054    }
055
056    private static JsonGenerator createGenerator(OutputStream out) throws IOException {
057        return getFactory().createJsonGenerator(out, JsonEncoding.UTF8);
058    }
059
060    public static void writeAutomationInfo(OutputStream out, AutomationInfo info, boolean prettyPrint)
061            throws IOException {
062        writeAutomationInfo(createGenerator(out), info, prettyPrint);
063    }
064
065    public static void writeAutomationInfo(JsonGenerator jg, AutomationInfo info, boolean prettyPrint)
066            throws IOException {
067        if (prettyPrint) {
068            jg.useDefaultPrettyPrinter();
069        }
070        jg.writeStartObject();
071        writePaths(jg);
072        writeCodecs(jg);
073        writeOperations(jg, info);
074        writeChains(jg, info);
075        jg.writeEndObject();
076        jg.flush();
077    }
078
079    private static void writePaths(JsonGenerator jg) throws IOException {
080        jg.writeObjectFieldStart("paths");
081        jg.writeStringField("login", "login");
082        jg.writeEndObject();
083    }
084
085    private static void writeCodecs(JsonGenerator jg) throws IOException {
086        jg.writeArrayFieldStart("codecs");
087        ObjectCodecService codecs = Framework.getService(ObjectCodecService.class);
088        for (ObjectCodec<?> codec : codecs.getCodecs()) {
089            if (!codec.isBuiltin()) {
090                jg.writeString(codec.getClass().getName());
091            }
092        }
093        jg.writeEndArray();
094    }
095
096    /**
097     * Used to export operations to studio.
098     */
099    public static String exportOperations() throws IOException, OperationException {
100        return exportOperations(false);
101    }
102
103    /**
104     * Used to export operations to studio.
105     *
106     * @param filterNotInStudio if true, operation types not exposed in Studio will be filtered.
107     * @since 5.9.1
108     */
109    public static String exportOperations(boolean filterNotInStudio) throws IOException, OperationException {
110        List<OperationDocumentation> ops = Framework.getService(AutomationService.class).getDocumentation();
111        ByteArrayOutputStream out = new ByteArrayOutputStream();
112        JsonGenerator jg = getFactory().createJsonGenerator(out);
113        jg.useDefaultPrettyPrinter();
114        jg.writeStartObject();
115        jg.writeArrayFieldStart("operations");
116        for (OperationDocumentation op : ops) {
117            if (filterNotInStudio) {
118                if (op.addToStudio && !Constants.CAT_CHAIN.equals(op.category)) {
119                    writeOperation(jg, op);
120                }
121            } else {
122                writeOperation(jg, op);
123            }
124        }
125        jg.writeEndArray();
126        jg.writeEndObject();
127        jg.flush();
128        return out.toString("UTF-8");
129    }
130
131    private static void writeOperations(JsonGenerator jg, AutomationInfo info) throws IOException {
132        jg.writeArrayFieldStart("operations");
133        for (OperationDocumentation op : info.getOperations()) {
134            writeOperation(jg, op);
135        }
136        jg.writeEndArray();
137    }
138
139    private static void writeChains(JsonGenerator jg, AutomationInfo info) throws IOException {
140        jg.writeArrayFieldStart("chains");
141        for (OperationDocumentation op : info.getChains()) {
142            writeOperation(jg, op, Constants.CHAIN_ID_PREFIX + op.id);
143        }
144        jg.writeEndArray();
145    }
146
147    public static void writeOperation(OutputStream out, OperationDocumentation op) throws IOException {
148        writeOperation(out, op, false);
149    }
150
151    /**
152     * @since 5.9.4
153     */
154    public static void writeOperation(OutputStream out, OperationDocumentation op, boolean prettyPrint)
155            throws IOException {
156        writeOperation(createGenerator(out), op, prettyPrint);
157    }
158
159    public static void writeOperation(JsonGenerator jg, OperationDocumentation op) throws IOException {
160        writeOperation(jg, op, false);
161    }
162
163    /**
164     * @since 5.9.4
165     */
166    public static void writeOperation(JsonGenerator jg, OperationDocumentation op, boolean prettyPrint)
167            throws IOException {
168        writeOperation(jg, op, op.url, prettyPrint);
169    }
170
171    public static void writeOperation(JsonGenerator jg, OperationDocumentation op, String url) throws IOException {
172        writeOperation(jg, op, url, false);
173    }
174
175    /**
176     * @since 5.9.4
177     */
178    public static void writeOperation(JsonGenerator jg, OperationDocumentation op, String url, boolean prettyPrint)
179            throws IOException {
180        if (prettyPrint) {
181            jg.useDefaultPrettyPrinter();
182        }
183        jg.writeStartObject();
184        jg.writeStringField("id", op.id);
185        if (op.getAliases() != null && op.getAliases().length > 0) {
186            jg.writeArrayFieldStart("aliases");
187            for (String alias : op.getAliases()) {
188                jg.writeString(alias);
189            }
190            jg.writeEndArray();
191        }
192        jg.writeStringField("label", op.label);
193        jg.writeStringField("category", op.category);
194        jg.writeStringField("requires", op.requires);
195        jg.writeStringField("description", op.description);
196        if (op.since != null && op.since.length() > 0) {
197            jg.writeStringField("since", op.since);
198        }
199        jg.writeStringField("url", url);
200        jg.writeArrayFieldStart("signature");
201        for (String s : op.signature) {
202            jg.writeString(s);
203        }
204        jg.writeEndArray();
205        writeParams(jg, Arrays.asList(op.params));
206        if (op.widgetDefinitions != null && op.widgetDefinitions.length > 0) {
207            jg.writeArrayFieldStart("widgets");
208            for (WidgetDefinition wdef : op.widgetDefinitions) {
209                jg.writeObject(JSONLayoutExporter.exportToJson(wdef, null, null));
210            }
211            jg.writeEndArray();
212        }
213        jg.writeEndObject();
214        jg.flush();
215    }
216
217    private static void writeParams(JsonGenerator jg, List<Param> params) throws IOException {
218        jg.writeArrayFieldStart("params");
219        for (Param p : params) {
220            jg.writeStartObject();
221            jg.writeStringField("name", p.name);
222            jg.writeStringField("description", p.description);
223            jg.writeStringField("type", p.type);
224            jg.writeBooleanField("required", p.required);
225
226            jg.writeStringField("widget", p.widget);
227            jg.writeNumberField("order", p.order);
228            jg.writeArrayFieldStart("values");
229            for (String value : p.values) {
230                jg.writeString(value);
231            }
232            jg.writeEndArray();
233            jg.writeEndObject();
234        }
235        jg.writeEndArray();
236    }
237
238    public static void writeLogin(OutputStream out, LoginInfo login) throws IOException {
239        writeLogin(createGenerator(out), login);
240    }
241
242    public static void writeLogin(JsonGenerator jg, LoginInfo login) throws IOException {
243        jg.writeStartObject();
244        jg.writeStringField("entity-type", "login");
245        jg.writeStringField("username", login.getUsername());
246        jg.writeBooleanField("isAdministrator", login.isAdministrator());
247        jg.writeArrayFieldStart("groups");
248        for (String group : login.getGroups()) {
249            jg.writeString(group);
250        }
251        jg.writeEndArray();
252        jg.writeEndObject();
253        jg.flush();
254    }
255
256    public static void writePrimitive(OutputStream out, Object value) throws IOException {
257        writePrimitive(createGenerator(out), value);
258    }
259
260    public static void writePrimitive(JsonGenerator jg, Object value) throws IOException {
261        jg.writeStartObject();
262        jg.writeStringField("entity-type", "primitive");
263        if (value != null) {
264            Class<?> type = value.getClass();
265            if (type == String.class) {
266                jg.writeStringField("value", (String) value);
267            } else if (type == Boolean.class) {
268                jg.writeBooleanField("value", (Boolean) value);
269            } else if (type == Long.class) {
270                jg.writeNumberField("value", ((Number) value).longValue());
271            } else if (type == Double.class) {
272                jg.writeNumberField("value", ((Number) value).doubleValue());
273            } else if (type == Integer.class) {
274                jg.writeNumberField("value", ((Number) value).intValue());
275            } else if (type == Float.class) {
276                jg.writeNumberField("value", ((Number) value).floatValue());
277            }
278        } else {
279            jg.writeNullField("value");
280        }
281        jg.writeEndObject();
282        jg.flush();
283    }
284
285}