/*
* 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.brooklyn.rest.util.json;
import java.io.IOException;
import java.util.Map;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.location.Location;
import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.api.objs.BrooklynObject;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;
import org.codehaus.jackson.map.module.SimpleModule;
public class BidiSerialization {
protected final static ThreadLocal<Boolean> STRICT_SERIALIZATION = new ThreadLocal<Boolean>();
/**
* Sets strict serialization on, or off (the default), for the current thread.
* Recommended to be used in a <code>try { ... } finally { ... }</code> block
* with {@link #clearStrictSerialization()} at the end.
* <p>
* With strict serialization, classes must have public fields or annotated fields, else they will not be serialized.
*/
public static void setStrictSerialization(Boolean value) {
STRICT_SERIALIZATION.set(value);
}
public static void clearStrictSerialization() {
STRICT_SERIALIZATION.remove();
}
public static boolean isStrictSerialization() {
Boolean result = STRICT_SERIALIZATION.get();
if (result!=null) return result;
return false;
}
public abstract static class AbstractWithManagementContextSerialization<T> {
protected class Serializer extends JsonSerializer<T> {
@Override
public void serialize(T value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
AbstractWithManagementContextSerialization.this.serialize(value, jgen, provider);
}
}
protected class Deserializer extends JsonDeserializer<T> {
@Override
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
return AbstractWithManagementContextSerialization.this.deserialize(jp, ctxt);
}
}
protected final Serializer serializer = new Serializer();
protected final Deserializer deserializer = new Deserializer();
protected final Class<T> type;
protected final ManagementContext mgmt;
public AbstractWithManagementContextSerialization(Class<T> type, ManagementContext mgmt) {
this.type = type;
this.mgmt = mgmt;
}
public JsonSerializer<T> getSerializer() {
return serializer;
}
public JsonDeserializer<T> getDeserializer() {
return deserializer;
}
public void serialize(T value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
jgen.writeStartObject();
writeBody(value, jgen, provider);
jgen.writeEndObject();
}
protected void writeBody(T value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException, JsonProcessingException {
jgen.writeStringField("type", value.getClass().getCanonicalName());
customWriteBody(value, jgen, provider);
}
public abstract void customWriteBody(T value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException;
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
@SuppressWarnings("unchecked")
Map<Object,Object> values = jp.readValueAs(Map.class);
String type = (String) values.get("type");
return customReadBody(type, values, jp, ctxt);
}
protected abstract T customReadBody(String type, Map<Object, Object> values, JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException;
public void install(SimpleModule module) {
module.addSerializer(type, serializer);
module.addDeserializer(type, deserializer);
}
}
public static class ManagementContextSerialization extends AbstractWithManagementContextSerialization<ManagementContext> {
public ManagementContextSerialization(ManagementContext mgmt) { super(ManagementContext.class, mgmt); }
@Override
public void customWriteBody(ManagementContext value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {}
@Override
protected ManagementContext customReadBody(String type, Map<Object, Object> values, JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
return mgmt;
}
}
public abstract static class AbstractBrooklynObjectSerialization<T extends BrooklynObject> extends AbstractWithManagementContextSerialization<T> {
public AbstractBrooklynObjectSerialization(Class<T> type, ManagementContext mgmt) {
super(type, mgmt);
}
@Override
protected void writeBody(T value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException, JsonProcessingException {
jgen.writeStringField("type", type.getCanonicalName());
customWriteBody(value, jgen, provider);
}
@Override
public void customWriteBody(T value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
jgen.writeStringField("id", value.getId());
}
@Override
protected T customReadBody(String type, Map<Object, Object> values, JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
return getInstanceFromId((String) values.get("id"));
}
protected abstract T getInstanceFromId(String id);
}
public static class EntitySerialization extends AbstractBrooklynObjectSerialization<Entity> {
public EntitySerialization(ManagementContext mgmt) { super(Entity.class, mgmt); }
@Override protected Entity getInstanceFromId(String id) { return mgmt.getEntityManager().getEntity(id); }
}
public static class LocationSerialization extends AbstractBrooklynObjectSerialization<Location> {
public LocationSerialization(ManagementContext mgmt) { super(Location.class, mgmt); }
@Override protected Location getInstanceFromId(String id) { return mgmt.getLocationManager().getLocation(id); }
}
// TODO how to look up policies and enrichers? (not essential...)
// public static class PolicySerialization extends AbstractBrooklynObjectSerialization<Policy> {
// public EntitySerialization(ManagementContext mgmt) { super(Policy.class, mgmt); }
// @Override protected Policy getKind(String id) { return mgmt.getEntityManager().getEntity(id); }
// }
// public static class EnricherSerialization extends AbstractBrooklynObjectSerialization<Enricher> {
// public EntitySerialization(ManagementContext mgmt) { super(Entity.class, mgmt); }
// @Override protected Enricher getKind(String id) { return mgmt.getEntityManager().getEntity(id); }
// }
}