blob: 735d7cf73e20dc6c7637a2e08aa9eb69fc868fc3 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.framework.jobs.impl;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import com.cloud.utils.exception.CloudRuntimeException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
/**
* Note: toPairList and appendPairList only support simple POJO objects currently
*/
public class JobSerializerHelper {
private static final Logger s_logger = Logger.getLogger(JobSerializerHelper.class);
public static final String token = "/";
private static Gson s_gson;
static {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setVersion(1.5);
s_logger.debug("Job GSON Builder initialized.");
gsonBuilder.registerTypeAdapter(Class.class, new ClassTypeAdapter());
gsonBuilder.registerTypeAdapter(Throwable.class, new ThrowableTypeAdapter());
s_gson = gsonBuilder.create();
}
public static String toSerializedString(Object result) {
if (result != null) {
Class<?> clz = result.getClass();
return clz.getName() + token + s_gson.toJson(result);
}
return null;
}
public static Object fromSerializedString(String result) {
try {
if (result != null && !result.isEmpty()) {
String[] serializedParts = result.split(token);
if (serializedParts.length < 2) {
return null;
}
String clzName = serializedParts[0];
String nameField = null;
String content = null;
if (serializedParts.length == 2) {
content = serializedParts[1];
} else {
nameField = serializedParts[1];
int index = result.indexOf(token + nameField + token);
content = result.substring(index + nameField.length() + 2);
}
Class<?> clz;
try {
clz = Class.forName(clzName);
} catch (ClassNotFoundException e) {
return null;
}
Object obj = s_gson.fromJson(content, clz);
return obj;
}
return null;
} catch (RuntimeException e) {
throw new CloudRuntimeException("Unable to deserialize: " + result, e);
}
}
public static String toObjectSerializedString(Serializable object) {
assert (object != null);
ByteArrayOutputStream bs = new ByteArrayOutputStream();
try {
ObjectOutputStream os = new ObjectOutputStream(bs);
os.writeObject(object);
os.close();
bs.close();
return Base64.encodeBase64URLSafeString(bs.toByteArray());
} catch (IOException e) {
throw new CloudRuntimeException("Unable to serialize: " + object, e);
}
}
public static Object fromObjectSerializedString(String base64EncodedString) {
if (base64EncodedString == null)
return null;
byte[] content = Base64.decodeBase64(base64EncodedString);
ByteArrayInputStream bs = new ByteArrayInputStream(content);
try {
ObjectInputStream is = new ObjectInputStream(bs);
Object obj = is.readObject();
is.close();
bs.close();
return obj;
} catch (IOException e) {
throw new CloudRuntimeException("Unable to serialize: " + base64EncodedString, e);
} catch (ClassNotFoundException e) {
throw new CloudRuntimeException("Unable to serialize: " + base64EncodedString, e);
}
}
public static class ClassTypeAdapter implements JsonSerializer<Class<?>>, JsonDeserializer<Class<?>> {
@Override
public JsonElement serialize(Class<?> clazz, Type typeOfResponseObj, JsonSerializationContext ctx) {
return new JsonPrimitive(clazz.getName());
}
@Override
public Class<?> deserialize(JsonElement arg0, Type arg1, JsonDeserializationContext arg2) throws JsonParseException {
String str = arg0.getAsString();
try {
return Class.forName(str);
} catch (ClassNotFoundException e) {
throw new CloudRuntimeException("Unable to find class " + str);
}
}
}
public static class ThrowableTypeAdapter implements JsonSerializer<Throwable>, JsonDeserializer<Throwable> {
@Override
public Throwable deserialize(JsonElement json, Type type, JsonDeserializationContext ctx) throws JsonParseException {
JsonObject obj = (JsonObject)json;
String className = obj.get("class").getAsString();
try {
Class<Throwable> clazz = (Class<Throwable>)Class.forName(className);
Throwable cause = s_gson.fromJson(obj.get("cause"), Throwable.class);
String msg = obj.get("msg").getAsString();
Constructor<Throwable> constructor = clazz.getConstructor(String.class, Throwable.class);
Throwable th = constructor.newInstance(msg, cause);
return th;
} catch (ClassNotFoundException e) {
throw new JsonParseException("Unable to find " + className);
} catch (NoSuchMethodException e) {
throw new JsonParseException("Unable to find constructor for " + className);
} catch (SecurityException e) {
throw new JsonParseException("Unable to get over security " + className);
} catch (InstantiationException e) {
throw new JsonParseException("Unable to instantiate " + className);
} catch (IllegalAccessException e) {
throw new JsonParseException("Illegal access to " + className, e);
} catch (IllegalArgumentException e) {
throw new JsonParseException("Illegal argument to " + className, e);
} catch (InvocationTargetException e) {
throw new JsonParseException("Cannot invoke " + className, e);
}
}
@Override
public JsonElement serialize(Throwable th, Type type, JsonSerializationContext ctx) {
JsonObject json = new JsonObject();
json.add("class", new JsonPrimitive(th.getClass().getName()));
json.add("cause", s_gson.toJsonTree(th.getCause()));
json.add("msg", new JsonPrimitive(th.getMessage()));
// json.add("stack", s_gson.toJsonTree(th.getStackTrace()));
return json;
}
}
}