at.alladin.rmbt.controlServer.ResultResource.java Source code

Java tutorial

Introduction

Here is the source code for at.alladin.rmbt.controlServer.ResultResource.java

Source

/*******************************************************************************
 * Copyright 2013-2015 alladin-IT GmbH
 * 
 * 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 at.alladin.rmbt.controlServer;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import java.util.regex.Pattern;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.restlet.resource.Get;
import org.restlet.resource.Post;

import at.alladin.rmbt.db.Cell_location;
import at.alladin.rmbt.db.GeoLocation;
import at.alladin.rmbt.db.Signal;
import at.alladin.rmbt.db.Test;
import at.alladin.rmbt.db.TestStat;
import at.alladin.rmbt.db.dao.TestStatDao;
import at.alladin.rmbt.db.fields.IntField;
import at.alladin.rmbt.db.fields.LongField;
import at.alladin.rmbt.shared.Helperfunctions;
import at.alladin.rmbt.shared.ResourceManager;

import com.google.common.net.InetAddresses;

public class ResultResource extends ServerResource {
    final static int UNKNOWN = Integer.MIN_VALUE;
    final static Pattern MCC_MNC_PATTERN = Pattern.compile("\\d{3}-\\d+");

    @Post("json")
    public String request(final String entity) {
        final String secret = getContext().getParameters().getFirstValue("RMBT_SECRETKEY");

        addAllowOrigin();

        JSONObject request = null;

        final ErrorList errorList = new ErrorList();
        final JSONObject answer = new JSONObject();

        System.out.println(MessageFormat.format(labels.getString("NEW_RESULT"), getIP()));

        if (entity != null && !entity.isEmpty())
            // try parse the string to a JSON object
            try {
                request = new JSONObject(entity);
                System.out.println(request);

                final String lang = request.optString("client_language");

                // Load Language Files for Client

                final List<String> langs = Arrays
                        .asList(settings.getString("RMBT_SUPPORTED_LANGUAGES").split(",\\s*"));

                if (langs.contains(lang)) {
                    errorList.setLanguage(lang);
                    labels = ResourceManager.getSysMsgBundle(new Locale(lang));
                }

                //                System.out.println(request.toString(4));

                if (conn != null) {

                    conn.setAutoCommit(false);

                    final Test test = new Test(conn);

                    if (request.optString("test_token").length() > 0) {

                        final String[] token = request.getString("test_token").split("_");

                        try {

                            // Check if UUID
                            final UUID testUuid = UUID.fromString(token[0]);

                            final String data = token[0] + "_" + token[1];

                            final String hmac = Helperfunctions.calculateHMAC(secret, data);
                            if (hmac.length() == 0)
                                errorList.addError("ERROR_TEST_TOKEN");

                            if (token[2].length() > 0 && hmac.equals(token[2])) {

                                final List<String> clientNames = Arrays
                                        .asList(settings.getString("RMBT_CLIENT_NAME").split(",\\s*"));
                                final List<String> clientVersions = Arrays
                                        .asList(settings.getString("RMBT_VERSION_NUMBER").split(",\\s*"));

                                if (test.getTestByUuid(testUuid) > 0)
                                    if (clientNames.contains(request.optString("client_name"))
                                            && clientVersions.contains(request.optString("client_version"))) {

                                        test.setFields(request);

                                        final String networkOperator = request
                                                .optString("telephony_network_operator");
                                        if (MCC_MNC_PATTERN.matcher(networkOperator).matches())
                                            test.getField("network_operator").setString(networkOperator);
                                        else
                                            test.getField("network_operator").setString(null);

                                        final String networkSimOperator = request
                                                .optString("telephony_network_sim_operator");
                                        if (MCC_MNC_PATTERN.matcher(networkSimOperator).matches())
                                            test.getField("network_sim_operator").setString(networkSimOperator);
                                        else
                                            test.getField("network_sim_operator").setString(null);

                                        // RMBTClient Info

                                        final String ipLocalRaw = request.optString("test_ip_local", null);
                                        if (ipLocalRaw != null) {
                                            final InetAddress ipLocalAddress = InetAddresses.forString(ipLocalRaw);
                                            // original address (not filtered)
                                            test.getField("client_ip_local")
                                                    .setString(InetAddresses.toAddrString(ipLocalAddress));
                                            // anonymized local address
                                            final String ipLocalAnonymized = Helperfunctions
                                                    .anonymizeIp(ipLocalAddress);
                                            test.getField("client_ip_local_anonymized")
                                                    .setString(ipLocalAnonymized);
                                            // type of local ip
                                            test.getField("client_ip_local_type")
                                                    .setString(Helperfunctions.IpType(ipLocalAddress));
                                            // public ip
                                            final InetAddress ipPublicAddress = InetAddresses
                                                    .forString(test.getField("client_public_ip").toString());
                                            test.getField("nat_type").setString(
                                                    Helperfunctions.getNatType(ipLocalAddress, ipPublicAddress));
                                        }

                                        final String ipServer = request.optString("test_ip_server", null);
                                        if (ipServer != null) {
                                            final InetAddress testServerInetAddress = InetAddresses
                                                    .forString(ipServer);
                                            test.getField("server_ip")
                                                    .setString(InetAddresses.toAddrString(testServerInetAddress));
                                        }

                                        //log IP address
                                        final String ipSource = getIP();
                                        test.getField("source_ip").setString(ipSource);

                                        //log anonymized address
                                        try {
                                            final InetAddress ipSourceIP = InetAddress.getByName(ipSource);
                                            final String ipSourceAnonymized = Helperfunctions
                                                    .anonymizeIp(ipSourceIP);
                                            test.getField("source_ip_anonymized").setString(ipSourceAnonymized);
                                        } catch (UnknownHostException e) {
                                            System.out.println("Exception thrown:" + e);
                                        }

                                        // Additional Info

                                        //////////////////////////////////////////////////
                                        // extended test stats:
                                        //////////////////////////////////////////////////
                                        final TestStat extendedTestStat = TestStat
                                                .checkForSubmittedTestStats(request, test.getUid());
                                        if (extendedTestStat != null) {
                                            final TestStatDao testStatDao = new TestStatDao(conn);
                                            testStatDao.save(extendedTestStat);
                                        }

                                        //////////////////////////////////////////////////

                                        JSONArray speedData = request.optJSONArray("speed_detail");

                                        if (speedData != null && !test.hasError()) {
                                            final PreparedStatement psSpeed = conn.prepareStatement(
                                                    "INSERT INTO test_speed (test_id, upload, thread, time, bytes) VALUES (?,?,?,?,?)");
                                            psSpeed.setLong(1, test.getUid());
                                            for (int i = 0; i < speedData.length(); i++) {
                                                final JSONObject item = speedData.getJSONObject(i);

                                                final String direction = item.optString("direction");
                                                if (direction != null && (direction.equals("download")
                                                        || direction.equals("upload"))) {
                                                    psSpeed.setBoolean(2, direction.equals("upload"));
                                                    psSpeed.setInt(3, item.optInt("thread"));
                                                    psSpeed.setLong(4, item.optLong("time"));
                                                    psSpeed.setLong(5, item.optLong("bytes"));

                                                    psSpeed.executeUpdate();
                                                }
                                            }
                                        }

                                        final JSONArray pingData = request.optJSONArray("pings");

                                        if (pingData != null && !test.hasError()) {
                                            final PreparedStatement psPing = conn.prepareStatement(
                                                    "INSERT INTO ping (test_id, value, value_server, time_ns) "
                                                            + "VALUES(?,?,?,?)");
                                            psPing.setLong(1, test.getUid());

                                            for (int i = 0; i < pingData.length(); i++) {

                                                final JSONObject pingDataItem = pingData.getJSONObject(i);

                                                long valueClient = pingDataItem.optLong("value", -1);
                                                if (valueClient >= 0)
                                                    psPing.setLong(2, valueClient);
                                                else
                                                    psPing.setNull(2, Types.BIGINT);

                                                long valueServer = pingDataItem.optLong("value_server", -1);
                                                if (valueServer >= 0)
                                                    psPing.setLong(3, valueServer);
                                                else
                                                    psPing.setNull(3, Types.BIGINT);

                                                long timeNs = pingDataItem.optLong("time_ns", -1);
                                                if (timeNs >= 0)
                                                    psPing.setLong(4, timeNs);
                                                else
                                                    psPing.setNull(4, Types.BIGINT);

                                                psPing.executeUpdate();
                                            }
                                        }

                                        final JSONArray geoData = request.optJSONArray("geoLocations");

                                        if (geoData != null && !test.hasError())
                                            for (int i = 0; i < geoData.length(); i++) {

                                                final JSONObject geoDataItem = geoData.getJSONObject(i);

                                                if (geoDataItem.optLong("tstamp", 0) != 0
                                                        && geoDataItem.optDouble("geo_lat", 0) != 0
                                                        && geoDataItem.optDouble("geo_long", 0) != 0) {

                                                    final GeoLocation geoloc = new GeoLocation(conn);

                                                    geoloc.setTest_id(test.getUid());

                                                    final long clientTime = geoDataItem.optLong("tstamp");
                                                    final Timestamp tstamp = java.sql.Timestamp
                                                            .valueOf(new Timestamp(clientTime).toString());

                                                    geoloc.setTime(tstamp, test.getField("timezone").toString());
                                                    geoloc.setAccuracy(
                                                            (float) geoDataItem.optDouble("accuracy", 0));
                                                    geoloc.setAltitude(geoDataItem.optDouble("altitude", 0));
                                                    geoloc.setBearing((float) geoDataItem.optDouble("bearing", 0));
                                                    geoloc.setSpeed((float) geoDataItem.optDouble("speed", 0));
                                                    geoloc.setProvider(geoDataItem.optString("provider", ""));
                                                    geoloc.setGeo_lat(geoDataItem.optDouble("geo_lat", 0));
                                                    geoloc.setGeo_long(geoDataItem.optDouble("geo_long", 0));
                                                    geoloc.setTime_ns(geoDataItem.optLong("time_ns", 0));

                                                    geoloc.storeLocation();

                                                    // Store Last Geolocation as
                                                    // Testlocation
                                                    if (i == geoData.length() - 1) {
                                                        if (geoDataItem.has("geo_lat"))
                                                            test.getField("geo_lat").setField(geoDataItem);

                                                        if (geoDataItem.has("geo_long"))
                                                            test.getField("geo_long").setField(geoDataItem);

                                                        if (geoDataItem.has("accuracy"))
                                                            test.getField("geo_accuracy").setField(geoDataItem);

                                                        if (geoDataItem.has("provider"))
                                                            test.getField("geo_provider").setField(geoDataItem);
                                                    }

                                                    if (geoloc.hasError()) {
                                                        errorList.addError(geoloc.getError());
                                                        break;
                                                    }

                                                }

                                            }

                                        final JSONArray cellData = request.optJSONArray("cellLocations");

                                        if (cellData != null && !test.hasError())
                                            for (int i = 0; i < cellData.length(); i++) {

                                                final JSONObject cellDataItem = cellData.getJSONObject(i);

                                                final Cell_location cellloc = new Cell_location(conn);

                                                cellloc.setTest_id(test.getUid());

                                                final long clientTime = cellDataItem.optLong("time");
                                                final Timestamp tstamp = java.sql.Timestamp
                                                        .valueOf(new Timestamp(clientTime).toString());

                                                cellloc.setTime(tstamp, test.getField("timezone").toString());

                                                cellloc.setTime_ns(cellDataItem.optLong("time_ns", 0));

                                                cellloc.setLocation_id(cellDataItem.optInt("location_id", 0));
                                                cellloc.setArea_code(cellDataItem.optInt("area_code", 0));

                                                cellloc.setPrimary_scrambling_code(
                                                        cellDataItem.optInt("primary_scrambling_code", 0));

                                                cellloc.storeLocation();

                                                if (cellloc.hasError()) {
                                                    errorList.addError(cellloc.getError());
                                                    break;
                                                }

                                            }

                                        int signalStrength = Integer.MAX_VALUE; //measured as RSSI (GSM,UMTS,Wifi)
                                        int lteRsrp = Integer.MAX_VALUE; // signal strength measured as RSRP
                                        int lteRsrq = Integer.MAX_VALUE; // signal quality of LTE measured as RSRQ
                                        int linkSpeed = UNKNOWN;
                                        final int networkType = test.getField("network_type").intValue();

                                        final JSONArray signalData = request.optJSONArray("signals");

                                        if (signalData != null && !test.hasError()) {

                                            for (int i = 0; i < signalData.length(); i++) {

                                                final JSONObject signalDataItem = signalData.getJSONObject(i);

                                                final Signal signal = new Signal(conn);

                                                signal.setTest_id(test.getUid());

                                                final long clientTime = signalDataItem.optLong("time");
                                                final Timestamp tstamp = java.sql.Timestamp
                                                        .valueOf(new Timestamp(clientTime).toString());

                                                signal.setTime(tstamp, test.getField("timezone").toString());

                                                final int thisNetworkType = signalDataItem.optInt("network_type_id",
                                                        0);
                                                signal.setNetwork_type_id(thisNetworkType);

                                                final int thisSignalStrength = signalDataItem
                                                        .optInt("signal_strength", UNKNOWN);
                                                if (thisSignalStrength != UNKNOWN)
                                                    signal.setSignal_strength(thisSignalStrength);
                                                signal.setGsm_bit_error_rate(
                                                        signalDataItem.optInt("gsm_bit_error_rate", 0));
                                                final int thisLinkSpeed = signalDataItem.optInt("wifi_link_speed",
                                                        0);
                                                signal.setWifi_link_speed(thisLinkSpeed);
                                                final int rssi = signalDataItem.optInt("wifi_rssi", UNKNOWN);
                                                if (rssi != UNKNOWN)
                                                    signal.setWifi_rssi(rssi);

                                                lteRsrp = signalDataItem.optInt("lte_rsrp", UNKNOWN);
                                                lteRsrq = signalDataItem.optInt("lte_rsrq", UNKNOWN);
                                                final int lteRssnr = signalDataItem.optInt("lte_rssnr", UNKNOWN);
                                                final int lteCqi = signalDataItem.optInt("lte_cqi", UNKNOWN);
                                                final long timeNs = signalDataItem.optLong("time_ns", UNKNOWN);
                                                signal.setLte_rsrp(lteRsrp);
                                                signal.setLte_rsrq(lteRsrq);
                                                signal.setLte_rssnr(lteRssnr);
                                                signal.setLte_cqi(lteCqi);
                                                signal.setTime_ns(timeNs);

                                                signal.storeSignal();

                                                if (networkType == 99) // wlan
                                                {
                                                    if (rssi < signalStrength && rssi != UNKNOWN)
                                                        signalStrength = rssi;
                                                } else if (thisSignalStrength < signalStrength
                                                        && thisSignalStrength != UNKNOWN)
                                                    signalStrength = thisSignalStrength;

                                                if (thisLinkSpeed != 0
                                                        && (linkSpeed == UNKNOWN || thisLinkSpeed < linkSpeed))
                                                    linkSpeed = thisLinkSpeed;

                                                if (signal.hasError()) {
                                                    errorList.addError(signal.getError());
                                                    break;
                                                }

                                            }
                                            // set rssi value (typically GSM,UMTS, but also old LTE-phones)
                                            if (signalStrength != Integer.MAX_VALUE && signalStrength != UNKNOWN
                                                    && signalStrength != 0) // 0 dBm is out of range
                                                ((IntField) test.getField("signal_strength"))
                                                        .setValue(signalStrength);
                                            // set rsrp value (typically LTE)
                                            if (lteRsrp != Integer.MAX_VALUE && lteRsrp != UNKNOWN && lteRsrp != 0) // 0 dBm is out of range
                                                ((IntField) test.getField("lte_rsrp")).setValue(lteRsrp);
                                            // set rsrq value (LTE)
                                            if (lteRsrq != Integer.MAX_VALUE && lteRsrq != UNKNOWN)
                                                ((IntField) test.getField("lte_rsrq")).setValue(lteRsrq);

                                            if (linkSpeed != Integer.MAX_VALUE && linkSpeed != UNKNOWN)
                                                ((IntField) test.getField("wifi_link_speed")).setValue(linkSpeed);
                                        }

                                        // use max network type

                                        final String sqlMaxNetworkType = "SELECT nt.uid" + " FROM signal s"
                                                + " JOIN network_type nt" + " ON s.network_type_id=nt.uid"
                                                + " WHERE test_id=?" + " ORDER BY nt.technology_order DESC"
                                                + " LIMIT 1";

                                        final PreparedStatement psMaxNetworkType = conn
                                                .prepareStatement(sqlMaxNetworkType);
                                        psMaxNetworkType.setLong(1, test.getUid());
                                        if (psMaxNetworkType.execute()) {
                                            final ResultSet rs = psMaxNetworkType.getResultSet();
                                            if (rs.next()) {
                                                final int maxNetworkType = rs.getInt("uid");
                                                if (maxNetworkType != 0)
                                                    ((IntField) test.getField("network_type"))
                                                            .setValue(maxNetworkType);
                                            }
                                        }

                                        /*
                                         * check for different types (e.g.
                                         * 2G/3G)
                                         */
                                        final String sqlAggSignal = "WITH agg AS"
                                                + " (SELECT array_agg(DISTINCT nt.group_name ORDER BY nt.group_name) agg"
                                                + " FROM signal s"
                                                + " JOIN network_type nt ON s.network_type_id=nt.uid WHERE test_id=?)"
                                                + " SELECT uid FROM agg JOIN network_type nt ON nt.aggregate=agg";

                                        final PreparedStatement psAgg = conn.prepareStatement(sqlAggSignal);
                                        psAgg.setLong(1, test.getUid());
                                        if (psAgg.execute()) {
                                            final ResultSet rs = psAgg.getResultSet();
                                            if (rs.next()) {
                                                final int newNetworkType = rs.getInt("uid");
                                                if (newNetworkType != 0)
                                                    ((IntField) test.getField("network_type"))
                                                            .setValue(newNetworkType);
                                            }
                                        }

                                        if (test.getField("network_type").intValue() <= 0)
                                            errorList.addError("ERROR_NETWORK_TYPE");

                                        final IntField downloadField = (IntField) test.getField("speed_download");
                                        if (downloadField.isNull() || downloadField.intValue() <= 0
                                                || downloadField.intValue() > 10000000) // 10 gbit/s limit
                                            errorList.addError("ERROR_DOWNLOAD_INSANE");

                                        final IntField upField = (IntField) test.getField("speed_upload");
                                        if (upField.isNull() || upField.intValue() <= 0
                                                || upField.intValue() > 10000000) // 10 gbit/s limit
                                            errorList.addError("ERROR_UPLOAD_INSANE");

                                        //clients still report eg: "test_ping_shortest":9195040 (note the 'test_' prefix there!)
                                        final LongField pingField = (LongField) test.getField("ping_shortest");
                                        if (pingField.isNull() || pingField.longValue() <= 0
                                                || pingField.longValue() > 60000000000L) // 1 min limit
                                            errorList.addError("ERROR_PING_INSANE");

                                        if (errorList.isEmpty())
                                            test.getField("status").setString("FINISHED");
                                        else
                                            test.getField("status").setString("ERROR");

                                        test.storeTestResults(false);

                                        if (test.hasError())
                                            errorList.addError(test.getError());

                                    } else
                                        errorList.addError("ERROR_CLIENT_VERSION");
                            } else
                                errorList.addError("ERROR_TEST_TOKEN_MALFORMED");
                        } catch (final IllegalArgumentException e) {
                            e.printStackTrace();
                            errorList.addError("ERROR_TEST_TOKEN_MALFORMED");
                        }

                    } else
                        errorList.addError("ERROR_TEST_TOKEN_MISSING");

                    conn.commit();
                } else
                    errorList.addError("ERROR_DB_CONNECTION");

            } catch (final JSONException e) {
                errorList.addError("ERROR_REQUEST_JSON");
                System.out.println("Error parsing JSDON Data " + e.toString());
                e.printStackTrace();
            } catch (final SQLException e) {
                System.out.println("Error while storing data " + e.toString());
                e.printStackTrace();
            }
        else
            errorList.addErrorString("Expected request is missing.");

        try {
            answer.putOpt("error", errorList.getList());
        } catch (final JSONException e) {
            System.out.println("Error saving ErrorList: " + e.toString());
        }

        return answer.toString();
    }

    @Get("json")
    public String retrieve(final String entity) {
        return request(entity);
    }

}