package com.intrbiz.bergamot.io; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.util.List; import java.util.Set; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.intrbiz.bergamot.model.message.AlertEncompassesMO; import com.intrbiz.bergamot.model.message.AlertEscalationMO; import com.intrbiz.bergamot.model.message.AlertMO; import com.intrbiz.bergamot.model.message.AuthTokenMO; import com.intrbiz.bergamot.model.message.ClusterMO; import com.intrbiz.bergamot.model.message.CommandMO; import com.intrbiz.bergamot.model.message.CommentMO; import com.intrbiz.bergamot.model.message.ContactMO; import com.intrbiz.bergamot.model.message.CredentialMO; import com.intrbiz.bergamot.model.message.DowntimeMO; import com.intrbiz.bergamot.model.message.EscalationMO; import com.intrbiz.bergamot.model.message.GroupMO; import com.intrbiz.bergamot.model.message.HostMO; import com.intrbiz.bergamot.model.message.LocationMO; import com.intrbiz.bergamot.model.message.NotificationEngineMO; import com.intrbiz.bergamot.model.message.NotificationsMO; import com.intrbiz.bergamot.model.message.ParameterMO; import com.intrbiz.bergamot.model.message.ResourceMO; import com.intrbiz.bergamot.model.message.SecurityDomainMO; import com.intrbiz.bergamot.model.message.ServiceMO; import com.intrbiz.bergamot.model.message.TeamMO; import com.intrbiz.bergamot.model.message.TimePeriodMO; import com.intrbiz.bergamot.model.message.TrapMO; import com.intrbiz.bergamot.model.message.agent.manager.request.CreateSiteCA; import com.intrbiz.bergamot.model.message.agent.manager.request.GetAgent; import com.intrbiz.bergamot.model.message.agent.manager.request.GetRootCA; import com.intrbiz.bergamot.model.message.agent.manager.request.GetServer; import com.intrbiz.bergamot.model.message.agent.manager.request.GetSiteCA; import com.intrbiz.bergamot.model.message.agent.manager.request.SignAgent; import com.intrbiz.bergamot.model.message.agent.manager.request.SignServer; import com.intrbiz.bergamot.model.message.agent.manager.request.SignTemplate; import com.intrbiz.bergamot.model.message.agent.manager.response.AgentManagerError; import com.intrbiz.bergamot.model.message.agent.manager.response.CreatedSiteCA; import com.intrbiz.bergamot.model.message.agent.manager.response.GotAgent; import com.intrbiz.bergamot.model.message.agent.manager.response.GotRootCA; import com.intrbiz.bergamot.model.message.agent.manager.response.GotServer; import com.intrbiz.bergamot.model.message.agent.manager.response.GotSiteCA; import com.intrbiz.bergamot.model.message.agent.manager.response.SignedAgent; import com.intrbiz.bergamot.model.message.agent.manager.response.SignedServer; import com.intrbiz.bergamot.model.message.agent.manager.response.SignedTemplate; import com.intrbiz.bergamot.model.message.api.call.AppliedConfigChange; import com.intrbiz.bergamot.model.message.api.call.VerifiedCommand; import com.intrbiz.bergamot.model.message.api.check.ExecuteAdhocCheck; import com.intrbiz.bergamot.model.message.api.check.ExecutedAdhocCheck; import com.intrbiz.bergamot.model.message.api.error.APIError; import com.intrbiz.bergamot.model.message.api.notification.NotificationEvent; import com.intrbiz.bergamot.model.message.api.notification.RegisterForNotifications; import com.intrbiz.bergamot.model.message.api.notification.RegisteredForNotifications; import com.intrbiz.bergamot.model.message.api.result.AdhocResultEvent; import com.intrbiz.bergamot.model.message.api.result.RegisterForAdhocResults; import com.intrbiz.bergamot.model.message.api.result.RegisteredForAdhocResults; import com.intrbiz.bergamot.model.message.api.update.RegisterForUpdates; import com.intrbiz.bergamot.model.message.api.update.RegisteredForUpdates; import com.intrbiz.bergamot.model.message.api.update.UpdateEvent; import com.intrbiz.bergamot.model.message.api.util.APIPing; import com.intrbiz.bergamot.model.message.api.util.APIPong; import com.intrbiz.bergamot.model.message.check.ExecuteCheck; import com.intrbiz.bergamot.model.message.cluster.manager.request.DeinitSite; import com.intrbiz.bergamot.model.message.cluster.manager.request.FlushGlobalCaches; import com.intrbiz.bergamot.model.message.cluster.manager.request.InitSite; import com.intrbiz.bergamot.model.message.cluster.manager.response.ClusterManagerError; import com.intrbiz.bergamot.model.message.cluster.manager.response.DeinitedSite; import com.intrbiz.bergamot.model.message.cluster.manager.response.FlushedGlobalCaches; import com.intrbiz.bergamot.model.message.cluster.manager.response.InitedSite; import com.intrbiz.bergamot.model.message.command.GeneralCommandError; import com.intrbiz.bergamot.model.message.command.RegisterBergamotAgent; import com.intrbiz.bergamot.model.message.command.RegisteredBergamotAgent; import com.intrbiz.bergamot.model.message.config.BergamotValidationReportMO; import com.intrbiz.bergamot.model.message.event.control.RegisterWatcher; import com.intrbiz.bergamot.model.message.event.watcher.RegisterCheck; import com.intrbiz.bergamot.model.message.event.watcher.UnregisterCheck; import com.intrbiz.bergamot.model.message.health.HealthCheckHeartbeat; import com.intrbiz.bergamot.model.message.health.HealthCheckJoin; import com.intrbiz.bergamot.model.message.health.HealthCheckKill; import com.intrbiz.bergamot.model.message.health.HealthCheckRequestJoin; import com.intrbiz.bergamot.model.message.health.HealthCheckUnjoin; import com.intrbiz.bergamot.model.message.importer.BergamotImportReportMO; import com.intrbiz.bergamot.model.message.notification.BackupCodeUsed; import com.intrbiz.bergamot.model.message.notification.PasswordResetNotification; import com.intrbiz.bergamot.model.message.notification.RegisterContactNotification; import com.intrbiz.bergamot.model.message.notification.SendAcknowledge; import com.intrbiz.bergamot.model.message.notification.SendAlert; import com.intrbiz.bergamot.model.message.notification.SendRecovery; import com.intrbiz.bergamot.model.message.notification.U2FADeviceRegistered; import com.intrbiz.bergamot.model.message.reading.CheckReadingMO; import com.intrbiz.bergamot.model.message.reading.ReadingParcelMO; import com.intrbiz.bergamot.model.message.result.ActiveResultMO; import com.intrbiz.bergamot.model.message.result.MatchOnAgentId; import com.intrbiz.bergamot.model.message.result.MatchOnCheckId; import com.intrbiz.bergamot.model.message.result.MatchOnHostAddress; import com.intrbiz.bergamot.model.message.result.MatchOnHostExternalRef; import com.intrbiz.bergamot.model.message.result.MatchOnHostName; import com.intrbiz.bergamot.model.message.result.MatchOnServiceExternalRef; import com.intrbiz.bergamot.model.message.result.MatchOnServiceName; import com.intrbiz.bergamot.model.message.result.MatchOnTrapExternalRef; import com.intrbiz.bergamot.model.message.result.MatchOnTrapName; import com.intrbiz.bergamot.model.message.result.PassiveResultMO; import com.intrbiz.bergamot.model.message.scheduler.DisableCheck; import com.intrbiz.bergamot.model.message.scheduler.EnableCheck; import com.intrbiz.bergamot.model.message.scheduler.PauseScheduler; import com.intrbiz.bergamot.model.message.scheduler.RescheduleCheck; import com.intrbiz.bergamot.model.message.scheduler.ResumeScheduler; import com.intrbiz.bergamot.model.message.scheduler.ScheduleCheck; import com.intrbiz.bergamot.model.message.scheduler.UnscheduleCheck; import com.intrbiz.bergamot.model.message.state.CheckStateMO; import com.intrbiz.bergamot.model.message.state.CheckStatsMO; import com.intrbiz.bergamot.model.message.state.CheckTransitionMO; import com.intrbiz.bergamot.model.message.state.GroupStateMO; import com.intrbiz.bergamot.model.message.update.AlertUpdate; import com.intrbiz.bergamot.model.message.update.CheckUpdate; import com.intrbiz.bergamot.model.message.update.GroupUpdate; import com.intrbiz.bergamot.model.message.update.LocationUpdate; import com.intrbiz.gerald.polyakov.io.PolyakovTranscoder; import com.intrbiz.queue.QueueEventTranscoder; import com.intrbiz.queue.QueueException; /** * Encode and decode messages */ public class BergamotTranscoder { public static final Class<?>[] CLASSES = { // message objects NotificationEngineMO.class, EscalationMO.class, NotificationsMO.class, CheckStateMO.class, GroupStateMO.class, CommandMO.class, HostMO.class, ClusterMO.class, ServiceMO.class, TrapMO.class, ResourceMO.class, ContactMO.class, GroupMO.class, LocationMO.class, TeamMO.class, TimePeriodMO.class, AlertMO.class, AlertEscalationMO.class, AlertEncompassesMO.class, CommentMO.class, DowntimeMO.class, SecurityDomainMO.class, CredentialMO.class, // model ParameterMO.class, // messages // check ExecuteCheck.class, ActiveResultMO.class, PassiveResultMO.class, MatchOnAgentId.class, MatchOnCheckId.class, MatchOnHostAddress.class, MatchOnHostName.class, MatchOnServiceName.class, MatchOnTrapName.class, MatchOnHostExternalRef.class, MatchOnServiceExternalRef.class, MatchOnTrapExternalRef.class, ReadingParcelMO.class, CheckReadingMO.class, // notifications SendAlert.class, SendRecovery.class, PasswordResetNotification.class, RegisterContactNotification.class, SendAcknowledge.class, U2FADeviceRegistered.class, BackupCodeUsed.class, // updates CheckUpdate.class, GroupUpdate.class, LocationUpdate.class, AlertUpdate.class, // scheduler EnableCheck.class, DisableCheck.class, ScheduleCheck.class, RescheduleCheck.class, UnscheduleCheck.class, PauseScheduler.class, ResumeScheduler.class, // API APIError.class, APIPing.class, APIPong.class, UpdateEvent.class, RegisterForUpdates.class, RegisteredForUpdates.class, NotificationEvent.class, RegisterForNotifications.class, RegisteredForNotifications.class, RegisterForAdhocResults.class, RegisteredForAdhocResults.class, AdhocResultEvent.class, ExecuteAdhocCheck.class, ExecutedAdhocCheck.class, // control RegisterWatcher.class, // watcher RegisterCheck.class, UnregisterCheck.class, // auth AuthTokenMO.class, // stats CheckStatsMO.class, CheckTransitionMO.class, // bergamot agent manager CreateSiteCA.class, CreatedSiteCA.class, GetSiteCA.class, GotSiteCA.class, GetRootCA.class, GotRootCA.class, GetAgent.class, GotAgent.class, GetServer.class, GotServer.class, SignAgent.class, SignedAgent.class, SignServer.class, SignedServer.class, AgentManagerError.class, SignTemplate.class, SignedTemplate.class, // cluster manager ClusterManagerError.class, InitSite.class, InitedSite.class, FlushGlobalCaches.class, FlushedGlobalCaches.class, DeinitSite.class, DeinitedSite.class, // util models BergamotImportReportMO.class, AppliedConfigChange.class, BergamotValidationReportMO.class, VerifiedCommand.class, // heathchecks HealthCheckJoin.class, HealthCheckHeartbeat.class, HealthCheckUnjoin.class, HealthCheckRequestJoin.class, HealthCheckKill.class, // commands RegisterBergamotAgent.class, RegisteredBergamotAgent.class, GeneralCommandError.class }; private final ObjectMapper factory = new ObjectMapper(); public BergamotTranscoder() { super(); this.factory.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); this.factory.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); this.factory.configure(SerializationFeature.INDENT_OUTPUT, true); this.factory.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // add types this.addEventType(BergamotTranscoder.CLASSES); // include the metric reading models from Polyakov this.addEventType(PolyakovTranscoder.CLASSES); } public void addEventType(Class<?>... classes) { this.factory.registerSubtypes(classes); } public void encode(Object event, OutputStream to) { try (JsonGenerator g = this.factory.getFactory().createGenerator(to)) { this.factory.writeValue(g, event); } catch (IOException e) { throw new RuntimeException("Failed to encode event", e); } } public void encode(Object event, Writer to) { try (JsonGenerator g = this.factory.getFactory().createGenerator(to)) { this.factory.writeValue(g, event); } catch (IOException e) { throw new RuntimeException("Failed to encode event", e); } } public byte[] encodeAsBytes(Object event) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); this.encode(event, baos); return baos.toByteArray(); } public String encodeAsString(Object event) { StringWriter sw = new StringWriter(); this.encode(event, sw); return sw.toString(); } public void encode(Object event, File file) { file.getParentFile().mkdirs(); try (FileWriter fw = new FileWriter(file)) { this.encode(event, fw); } catch (IOException e) { throw new RuntimeException("Failed to write file", e); } } public <T> T decode(InputStream from, JavaType type) { try (JsonParser p = this.factory.getFactory().createParser(from)) { return this.factory.readValue(p, type); } catch (IOException e) { throw new RuntimeException("Failed to decode event", e); } } public <T> T decode(InputStream from, Class<T> type) { try (JsonParser p = this.factory.getFactory().createParser(from)) { return (T) this.factory.readValue(p, type); } catch (IOException e) { throw new RuntimeException("Failed to decode event", e); } } public <T> List<T> decodeList(InputStream from, Class<T> elementType) { try (JsonParser p = this.factory.getFactory().createParser(from)) { return this.factory.readValue(p, this.factory.getTypeFactory().constructCollectionType(List.class, elementType)); } catch (IOException e) { throw new RuntimeException("Failed to decode event", e); } } public <T> Set<T> decodeSet(InputStream from, Class<T> elementType) { try (JsonParser p = this.factory.getFactory().createParser(from)) { return this.factory.readValue(p, this.factory.getTypeFactory().constructCollectionType(Set.class, elementType)); } catch (IOException e) { throw new RuntimeException("Failed to decode event", e); } } public <T> T decode(Reader from, Class<T> type) { try (JsonParser p = this.factory.getFactory().createParser(from)) { return (T) this.factory.readValue(p, type); } catch (IOException e) { throw new RuntimeException("Failed to decode event", e); } } public <T> T decode(Reader from, JavaType type) { try (JsonParser p = this.factory.getFactory().createParser(from)) { return this.factory.readValue(p, type); } catch (IOException e) { throw new RuntimeException("Failed to decode event", e); } } public <T> List<T> decodeList(Reader from, Class<T> elementType) { try (JsonParser p = this.factory.getFactory().createParser(from)) { return this.factory.readValue(p, this.factory.getTypeFactory().constructCollectionType(List.class, elementType)); } catch (IOException e) { throw new RuntimeException("Failed to decode event", e); } } public <T> Set<T> decodeSet(Reader from, Class<T> elementType) { try (JsonParser p = this.factory.getFactory().createParser(from)) { return this.factory.readValue(p, this.factory.getTypeFactory().constructCollectionType(Set.class, elementType)); } catch (IOException e) { throw new RuntimeException("Failed to decode event", e); } } public <T> T decodeFromString(String event, Class<T> type) { return this.decode(new StringReader(event), type); } public <T> T decodeFromString(String event, JavaType type) { return this.decode(new StringReader(event), type); } public <T> List<T> decodeListFromString(String event, Class<T> elementType) { return this.decodeList(new StringReader(event), elementType); } public <T> Set<T> decodeSetFromString(String event, Class<T> elementType) { return this.decodeSet(new StringReader(event), elementType); } public <T> T decodeFromBytes(byte[] event, Class<T> type) { return this.decode(new ByteArrayInputStream(event), type); } public <T> T decodeFromBytes(byte[] event, JavaType type) { return this.decode(new ByteArrayInputStream(event), type); } public <T> List<T> decodeListFromBytes(byte[] event, Class<T> elementType) { return this.decodeList(new ByteArrayInputStream(event), elementType); } public <T> Set<T> decodeSetFromBytes(byte[] event, Class<T> elementType) { return this.decodeSet(new ByteArrayInputStream(event), elementType); } public <T> T decode(File event, Class<T> type) { try (FileReader fr = new FileReader(event)) { return this.decode(fr, type); } catch (IOException e) { throw new RuntimeException("Failed to read file", e); } } public <T> T decode(File event, JavaType type) { try (FileReader fr = new FileReader(event)) { return this.decode(fr, type); } catch (IOException e) { throw new RuntimeException("Failed to read file", e); } } public <T> List<T> decodeList(File event, Class<T> elementType) { try (FileReader fr = new FileReader(event)) { return this.decodeList(fr, elementType); } catch (IOException e) { throw new RuntimeException("Failed to read file", e); } } public <T> Set<T> decodeSet(File event, Class<T> elementType) { try (FileReader fr = new FileReader(event)) { return this.decodeSet(fr, elementType); } catch (IOException e) { throw new RuntimeException("Failed to read file", e); } } /** * Adapt this transcoder for use as a QueueTranscoder */ public <T> QueueEventTranscoder<T> asQueueEventTranscoder(final Class<T> type) { return new QueueEventTranscoder<T>() { @Override public byte[] encodeAsBytes(T event) throws QueueException { return BergamotTranscoder.this.encodeAsBytes(event); } @Override public T decodeFromBytes(byte[] data) throws QueueException { return (T) BergamotTranscoder.this.decodeFromBytes(data, type); } }; } }