org.jitsi.jicofo.log.EventFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.jitsi.jicofo.log.EventFactory.java

Source

/*
 * Jicofo, the Jitsi Conference Focus.
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jitsi.jicofo.log;

import org.jitsi.util.*;
import org.jitsi.videobridge.eventadmin.*;
import org.jitsi.videobridge.influxdb.*;
import org.json.simple.*;
import org.json.simple.parser.*;

import java.util.*;

/**
 * A utility class with static methods which initialize <tt>Event</tt> instances
 * with pre-determined fields.
 *
 * @author Boris Grozev
 * @author Pawel Domas
 */
public class EventFactory extends org.jitsi.videobridge.EventFactory {
    /**
     * The logger instance used by this class.
     */
    private final static Logger logger = Logger.getLogger(EventFactory.class);

    /**
     * The name of the key for additional authentication properties.
     */
    public static final String AUTH_PROPERTIES_KEY = "properties";

    /**
     * The name of the key for authentication session ID.
     */
    public static final String AUTH_SESSION_ID_KEY = "auth_session_id";

    /**
     * The name of the key for videobridge JID.
     */
    public static final String BRIDGE_JID_KEY = "bridge_jid";

    /**
     * The name of the key for conference ID.
     */
    public static final String CONFERENCE_ID_KEY = "conference_id";

    /**
     * The name of the key for display name.
     */
    public static final String DISPLAY_NAME_KEY = "display_name";

    /**
     * The name of the key for endpoint ID.
     */
    public static final String ENDPOINT_ID_KEY = "endpoint_id";

    /**
     * The name of the key for focus instance ID.
     */
    public static final String FOCUS_ID_KEY = "focus_id";

    /**
     * The name of the key for machine unique identifier supplied during
     * authentication.
     */
    public static final String MACHINE_UID_KEY = "machine_uid";

    /**
     * The name of the key for MUC room JID.
     */
    public static final String ROOM_JID_KEY = "room_jid";

    /**
     * The name of the key for authenticated user identity.
     */
    public static final String USER_IDENTITY_KEY = "user_identity";

    /**
     * The name of the topic of a "conference room" event.
     */
    public static final String CONFERENCE_ROOM_TOPIC = "org/jitsi/jicofo/CONFERENCE_ROOM_CREATED";

    /**
     * The name of the topic of a "peer connection stats" event.
     */
    public static final String PEER_CONNECTION_STATS_TOPIC = "org/jitsi/jicofo/PEER_CONNECTION_STATS";

    /**
     * The name of the topic of an "authentication session created" event.
     */
    public static final String AUTH_SESSION_CREATED_TOPIC = "org/jitsi/jicofo/AUTH_SESSION_CREATED";

    /**
     * The name of the topic of an "authentication session destroyed" event.
     */
    public static final String AUTH_SESSION_DESTROYED_TOPIC = "org/jitsi/jicofo/AUTH_SESSION_DESTROYED";

    /**
     * The name of the topic of an "endpoint authenticated" event.
     */
    public static final String ENDPOINT_AUTHENTICATED_TOPIC = "org/jitsi/jicofo/ENDPOINT_AUTHENTICATED";

    /**
     * The name of the topic of a "focus instance created" event.
     */
    public static final String FOCUS_CREATED_TOPIC = "org/jitsi/jicofo/FOCUS_CREATED";

    /**
     * The name of the topic of a "focus instance destroyed" event.
     */
    public static final String FOCUS_DESTROYED_TOPIC = "org/jitsi/jicofo/FOCUS_DESTROYED";

    /**
     * Creates a new "endpoint display name changed" <tt>Event</tt>, which
     * conference ID to the JID of the associated MUC.
     *
     * @param conferenceId the ID of the COLIBRI conference.
     * @param endpointId the ID of the COLIBRI endpoint.
     * @param displayName the new display name.
     *
     * @return the <tt>Event</tt> which was created.
     */
    public static Event endpointDisplayNameChanged(String conferenceId, String endpointId, String displayName) {
        Dictionary properties = new Hashtable(3);
        properties.put(CONFERENCE_ID_KEY, conferenceId);
        properties.put(ENDPOINT_ID_KEY, endpointId);
        properties.put(DISPLAY_NAME_KEY, displayName);
        return new Event(ENDPOINT_DISPLAY_NAME_CHANGED_TOPIC, properties);
    }

    /**
     * Creates an Event after parsing <tt>stats</tt> as JSON in the format
     * used in Jitsi Meet.
     * @param conferenceId the ID of the conference.
     * @param endpointId the ID of the endpoint.
     * @param stats the string representation of
     * @return
     */
    public static Event peerConnectionStats(String conferenceId, String endpointId, String stats) {
        Object[] values;

        try {
            values = parsePeerConnectionStats(conferenceId, endpointId, stats);
        } catch (Exception e) {
            logger.warn("Failed to parse PeerConnection stats JSON: " + e);
            return null;
        }

        InfluxDBEvent influxDBEvent = new InfluxDBEvent("peer_connection_stats",
                LoggingHandler.PEER_CONNECTION_STATS_COLUMNS, values);

        // We specifically add a "time" column
        influxDBEvent.setUseLocalTime(false);

        return new Event(PEER_CONNECTION_STATS_TOPIC, makeProperties(influxDBEvent));
    }

    /**
     * Parses <tt>statsStr</tt> as JSON in the format used by Jitsi Meet, and
     * returns an Object[][] containing the values to be used in an
     * <tt>Event</tt> for the given JSON.
     * @param conferenceId the value to use for the conference_id field.
     * @param endpointId the value to use for the endpoint_id field.
     * @param statsStr the PeerConnection JSON string.
     * @return an Object[][] containing the values to be used in an
     * <tt>Event</tt> for the given JSON.
     * @throws Exception if parsing fails for any reason.
     */
    private static Object[] parsePeerConnectionStats(String conferenceId, String endpointId, String statsStr)
            throws Exception {
        // An example JSON in the format that we expect:
        // {
        //   "timestamps": [1, 2, 3],
        //   "stats": {
        //      "group1": {
        //          "type": "some string",
        //          "stat1": ["some", "values", ""]
        //          "stat2": ["some", "more", "values"]
        //      },
        //      "bweforvideo": {
        //          "type":"VideoBwe",
        //          "googActualEncBitrate": ["12","34","56"],
        //          "googAvailableSendBandwidth": ["78", "90", "12"]
        //      }
        //   }
        // }

        // time: 1
        // conference_id: blabla
        // endpoint_id: blabla
        // value: [
        //     ["group1", "some string", {"stat1": "some", "stat2": "some"}],
        //     ["bweforvideo", "VideoBwe", {"googActualEncBitrate": "12", "googAvailableSendBandwidth": "78"}]
        // ]

        JSONParser parser = new JSONParser();
        JSONObject jsonObject = (JSONObject) parser.parse(statsStr);

        List<Object[]> values = new LinkedList<Object[]>();
        JSONArray timestamps = (JSONArray) jsonObject.get("timestamps");
        JSONObject stats = (JSONObject) jsonObject.get("stats");

        for (int i = 0; i < timestamps.size(); i++) {
            long timestamp = (Long) timestamps.get(i);

            JSONArray value = new JSONArray();
            for (Object groupName : stats.keySet()) {
                JSONArray groupValue = new JSONArray();
                JSONObject group = ((JSONObject) stats.get(groupName));
                Object type = group.get("type");

                groupValue.add(groupName);
                groupValue.add(type);

                JSONObject s = new JSONObject();
                for (Object statName : group.keySet()) {
                    if ("type".equals(statName))
                        continue;

                    JSONArray statValues = (JSONArray) group.get(statName);
                    s.put(statName, statValues.get(i));
                }
                groupValue.add(s);

                value.add(groupValue);
            }
            Object[] point = new Object[LoggingHandler.PEER_CONNECTION_STATS_COLUMNS.length];

            point[0] = timestamp;
            point[1] = conferenceId;
            point[2] = endpointId;
            point[3] = value.toJSONString();

            values.add(point);
        }

        return values.toArray();
    }

    /**
     * Creates a new "room conference" <tt>Event</tt> which binds a COLIBRI
     * conference ID to the JID of the associated MUC.
     *
     * @param conferenceId the ID of the COLIBRI conference.
     * @param roomJid the JID of the MUC for which the focus was created.
     *
     * @return the <tt>Event</tt> which was created.
     */
    public static Event conferenceRoom(String conferenceId, String roomJid, String focus, String bridgeJid) {
        Dictionary properties = new Hashtable(3);
        properties.put(CONFERENCE_ID_KEY, conferenceId);
        properties.put(ROOM_JID_KEY, roomJid);
        properties.put(FOCUS_ID_KEY, focus);
        properties.put(BRIDGE_JID_KEY, bridgeJid);
        return new Event(CONFERENCE_ROOM_TOPIC, properties);
    }

    /**
     * Creates new "authentication session created" event.
     *
     * @param sessionId authentication session identifier.
     * @param userIdentity authenticated user identity
     * @param machineUid machine unique identifier used to distinguish session
     *                   for the same user on different machines.
     * @param properties the map of additional properties to be logged provided
     *                   during authentication.
     *
     * @return "authentication session created" <tt>Event</tt>
     */
    public static Event authSessionCreated(String sessionId, String userIdentity, String machineUid,
            Map<String, String> properties) {
        Dictionary<String, String> eventProps = new Hashtable<String, String>(4);

        eventProps.put(AUTH_SESSION_ID_KEY, sessionId);
        eventProps.put(USER_IDENTITY_KEY, userIdentity);
        eventProps.put(MACHINE_UID_KEY, machineUid);

        String mergedProperties = mergeProperties(properties);

        eventProps.put(AUTH_PROPERTIES_KEY, mergedProperties);

        return new Event(AUTH_SESSION_CREATED_TOPIC, eventProps);
    }

    /**
     * Creates new "authentication session destroyed" event.
     *
     * @param sessionId authentication session identifier string.
     *
     * @return created "authentication session destroyed" <tt>Event</tt>.
     */
    public static Event authSessionDestroyed(String sessionId) {
        Dictionary<String, String> eventProps = new Hashtable<String, String>(1);

        eventProps.put(AUTH_SESSION_ID_KEY, sessionId);

        return new Event(AUTH_SESSION_DESTROYED_TOPIC, eventProps);
    }

    /**
     * Creates "endpoint authenticated" event.
     *
     * @param sessionId authentication session identifier.
     * @param focusId focus instance id which was hosting the conference session
     * @param endpointId the ID of authenticated Colibri endpoint(participant).
     *
     * @return created "endpoint authenticated" <tt>Event</tt>.
     */
    public static Event endpointAuthenticated(String sessionId, String focusId, String endpointId) {
        Dictionary<String, String> eventProps = new Hashtable<String, String>(2);

        eventProps.put(AUTH_SESSION_ID_KEY, sessionId);
        eventProps.put(FOCUS_ID_KEY, focusId);
        eventProps.put(ENDPOINT_ID_KEY, endpointId);

        return new Event(ENDPOINT_AUTHENTICATED_TOPIC, eventProps);
    }

    /**
     * Creates new "focus created" event.
     *
     * @param focusId focus instance identifier.
     * @param roomName MUC room JID for which the focus has been created.
     *
     * @return new "focus created" <tt>Event</tt>.
     */
    public static Event focusCreated(String focusId, String roomName) {
        Dictionary<String, String> eventProps = new Hashtable<String, String>(2);

        eventProps.put(FOCUS_ID_KEY, focusId);
        eventProps.put(ROOM_JID_KEY, roomName);

        return new Event(FOCUS_CREATED_TOPIC, eventProps);
    }

    /**
     * Creates new "focus destroyed" event.
     *
     * @param focusId focus instance identifier.
     * @param roomName MUC room JID for which the focus has been destroyed.
     *
     * @return new "focus destroyed" <tt>Event</tt> instance.
     */
    public static Event focusDestroyed(String focusId, String roomName) {
        Dictionary<String, String> eventProps = new Hashtable<String, String>(2);

        eventProps.put(FOCUS_ID_KEY, focusId);
        eventProps.put(ROOM_JID_KEY, roomName);

        return new Event(FOCUS_DESTROYED_TOPIC, eventProps);
    }

    /**
     * Merges authentication properties into single String transmitted in the
     * log event. After each key name there is colon appended and key/value
     * pairs are separated with CRLF(\r\n).
     *
     * @param properties the map of authentication properties.
     *
     * @return authentication properties map merged into single <tt>String</tt>.
     */
    public static String mergeProperties(Map<String, String> properties) {
        StringBuilder output = new StringBuilder();
        for (Map.Entry<String, String> entry : properties.entrySet()) {
            output.append(entry.getKey()).append(":").append(entry.getValue()).append("\r\n");
        }
        return output.toString();
    }

    /**
     * Splits merged authentication properties <tt>String</tt> into String
     * key/value map.
     *
     * @param merged a <tt>String</tt> that contains merged authentication
     *               properties(with {@link #mergeProperties(Map) method}).
     *
     * @return key/value map of authentication properties.
     */
    public static Map<String, String> splitProperties(String merged) {
        String[] entries = merged.split("\r\n");
        Map<String, String> map = new Hashtable<String, String>(entries.length);
        for (String entry : entries) {
            if (StringUtils.isNullOrEmpty(entry))
                continue;

            int colonIdx = entry.indexOf(":");
            String key = entry.substring(0, colonIdx);
            String value = entry.substring(colonIdx + 1);
            map.put(key, value);
        }
        return map;
    }
}