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