/**
* Copyright 2014-2017 Linagora, Université Joseph Fourier, Floralis
*
* The present code is developed in the scope of the joint LINAGORA -
* Université Joseph Fourier - Floralis research program and is designated
* as a "Result" pursuant to the terms and conditions of the LINAGORA
* - Université Joseph Fourier - Floralis research program. Each copyright
* holder of Results enumerated here above fully & independently holds complete
* ownership of the complete Intellectual Property rights applicable to the whole
* of said Results, and may freely exploit it in any manner which does not infringe
* the moral rights of the other copyright holders.
*
* Licensed 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 net.roboconf.dm.rest.commons.json;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import net.roboconf.core.model.beans.Application;
import net.roboconf.core.model.beans.ApplicationTemplate;
import net.roboconf.core.model.beans.Component;
import net.roboconf.core.model.beans.Instance;
import net.roboconf.core.model.beans.Instance.InstanceStatus;
import net.roboconf.core.model.helpers.ComponentHelpers;
import net.roboconf.core.model.helpers.InstanceHelpers;
import net.roboconf.core.model.helpers.VariableHelpers;
import net.roboconf.core.model.runtime.Preference;
import net.roboconf.core.model.runtime.Preference.PreferenceKeyCategory;
import net.roboconf.core.model.runtime.ScheduledJob;
import net.roboconf.core.model.runtime.TargetUsageItem;
import net.roboconf.core.model.runtime.TargetWrapperDescriptor;
import net.roboconf.core.utils.IconUtils;
import net.roboconf.core.utils.Utils;
import net.roboconf.dm.rest.commons.Diagnostic;
import net.roboconf.dm.rest.commons.Diagnostic.DependencyInformation;
import net.roboconf.dm.rest.commons.beans.ApplicationBindings;
import net.roboconf.dm.rest.commons.beans.ApplicationBindings.ApplicationBindingItem;
import net.roboconf.dm.rest.commons.beans.TargetAssociation;
import net.roboconf.dm.rest.commons.beans.WebSocketMessage;
/**
* A set of utilities to bind Roboconf's runtime model to JSon.
* @author Vincent Zurczak - Linagora
*/
public final class JSonBindingUtils {
// Annotations set by the deserializers
public static final String AT_INSTANCE_PATH = "@instance_path";
// We use global maps to verify some little things in tests.
static final Map<Class<?>,JsonSerializer<?>> SERIALIZERS = new HashMap<> ();
static final Map<Class<?>,JsonDeserializer<?>> DESERIALIZERS = new HashMap<> ();
static {
// Read - Write
SERIALIZERS.put( Instance.class, new InstanceSerializer());
DESERIALIZERS.put( Instance.class, new InstanceDeserializer());
SERIALIZERS.put( ApplicationTemplate.class, new ApplicationTemplateSerializer());
DESERIALIZERS.put( ApplicationTemplate.class, new ApplicationTemplateDeserializer());
SERIALIZERS.put( Application.class, new ApplicationSerializer());
DESERIALIZERS.put( Application.class, new ApplicationDeserializer());
SERIALIZERS.put( Component.class, new ComponentSerializer());
DESERIALIZERS.put( Component.class, new ComponentDeserializer());
SERIALIZERS.put( Diagnostic.class, new DiagnosticSerializer());
DESERIALIZERS.put( Diagnostic.class, new DiagnosticDeserializer());
SERIALIZERS.put( DependencyInformation.class, new DependencyInformationSerializer());
DESERIALIZERS.put( DependencyInformation.class, new DependencyInformationDeserializer());
SERIALIZERS.put( TargetWrapperDescriptor.class, new TargetWDSerializer());
DESERIALIZERS.put( TargetWrapperDescriptor.class, new TargetWDDeserializer());
SERIALIZERS.put( StringWrapper.class, new StringWrapperSerializer());
DESERIALIZERS.put( StringWrapper.class, new StringWrapperDeserializer());
SERIALIZERS.put( MapWrapper.class, new MapWrapperSerializer());
DESERIALIZERS.put( MapWrapper.class, new MapWrapperDeserializer());
SERIALIZERS.put( ScheduledJob.class, new ScheduledJobSerializer());
DESERIALIZERS.put( ScheduledJob.class, new ScheduledJobDeserializer());
SERIALIZERS.put( Preference.class, new PreferenceSerializer());
DESERIALIZERS.put( Preference.class, new PreferenceDeserializer());
// Write ONLY
SERIALIZERS.put( MappedCollectionWrapper.class, new MappedCollectionWrapperSerializer());
SERIALIZERS.put( TargetUsageItem.class, new TargetUsageItemSerializer());
SERIALIZERS.put( TargetAssociation.class, new TargetAssociationSerializer());
SERIALIZERS.put( ApplicationBindings.class, new ApplicationBindingsSerializer());
SERIALIZERS.put( WebSocketMessage.class, new WebSocketMessageSerializer());
}
/**
* @return the serializers as an unmodifiable map
*/
public static Map<Class<?>,? super JsonSerializer<?>> getSerializers() {
return Collections.unmodifiableMap( SERIALIZERS );
}
private static final String NAME = "name";
private static final String DISPLAY_NAME = "displayName";
private static final String QUALIFIER = "qualifier";
private static final String DESC = "desc";
private static final String EEP = "eep";
private static final String EXT_VARS = "extVars";
private static final String EXT_DEP = "extDep";
private static final String S = "s";
private static final String PATH = "path";
private static final String CRON = "cron";
private static final String ID = "id";
private static final String BOUND = "bound";
private static final String APP_ICON = "icon";
private static final String APP_INFO = "info";
private static final String APP_INST_TPL_NAME = "tplName";
private static final String APP_INST_TPL_QUALIFIER = "tplQualifier";
private static final String APP_INST_TPL_EEP = "tplEep";
private static final String APP_TPL_APPS = "apps";
private static final String COMP_INSTALLER = "installer";
private static final String INST_CHANNELS = "channels";
private static final String INST_COMPONENT = "component";
private static final String INST_STATUS = "status";
private static final String INST_EXPORTS = "exports";
private static final String INST_DATA = "data";
private static final String DEP_OPTIONAL = "optional";
private static final String DEP_RESOLVED = "resolved";
private static final String DIAG_PATH = "path";
private static final String DIAG_DEPENDENCIES = "dependencies";
private static final String TARGET_HANDLER = "handler";
private static final String TARGET_DEFAULT = "default";
private static final String TARGET_STATS_USING = "using";
private static final String TARGET_STATS_REFERENCING = "referencing";
private static final String PREF_VALUE = "value";
private static final String PREF_CATEGORY = "category";
private static final String JOB_NAME = "job-name";
private static final String JOB_APP_NAME = "app-name";
private static final String JOB_CMD_NAME = "cmd-name";
private static final String WS_EVENT = "event";
private static final String WS_APP = "app";
private static final String WS_TPL = "tpl";
private static final String WS_INST = "inst";
private static final String WS_MSG = "msg";
/**
* Private constructor.
*/
private JSonBindingUtils() {
// nothing
}
/**
* Creates a mapper with specific binding for Roboconf types.
* @return a non-null, configured mapper
*/
@SuppressWarnings( { "unchecked", "rawtypes" } )
public static ObjectMapper createObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false );
SimpleModule module = new SimpleModule( "RoboconfModule", new Version( 1, 0, 0, null, null, null ));
for( Map.Entry<Class<?>,? super JsonSerializer<?>> entry : SERIALIZERS.entrySet())
module.addSerializer((Class) entry.getKey(), (JsonSerializer) entry.getValue());
for( Map.Entry<Class<?>,? super JsonDeserializer<?>> entry : DESERIALIZERS.entrySet())
module.addDeserializer((Class) entry.getKey(), (JsonDeserializer) entry.getValue());
mapper.registerModule( module );
return mapper;
}
/**
* A JSon serializer for a bean describing a target usage.
* <p>
* No deserializer is provided, as it does not make sense for the REST API.
* </p>
*
* @author Vincent Zurczak - Linagora
*/
public static class TargetUsageItemSerializer extends JsonSerializer<TargetUsageItem> {
@Override
public void serialize(
TargetUsageItem item,
JsonGenerator generator,
SerializerProvider provider )
throws IOException {
generator.writeStartObject();
if( item.getName() != null )
generator.writeStringField( NAME, item.getName());
if( item.getQualifier() != null )
generator.writeStringField( QUALIFIER, item.getQualifier());
if( item.isUsing())
generator.writeStringField( TARGET_STATS_USING, "true" );
if( item.isReferencing())
generator.writeStringField( TARGET_STATS_REFERENCING, "true" );
generator.writeEndObject();
}
}
/**
* A JSon serializer for a bean describing a scheduled job.
* @author Vincent Zurczak - Linagora
*/
public static class ScheduledJobSerializer extends JsonSerializer<ScheduledJob> {
@Override
public void serialize(
ScheduledJob job,
JsonGenerator generator,
SerializerProvider provider )
throws IOException {
generator.writeStartObject();
if( job.getJobId() != null )
generator.writeStringField( ID, job.getJobId());
if( job.getAppName() != null )
generator.writeStringField( JOB_APP_NAME, job.getAppName());
if( job.getCmdName() != null )
generator.writeStringField( JOB_CMD_NAME, job.getCmdName());
if( job.getJobName() != null )
generator.writeStringField( JOB_NAME, job.getJobName());
if( job.getCron() != null )
generator.writeStringField( CRON, job.getCron());
generator.writeEndObject();
}
}
/**
* A JSon deserializer for scheduled jobs.
* @author Vincent Zurczak - Linagora
*/
public static class ScheduledJobDeserializer extends JsonDeserializer<ScheduledJob> {
@Override
public ScheduledJob deserialize( JsonParser parser, DeserializationContext context ) throws IOException {
ObjectCodec oc = parser.getCodec();
JsonNode node = oc.readTree( parser );
ScheduledJob job = new ScheduledJob();
JsonNode n;
if(( n = node.get( ID )) != null )
job.setJobId( n.textValue());
if(( n = node.get( JOB_NAME )) != null )
job.setJobName( n.textValue());
if(( n = node.get( JOB_APP_NAME )) != null )
job.setAppName( n.textValue());
if(( n = node.get( JOB_CMD_NAME )) != null )
job.setCmdName( n.textValue());
if(( n = node.get( CRON )) != null )
job.setCron( n.textValue());
return job;
}
}
/**
* A JSon serializer for a bean describing a target association.
* <p>
* No deserializer is provided, as it does not make sense for the REST API.
* </p>
*
* @author Vincent Zurczak - Linagora
*/
public static class TargetAssociationSerializer extends JsonSerializer<TargetAssociation> {
@Override
public void serialize(
TargetAssociation item,
JsonGenerator generator,
SerializerProvider provider )
throws IOException {
generator.writeStartObject();
if( item.getInstancePathOrComponentName() != null )
generator.writeStringField( PATH, item.getInstancePathOrComponentName());
if( item.getInstanceComponent() != null )
generator.writeStringField( INST_COMPONENT, item.getInstanceComponent());
if( item.getTargetDescriptor() != null )
generator.writeObjectField( DESC, item.getTargetDescriptor());
generator.writeEndObject();
}
}
/**
* A JSon serializer for Roboconf preferences.
* @author Vincent Zurczak - Linagora
*/
public static class PreferenceSerializer extends JsonSerializer<Preference> {
@Override
public void serialize(
Preference item,
JsonGenerator generator,
SerializerProvider provider )
throws IOException {
generator.writeStartObject();
if( item.getName() != null )
generator.writeStringField( NAME, item.getName());
if( item.getValue() != null )
generator.writeObjectField( PREF_VALUE, item.getValue());
if( item.getCategory() != null )
generator.writeObjectField( PREF_CATEGORY, item.getCategory().toString().toLowerCase());
generator.writeEndObject();
}
}
/**
* A JSon deserializer for Roboconf preferences.
* @author Vincent Zurczak - Linagora
*/
public static class PreferenceDeserializer extends JsonDeserializer<Preference> {
@Override
public Preference deserialize( JsonParser parser, DeserializationContext context ) throws IOException {
ObjectCodec oc = parser.getCodec();
JsonNode node = oc.readTree( parser );
String name = null, value = null, cat = null;
JsonNode n;
if(( n = node.get( NAME )) != null )
name = n.textValue();
if(( n = node.get( PREF_VALUE )) != null )
value = n.textValue();
if(( n = node.get( PREF_CATEGORY )) != null )
cat = n.textValue();
return new Preference( name, value, PreferenceKeyCategory.which( cat ));
}
}
/**
* A JSon serializer for target descriptors.
* @author Vincent Zurczak - Linagora
*/
public static class TargetWDSerializer extends JsonSerializer<TargetWrapperDescriptor> {
@Override
public void serialize(
TargetWrapperDescriptor twd,
JsonGenerator generator,
SerializerProvider provider )
throws IOException {
generator.writeStartObject();
if( twd.getId() != null )
generator.writeStringField( ID, twd.getId());
if( twd.getName() != null )
generator.writeStringField( NAME, twd.getName());
if( twd.getHandler() != null )
generator.writeStringField( TARGET_HANDLER, twd.getHandler());
if( twd.getDescription() != null )
generator.writeStringField( DESC, twd.getDescription());
if( twd.isDefault())
generator.writeStringField( TARGET_DEFAULT, "true" );
generator.writeEndObject();
}
}
/**
* A JSon deserializer for target descriptors.
* @author Vincent Zurczak - Linagora
*/
public static class TargetWDDeserializer extends JsonDeserializer<TargetWrapperDescriptor> {
@Override
public TargetWrapperDescriptor deserialize( JsonParser parser, DeserializationContext context ) throws IOException {
ObjectCodec oc = parser.getCodec();
JsonNode node = oc.readTree( parser );
TargetWrapperDescriptor twd = new TargetWrapperDescriptor();
JsonNode n;
if(( n = node.get( DESC )) != null )
twd.setDescription( n.textValue());
if(( n = node.get( TARGET_HANDLER )) != null )
twd.setHandler( n.textValue());
if(( n = node.get( ID )) != null )
twd.setId( n.textValue());
if(( n = node.get( NAME )) != null )
twd.setName( n.textValue());
return twd;
}
}
/**
* A JSon deserializer for string wrappers.
* @author Vincent Zurczak - Linagora
*/
public static class StringWrapperDeserializer extends JsonDeserializer<StringWrapper> {
@Override
public StringWrapper deserialize( JsonParser parser, DeserializationContext context ) throws IOException {
ObjectCodec oc = parser.getCodec();
JsonNode node = oc.readTree( parser );
String s = null;
JsonNode n;
if(( n = node.get( S )) != null )
s = n.textValue();
return new StringWrapper( s );
}
}
/**
* A JSon serializer for string wrappers.
* @author Vincent Zurczak - Linagora
*/
public static class StringWrapperSerializer extends JsonSerializer<StringWrapper> {
@Override
public void serialize(
StringWrapper s,
JsonGenerator generator,
SerializerProvider provider )
throws IOException {
generator.writeStartObject();
if( s.toString() != null )
generator.writeStringField( S, s.toString());
generator.writeEndObject();
}
}
/**
* A JSon deserializer for map wrappers.
* @author Vincent Zurczak - Linagora
*/
public static class MapWrapperDeserializer extends JsonDeserializer<MapWrapper> {
@Override
public MapWrapper deserialize( JsonParser parser, DeserializationContext context ) throws IOException {
ObjectCodec oc = parser.getCodec();
JsonNode node = oc.readTree( parser );
Map<String,String> map = new HashMap<> ();
for( Iterator<Map.Entry<String,JsonNode>> it = node.fields(); it.hasNext(); ) {
Map.Entry<String,JsonNode> entry = it.next();
map.put( entry.getKey(), entry.getValue().textValue());
}
return new MapWrapper( map );
}
}
/**
* A JSon serializer for map wrappers.
* @author Vincent Zurczak - Linagora
*/
public static class MapWrapperSerializer extends JsonSerializer<MapWrapper> {
@Override
public void serialize(
MapWrapper m,
JsonGenerator generator,
SerializerProvider provider )
throws IOException {
generator.writeStartObject();
for( Map.Entry<String,String> entry : m.getMap().entrySet()) {
generator.writeStringField(
entry.getKey() == null ? "" : entry.getKey(),
entry.getValue() == null ? "" : entry.getValue());
}
generator.writeEndObject();
}
}
/**
* A JSon serializer for application templates.
* @author Vincent Zurczak - Linagora
*/
public static class ApplicationTemplateSerializer extends JsonSerializer<ApplicationTemplate> {
@Override
public void serialize(
ApplicationTemplate app,
JsonGenerator generator,
SerializerProvider provider )
throws IOException {
generator.writeStartObject();
if( app.getName() != null )
generator.writeStringField( NAME, app.getName());
if( app.getDisplayName() != null )
generator.writeStringField( DISPLAY_NAME, app.getDisplayName());
if( app.getDescription() != null )
generator.writeStringField( DESC, app.getDescription());
if( app.getQualifier() != null )
generator.writeStringField( QUALIFIER, app.getQualifier());
if( app.getExternalExportsPrefix() != null )
generator.writeStringField( EEP, app.getExternalExportsPrefix());
// Read-only information.
// We do not expect it for deserialization
if( ! app.externalExports.isEmpty())
generator.writeObjectField( EXT_VARS, new MapWrapper( app.externalExports ));
// Read-only information.
// We do not expect it for deserialization
String iconLocation = IconUtils.findIconUrl( app );
if( ! Utils.isEmptyOrWhitespaces( iconLocation ))
generator.writeStringField( APP_ICON, iconLocation );
// Read-only information.
// We do not expect it for deserialization
Set<String> prefixesForExternalImports = VariableHelpers.findPrefixesForExternalImports( app );
if( ! prefixesForExternalImports.isEmpty()) {
generator.writeArrayFieldStart( EXT_DEP );
for( String prefix : prefixesForExternalImports )
generator.writeString( prefix );
generator.writeEndArray();
}
// Read-only information.
// We do not expect it for deserialization
generator.writeArrayFieldStart( APP_TPL_APPS );
for( Application associatedApp : app.getAssociatedApplications()) {
// #483 We do not know why, but after we delete an application
// from the web console, the resulting JSon array sometimes contain null.
// This prevents the deletion of a template that does not have applications anymore.
// The "IF" is a WORKAROUND.
if( associatedApp != null
&& associatedApp.getName() != null ) {
// end of WORKAROUND
generator.writeString( associatedApp.getName());
}
}
generator.writeEndArray();
generator.writeEndObject();
}
}
/**
* A JSon serializer for mapped collection wrappers.
* @author Vincent Zurczak - Linagora
*/
public static class MappedCollectionWrapperSerializer extends JsonSerializer<MappedCollectionWrapper> {
@Override
public void serialize(
MappedCollectionWrapper m,
JsonGenerator generator,
SerializerProvider provider )
throws IOException {
generator.writeStartObject();
for( Map.Entry<String,? extends Collection<String>> entry : m.getMap().entrySet()) {
generator.writeArrayFieldStart( entry.getKey() == null ? "" : entry.getKey());
if( entry.getValue() != null ) {
for( String item : entry.getValue())
generator.writeString( item );
}
generator.writeEndArray();
}
generator.writeEndObject();
}
}
/**
* A JSon deserializer for application templates.
* @author Vincent Zurczak - Linagora
*/
public static class ApplicationTemplateDeserializer extends JsonDeserializer<ApplicationTemplate> {
@Override
public ApplicationTemplate deserialize( JsonParser parser, DeserializationContext context ) throws IOException {
ObjectCodec oc = parser.getCodec();
JsonNode node = oc.readTree( parser );
ApplicationTemplate application = new ApplicationTemplate();
JsonNode n;
if(( n = node.get( DISPLAY_NAME )) != null )
application.setName( n.textValue());
else if(( n = node.get( NAME )) != null )
application.setName( n.textValue());
if(( n = node.get( DESC )) != null )
application.setDescription( n.textValue());
if(( n = node.get( QUALIFIER )) != null )
application.setQualifier( n.textValue());
if(( n = node.get( EEP )) != null )
application.setExternalExportsPrefix( n.textValue());
return application;
}
}
/**
* A JSon serializer for diagnostics.
* @author Vincent Zurczak - Linagora
*/
public static class DiagnosticSerializer extends JsonSerializer<Diagnostic> {
@Override
public void serialize(
Diagnostic diag,
JsonGenerator generator,
SerializerProvider provider )
throws IOException {
generator.writeStartObject();
if( diag.getInstancePath() != null )
generator.writeStringField( DIAG_PATH, diag.getInstancePath());
generator.writeArrayFieldStart( DIAG_DEPENDENCIES );
for( DependencyInformation info : diag.getDependenciesInformation())
generator.writeObject( info );
generator.writeEndArray();
generator.writeEndObject();
}
}
/**
* A JSon deserializer for diagnostics.
* @author Vincent Zurczak - Linagora
*/
public static class DiagnosticDeserializer extends JsonDeserializer<Diagnostic> {
@Override
public Diagnostic deserialize( JsonParser parser, DeserializationContext context ) throws IOException {
ObjectCodec oc = parser.getCodec();
JsonNode node = oc.readTree( parser );
Diagnostic diag = new Diagnostic();
JsonNode n;
if(( n = node.get( DIAG_PATH )) != null )
diag.setInstancePath( n.textValue());
if(( n = node.get( DIAG_DEPENDENCIES )) != null ) {
for( JsonNode arrayNodeItem : n ) {
ObjectMapper mapper = createObjectMapper();
DependencyInformation info = mapper.readValue( arrayNodeItem.toString(), DependencyInformation.class );
diag.getDependenciesInformation().add( info );
}
}
return diag;
}
}
/**
* A JSon serializer for dependencies information.
* @author Vincent Zurczak - Linagora
*/
public static class DependencyInformationSerializer extends JsonSerializer<DependencyInformation> {
@Override
public void serialize(
DependencyInformation info,
JsonGenerator generator,
SerializerProvider provider )
throws IOException {
generator.writeStartObject();
if( info.getDependencyName() != null )
generator.writeStringField( NAME, info.getDependencyName());
generator.writeStringField( DEP_OPTIONAL, String.valueOf( info.isOptional()));
generator.writeStringField( DEP_RESOLVED, String.valueOf( info.isResolved()));
generator.writeEndObject();
}
}
/**
* A JSon deserializer for dependencies information.
* @author Vincent Zurczak - Linagora
*/
public static class DependencyInformationDeserializer extends JsonDeserializer<DependencyInformation> {
@Override
public DependencyInformation deserialize( JsonParser parser, DeserializationContext context ) throws IOException {
ObjectCodec oc = parser.getCodec();
JsonNode node = oc.readTree( parser );
DependencyInformation info = new DependencyInformation();
JsonNode n;
if(( n = node.get( NAME )) != null )
info.setDependencyName( n.textValue());
if(( n = node.get( DEP_OPTIONAL )) != null )
info.setOptional( Boolean.valueOf( n.textValue()));
if(( n = node.get( DEP_RESOLVED )) != null )
info.setResolved( Boolean.valueOf( n.textValue()));
return info;
}
}
/**
* A JSon serializer for application bindings.
* @author Vincent Zurczak - Linagora
*/
public static class ApplicationBindingsSerializer extends JsonSerializer<ApplicationBindings> {
@Override
public void serialize(
ApplicationBindings bindings,
JsonGenerator generator,
SerializerProvider provider )
throws IOException {
generator.writeStartObject();
for( Map.Entry<String,List<ApplicationBindingItem>> entry : bindings.prefixToItems.entrySet()) {
generator.writeArrayFieldStart( entry.getKey());
for( ApplicationBindingItem item : entry.getValue()) {
generator.writeStartObject();
generator.writeStringField( NAME, item.getApplicationName());
generator.writeBooleanField( BOUND, item.isBound());
generator.writeEndObject();
}
generator.writeEndArray();
}
generator.writeEndObject();
}
}
/**
* A JSon serializer for web socket messages.
* @author Vincent Zurczak - Linagora
*/
public static class WebSocketMessageSerializer extends JsonSerializer<WebSocketMessage> {
@Override
public void serialize(
WebSocketMessage wsm,
JsonGenerator generator,
SerializerProvider provider )
throws IOException {
generator.writeStartObject();
if( wsm.getEventType() != null )
generator.writeStringField( WS_EVENT, wsm.getEventType().toString());
if( wsm.getApplication() != null )
generator.writeObjectField( WS_APP, wsm.getApplication());
if( wsm.getApplicationTemplate() != null )
generator.writeObjectField( WS_TPL, wsm.getApplicationTemplate());
if( wsm.getInstance() != null )
generator.writeObjectField( WS_INST, wsm.getInstance());
if( wsm.getMessage() != null )
generator.writeObjectField( WS_MSG, wsm.getMessage());
generator.writeEndObject();
}
}
/**
* A JSon serializer for applications.
* @author Vincent Zurczak - Linagora
*/
public static class ApplicationSerializer extends JsonSerializer<Application> {
@Override
public void serialize(
Application app,
JsonGenerator generator,
SerializerProvider provider )
throws IOException {
generator.writeStartObject();
if( app.getName() != null )
generator.writeStringField( NAME, app.getName());
if( app.getDisplayName() != null )
generator.writeStringField( DISPLAY_NAME, app.getDisplayName());
if( app.getDescription() != null )
generator.writeStringField( DESC, app.getDescription());
if( app.getTemplate() != null ) {
generator.writeStringField( APP_INST_TPL_NAME, app.getTemplate().getName());
if( app.getTemplate().getQualifier() != null )
generator.writeStringField( APP_INST_TPL_QUALIFIER, app.getTemplate().getQualifier());
if( app.getTemplate().getExternalExportsPrefix() != null )
generator.writeStringField( APP_INST_TPL_EEP, app.getTemplate().getExternalExportsPrefix());
// Read-only information.
// We do not expect it for deserialization
Map<String,String> externalExports = app.getTemplate().externalExports;
if( ! externalExports.isEmpty())
generator.writeObjectField( EXT_VARS, new MapWrapper( externalExports ));
}
// Read-only information.
// We do not expect it for deserialization
String iconLocation = IconUtils.findIconUrl( app );
if( ! Utils.isEmptyOrWhitespaces( iconLocation ))
generator.writeStringField( APP_ICON, iconLocation );
// Read-only information.
// We do not expect it for deserialization
Set<String> prefixesForExternalImports = VariableHelpers.findPrefixesForExternalImports( app );
if( ! prefixesForExternalImports.isEmpty()) {
generator.writeArrayFieldStart( EXT_DEP );
for( String prefix : prefixesForExternalImports )
generator.writeString( prefix );
generator.writeEndArray();
}
// #357 Add a state for applications in JSon objects
String info = null;
for( Instance rootInstance : app.getRootInstances()) {
if( rootInstance.getStatus() == InstanceStatus.PROBLEM ) {
info = "warn";
break;
}
if( rootInstance.getStatus() != InstanceStatus.NOT_DEPLOYED ) {
info = "ok";
break;
}
}
if( info != null )
generator.writeObjectField( APP_INFO, info );
generator.writeEndObject();
}
}
/**
* A JSon deserializer for applications.
* @author Vincent Zurczak - Linagora
*/
public static class ApplicationDeserializer extends JsonDeserializer<Application> {
@Override
public Application deserialize( JsonParser parser, DeserializationContext context ) throws IOException {
ObjectCodec oc = parser.getCodec();
JsonNode node = oc.readTree( parser );
Application application;
JsonNode n;
if(( n = node.get( APP_INST_TPL_NAME )) != null ) {
ApplicationTemplate appTemplate = new ApplicationTemplate();
appTemplate.setName( n.textValue());
n = node.get( APP_INST_TPL_QUALIFIER );
if( n != null )
appTemplate.setQualifier( n.textValue());
n = node.get( APP_INST_TPL_EEP );
if( n != null )
appTemplate.setExternalExportsPrefix( n.textValue());
application = new Application( appTemplate );
} else {
application = new Application( null );
}
if(( n = node.get( DISPLAY_NAME )) != null )
application.setName( n.textValue());
else if(( n = node.get( NAME )) != null )
application.setName( n.textValue());
if(( n = node.get( DESC )) != null )
application.setDescription( n.textValue());
return application;
}
}
/**
* A JSon serializer for instances.
* @author Vincent Zurczak - Linagora
*/
public static class InstanceSerializer extends JsonSerializer<Instance> {
@Override
public void serialize(
Instance instance,
JsonGenerator generator,
SerializerProvider provider )
throws IOException {
generator.writeStartObject();
if( instance.getName() != null ) {
generator.writeStringField( NAME, instance.getName());
generator.writeStringField( PATH, InstanceHelpers.computeInstancePath( instance ));
}
if( instance.getStatus() != null )
generator.writeStringField( INST_STATUS, String.valueOf( instance.getStatus()));
if( instance.getComponent() != null )
generator.writeObjectField( INST_COMPONENT, instance.getComponent());
if( ! instance.channels.isEmpty()) {
generator.writeArrayFieldStart( INST_CHANNELS );
for( String channel : instance.channels )
generator.writeString( channel );
generator.writeEndArray();
}
// All exports are serialized in the same object (overridden or not).
// Will be necessary in external apps, like web console (eg. to edit exports).
Map<String, String> exports = InstanceHelpers.findAllExportedVariables(instance);
if( ! exports.isEmpty()) {
generator.writeFieldName( INST_EXPORTS );
generator.writeStartObject();
for( Map.Entry<String,String> entry : exports.entrySet())
generator.writeObjectField( entry.getKey(), entry.getValue());
generator.writeEndObject();
}
// Write some meta-data (useful for web clients).
// De-serializing this information is useless for the moment.
if( ! instance.data.isEmpty()) {
generator.writeFieldName( INST_DATA );
generator.writeStartObject();
for( Map.Entry<String,String> entry : instance.data.entrySet())
generator.writeObjectField( entry.getKey(), entry.getValue());
generator.writeEndObject();
}
generator.writeEndObject();
}
}
/**
* A JSon deserializer for instances.
* @author Vincent Zurczak - Linagora
*/
public static class InstanceDeserializer extends JsonDeserializer<Instance> {
@Override
public Instance deserialize( JsonParser parser, DeserializationContext context ) throws IOException {
ObjectCodec oc = parser.getCodec();
JsonNode node = oc.readTree( parser );
Instance instance = new Instance();
JsonNode n;
if(( n = node.get( NAME )) != null )
instance.setName( n.textValue());
if(( n = node.get( INST_STATUS )) != null )
instance.setStatus( InstanceStatus.whichStatus( n.textValue()));
if(( n = node.get( INST_CHANNELS )) != null ) {
for( JsonNode arrayNodeItem : n )
instance.channels.add( arrayNodeItem.textValue());
}
ObjectMapper mapper = createObjectMapper();
// Consider all exports as overridden. This will be fixed later
// (e.g. by comparison with component exports).
if(( n = node.get( INST_EXPORTS )) != null ) {
Map<String, String> exports = mapper.readValue( n.toString(), new TypeReference<HashMap<String,String>>(){});
instance.overriddenExports.putAll(exports);
}
if(( n = node.get( INST_COMPONENT )) != null ) {
Component instanceComponent = mapper.readValue( n.toString(), Component.class );
instance.setComponent( instanceComponent );
}
// Add meta-data
if(( n = node.get( PATH )) != null ) {
instance.data.put( AT_INSTANCE_PATH, n.textValue());
}
return instance;
}
}
/**
* A JSon serializer for components.
* <p>
* Only the name and alias are serialized.
* </p>
*
* @author Vincent Zurczak - Linagora
*/
public static class ComponentSerializer extends JsonSerializer<Component> {
@Override
public void serialize(
Component component,
JsonGenerator generator,
SerializerProvider provider )
throws IOException {
generator.writeStartObject();
if( component.getName() != null )
generator.writeStringField( NAME, component.getName());
String installerName = ComponentHelpers.findComponentInstaller( component );
if( installerName != null )
generator.writeStringField( COMP_INSTALLER, installerName );
generator.writeEndObject();
}
}
/**
* A JSon deserializer for components.
* @author Vincent Zurczak - Linagora
*/
public static class ComponentDeserializer extends JsonDeserializer<Component> {
@Override
public Component deserialize( JsonParser parser, DeserializationContext context ) throws IOException {
ObjectCodec oc = parser.getCodec();
JsonNode node = oc.readTree( parser );
Component component = new Component();
JsonNode n;
if(( n = node.get( NAME )) != null )
component.setName( n.textValue());
if(( n = node.get( COMP_INSTALLER )) != null )
component.setInstallerName( n.textValue());
return component;
}
}
}