org.glassfish.json.JsonArrayBuilder error

Digital One6 years ago

There's a new DmtHttpProtocol tracker that only uses WifiAccessPoints, so no lat/lng, and needs to geolocate each time through for example Google.

I am however receiving an error on the JsonObject, and I've tried everything. Is there something related to how it works that I'm missing?

org.glassfish.json.JsonArrayBuilderImpl$JsonArrayImpl cannot be cast to javax.json.JsonObject - ClassCastException (... < DmtHttpProtocolDecoder:136 < ExtendedObjectDecoder:51 < ... < WrapperContext:102 < ...)

{
  "SerNo": 100000,
  "IMEI": "#",
  "ICCID": "#",
  "ProdId": 72,
  "FW": "72.2.1.3",
  "Records": [
    {
      "SeqNo": 53,
      "Reason": 11,
      "DateUTC": "2019-01-18 18:52:45",
      "Fields": [
        {
          "APs": [
            {
              "MAC": "00:00:00:00:00:00",
              "Sig": -44,
              "Ch": 11
            },
            {
              "MAC": "00:00:00:00:00:01",
              "Sig": -46,
              "Ch": 11
            }
          ],
          "FType": 25
        },
        {
          "Towers": [
            {
              "CID": 00000000,
              "LAC": 00000,
              "MCC": 000,
              "MNC": 000
            }
          ],
          "FType": 28
        },
        {
          "DIn": 0,
          "DOut": 0,
          "DevStat": 0,
          "FType": 2
        },
        {
          "AnalogueData": {
            "1": 4503,
            "3": 2627,
            "4": 17,
            "5": 4516
          },
          "FType": 6
        }
      ]
    }
  ]
}

I've done the following:

import org.traccar.model.CellTower;
import org.traccar.model.Network;
import org.traccar.model.WifiAccessPoint;

...

                    case 25:
                        JsonArray waps = field.getJsonArray("APs");
                        for (int k = 0; k < waps.size(); k++) {
                            JsonObject wap = waps.getJsonObject(k);
                            network.addWifiAccessPoint(WifiAccessPoint.from(
                                    wap.getString("MAC"),
                                    wap.getInt("Sig"),
                                    wap.getInt("Ch")
                            ));
                        }
                        break;
                    case 28:
                        JsonObject ct = field.getJsonObject("Towers");
                        network.addCellTower(CellTower.from(
                                ct.getInt("MCC"),
                                ct.getInt("MNC"),
                                ct.getInt("LAC"),
                                ct.getInt("CID")
                        ));
Anton Tananaev6 years ago

As error message clearly tells you, you are trying to convert JSON array into JSON object.

Digital One6 years ago

"APs" is an array of several WifiAccessPoints.

I've tried to set it up as a JsonObject = field.getJsonObject("APs"), and access but still run into the same error.

Anton Tananaev6 years ago

Please provide information about new device, server logs with HEX samples and updated protocol documentation.

Digital One6 years ago

DigitalMatter Yabby WiFi

/*
 * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org)
 *
 * 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 org.traccar.protocol;

import io.netty.channel.Channel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.traccar.BaseHttpProtocolDecoder;
import org.traccar.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.CellTower;
import org.traccar.model.Network;
import org.traccar.model.Position;
import org.traccar.model.WifiAccessPoint;

import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
import java.io.StringReader;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.TimeZone;

public class DmtHttpProtocolDecoder extends BaseHttpProtocolDecoder {

    public DmtHttpProtocolDecoder(Protocol protocol) {
        super(protocol);
    }

    @Override
    protected Object decode(
            Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {

        FullHttpRequest request = (FullHttpRequest) msg;
        JsonObject root = Json.createReader(
                new StringReader(request.content().toString(StandardCharsets.US_ASCII))).readObject();

        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));

        DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, root.getString("IMEI"));
        if (deviceSession == null) {
            sendResponse(channel, HttpResponseStatus.BAD_REQUEST);
            return null;
        }

        List<Position> positions = new LinkedList<>();

        JsonArray records = root.getJsonArray("Records");

        for (int i = 0; i < records.size(); i++) {
            Network network = new Network();

            Position position = new Position(getProtocolName());
            position.setDeviceId(deviceSession.getDeviceId());

            JsonObject record = records.getJsonObject(i);

            position.set(Position.KEY_INDEX, record.getInt("SeqNo"));
            position.set(Position.KEY_EVENT, record.getInt("Reason"));

            position.setDeviceTime(dateFormat.parse(record.getString("DateUTC")));

            JsonArray fields = record.getJsonArray("Fields");

            for (int j = 0; j < fields.size(); j++) {
                JsonObject field = fields.getJsonObject(j);
                switch (field.getInt("FType")) {
                    case 0:
                        position.setFixTime(dateFormat.parse(field.getString("GpsUTC")));
                        position.setLatitude(field.getJsonNumber("Lat").doubleValue());
                        position.setLongitude(field.getJsonNumber("Long").doubleValue());
                        position.setAltitude(field.getInt("Alt"));
                        position.setSpeed(UnitsConverter.knotsFromCps(field.getInt("Spd")));
                        position.setCourse(field.getInt("Head"));
                        position.setAccuracy(field.getInt("PosAcc"));
                        position.setValid(field.getInt("GpsStat") > 0);
                        break;
                    case 2:
                        int input = field.getInt("DIn");
                        int output = field.getInt("DOut");

                        position.set(Position.KEY_IGNITION, BitUtil.check(input, 0));

                        position.set(Position.KEY_INPUT, input);
                        position.set(Position.KEY_OUTPUT, output);
                        position.set(Position.KEY_STATUS, field.getInt("DevStat"));
                        break;
                    case 6:
                        JsonObject adc = field.getJsonObject("AnalogueData");
                        if (adc.containsKey("1")) {
                            position.set(Position.KEY_BATTERY, adc.getInt("1") * 0.001);
                        }
                        if (adc.containsKey("2")) {
                            position.set(Position.KEY_POWER, adc.getInt("2") * 0.01);
                        }
                        if (adc.containsKey("3")) {
                            position.set(Position.KEY_DEVICE_TEMP, adc.getInt("3") * 0.01);
                        }
                        if (adc.containsKey("4")) {
                            position.set(Position.KEY_RSSI, adc.getInt("4"));
                        }
                        if (adc.containsKey("5")) {
                            position.set("solarPower", adc.getInt("5") * 0.001);
                        }
                        break;
                    case 25:
                        JsonArray waps = field.getJsonArray("APs");
                        for (int k = 0; k < waps.size(); k++) {
                            JsonObject wap = waps.getJsonObject(k);
                            network.addWifiAccessPoint(WifiAccessPoint.from(
                                    wap.getString("MAC"),
                                    wap.getInt("Sig"),
                                    wap.getInt("Ch")
                            ));
                        }
                        break;
                    case 28:
                        JsonObject ct = field.getJsonObject("Towers");
                        network.addCellTower(CellTower.from(
                                ct.getInt("MCC"),
                                ct.getInt("MNC"),
                                ct.getInt("LAC"),
                                ct.getInt("CID")
                        ));
                        break;
                    default:
                        break;
                }
            }

            if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) {
                position.setNetwork(network);
            }

            positions.add(position);
        }

        sendResponse(channel, HttpResponseStatus.OK);
        return positions;
    }

}
504f5354202f20485454502f312e310d0a436f6e74656e742d547970653a206170706c69636174696f6e2f6a736f6e3b20636861727365743d7574662d380d0a4163636570743a20746578742f68746d6c2c746578742f786d6c2c746578742f6a736f6e2c6170706c69636174696f6e2f7868746d6c2b786d6c2c6170706c69636174696f6e2f786d6c3b713d302e392c2a2f2a3b713d302e380d0a486f73743a2036382e3138332e3136372e3135323a353133390d0a436f6e74656e742d4c656e6774683a20313733380d0a436f6e6e656374696f6e3a20436c6f73650d0a0d0a7b225365724e6f223a3137343535352c22494d4549223a22333532373533303932303234353336222c224943434944223a2238393031323630383532323931343231393634222c2250726f644964223a37322c224657223a2237322e322e312e33222c225265636f726473223a5b7b225365714e6f223a35332c22526561736f6e223a31312c2244617465555443223a22323031392d30312d31382031383a35323a3435222c224669656c6473223a5b7b22415073223a5b7b224d4143223a2246303a39463a43323a41343a39383a3030222c22536967223a2d34342c224368223a31317d2c7b224d4143223a2246323a39463a43323a41343a39383a3030222c22536967223a2d34362c224368223a31317d2c7b224d4143223a2238303a32413a41383a39313a46413a3038222c22536967223a2d34372c224368223a367d2c7b224d4143223a2242303a42453a37363a34353a41443a4644222c22536967223a2d35342c224368223a327d2c7b224d4143223a2242383a45433a41333a35413a31413a3644222c22536967223a2d35372c224368223a31317d2c7b224d4143223a2242303a42453a37363a34353a41393a4139222c22536967223a2d36302c224368223a31317d2c7b224d4143223a2242303a42453a37363a34353a42333a4442222c22536967223a2d36342c224368223a327d2c7b224d4143223a2235453a46343a41423a32423a43443a4538222c22536967223a2d36362c224368223a31317d2c7b224d4143223a2245323a35353a37443a41443a35373a4531222c22536967223a2d36392c224368223a31317d2c7b224d4143223a2243303a32353a45393a35413a39383a3835222c22536967223a2d37302c224368223a327d2c7b224d4143223a2241453a32303a32453a46373a36393a3130222c22536967223a2d37322c224368223a367d2c7b224d4143223a2246303a39463a43323a41343a46353a3330222c22536967223a2d37322c224368223a367d2c7b224d4143223a2246323a39463a43323a41343a46353a3330222c22536967223a2d37322c224368223a367d2c7b224d4143223a2232303a46383a35453a31423a34363a3943222c22536967223a2d37322c224368223a337d2c7b224d4143223a2245323a35353a37443a41423a37373a4531222c22536967223a2d37322c224368223a317d2c7b224d4143223a2232303a46383a35453a31423a34373a3530222c22536967223a2d37332c224368223a337d2c7b224d4143223a2242303a33393a35363a39343a31333a3144222c22536967223a2d37342c224368223a31317d2c7b224d4143223a2231323a37423a45463a39433a42463a3830222c22536967223a2d37342c224368223a387d2c7b224d4143223a2236303a45333a32373a42303a36373a3444222c22536967223a2d37352c224368223a31317d2c7b224d4143223a2246303a39463a43323a33313a46423a4635222c22536967223a2d37362c224368223a367d2c7b224d4143223a2237383a38413a32303a37313a43313a3839222c22536967223a2d37372c224368223a367d2c7b224d4143223a2230453a39463a44423a35463a43363a3941222c22536967223a2d37382c224368223a31317d2c7b224d4143223a2244343a36453a30453a33353a44393a3738222c22536967223a2d37382c224368223a317d2c7b224d4143223a2243303a35363a32373a36453a42443a3834222c22536967223a2d37392c224368223a31317d2c7b224d4143223a2243323a35363a32373a36453a42443a3836222c22536967223a2d37392c224368223a31317d2c7b224d4143223a2246383a42423a42463a39353a39413a3033222c22536967223a2d37392c224368223a317d2c7b224d4143223a2245323a42363a35383a34393a39443a3034222c22536967223a2d37392c224368223a367d2c7b224d4143223a2245383a31443a41383a30323a32303a3038222c22536967223a2d37392c224368223a367d2c7b224d4143223a2231303a31333a33313a38433a42333a3936222c22536967223a2d37392c224368223a317d2c7b224d4143223a2245383a31443a41383a30323a33433a4538222c22536967223a2d38302c224368223a317d5d2c224654797065223a32357d2c7b22546f77657273223a5b7b22434944223a32313530383831312c224c4143223a36303138302c224d4343223a3331302c224d4e43223a3236307d5d2c224654797065223a32387d2c7b2244496e223a302c22444f7574223a302c2244657653746174223a302c224654797065223a327d2c7b22416e616c6f67756544617461223a7b2231223a343530332c2233223a323632372c2234223a31372c2235223a343531367d2c224654797065223a367d5d7d5d7d485454502f312e3120323030204f4b0d0a636f6e74656e742d6c656e6774683a20300d0a0d0a
Digital One6 years ago

Also, quick question on testing.

I'm trying to run the code from the DmtHttpProtocolDecoderTest.java -- so technically, it should work, however I get this in response.

curl \
        -X POST \
        -H "Content-Type: application/json; charset=utf-8" \
        -d "{\"SerNo\":131693,\"IMEI\":\"356692063643328\",\"ICCID\":\"8944538523010771676\",\"ProdId\":33,\"FW\":\"33.4.1.27\",\"Records\":[{\"SeqNo\":125,\"Reason\":11,\"DateUTC\":\"2017-05-11 05:58:44\",\"Fields\":[{\"GpsUTC\":\"2017-05-08 18:04:57\",\"Lat\":43.7370138,\"Long\":-79.3462607,\"Alt\":197,\"Spd\":0,\"SpdAcc\":13,\"Head\":66,\"PDOP\":18,\"PosAcc\":37,\"GpsStat\":7,\"FType\":0},{\"DIn\":2,\"DOut\":0,\"DevStat\":2,\"FType\":2},{\"AnalogueData\":{\"1\":14641,\"3\":2484,\"4\":26,\"5\":10868},\"FType\":6},{\"AnalogueData\":{\"11\":34,\"12\":0,\"13\":309,\"14\":9921,\"15\":3},\"FType\":7}]},{\"SeqNo\":128,\"Reason\":11,\"DateUTC\":\"2017-05-11 17:59:45\",\"Fields\":[{\"GpsUTC\":\"2017-05-08 18:04:57\",\"Lat\":43.7370138,\"Long\":-79.3462607,\"Alt\":197,\"Spd\":0,\"SpdAcc\":13,\"Head\":66,\"PDOP\":18,\"PosAcc\":37,\"GpsStat\":7,\"FType\":0},{\"DIn\":2,\"DOut\":0,\"DevStat\":2,\"FType\":2},{\"AnalogueData\":{\"1\":14607,\"3\":2752,\"4\":26,\"5\":11062},\"FType\":6},{\"AnalogueData\":{\"11\":34,\"12\":1,\"13\":325,\"14\":10881,\"15\":3},\"FType\":7}]},{\"SeqNo\":130,\"Reason\":9,\"DateUTC\":\"2017-05-11 19:30:03\",\"Fields\":[{\"GpsUTC\":\"2017-05-08 18:04:57\",\"Lat\":43.7370138,\"Long\":-79.3462607,\"Alt\":197,\"Spd\":0,\"SpdAcc\":13,\"Head\":66,\"PDOP\":18,\"PosAcc\":37,\"GpsStat\":3,\"FType\":0},{\"DIn\":6,\"DOut\":0,\"DevStat\":2,\"FType\":2},{\"AnalogueData\":{\"1\":14599,\"3\":2731,\"4\":27,\"5\":10965},\"FType\":6},{\"AnalogueData\":{\"11\":34,\"12\":2,\"13\":329,\"14\":11121,\"15\":3},\"FType\":7}]},{\"SeqNo\":131,\"Reason\":11,\"DateUTC\":\"2017-05-11 19:32:03\",\"Fields\":[{\"GpsUTC\":\"2017-05-08 18:04:57\",\"Lat\":43.7370138,\"Long\":-79.3462607,\"Alt\":197,\"Spd\":0,\"SpdAcc\":13,\"Head\":66,\"PDOP\":18,\"PosAcc\":37,\"GpsStat\":7,\"FType\":0},{\"DIn\":6,\"DOut\":0,\"DevStat\":2,\"FType\":2},{\"AnalogueData\":{\"1\":14403,\"3\":2783,\"4\":27,\"5\":10965},\"FType\":6},{\"AnalogueData\":{\"11\":34,\"12\":2,\"13\":330,\"14\":11181,\"15\":3},\"FType\":7}]},{\"SeqNo\":133,\"Reason\":11,\"DateUTC\":\"2017-05-11 19:36:15\",\"Fields\":[{\"GpsUTC\":\"2017-05-08 18:04:57\",\"Lat\":43.7370138,\"Long\":-79.3462607,\"Alt\":197,\"Spd\":0,\"SpdAcc\":13,\"Head\":66,\"PDOP\":18,\"PosAcc\":37,\"GpsStat\":7,\"FType\":0},{\"DIn\":6,\"DOut\":0,\"DevStat\":2,\"FType\":2},{\"AnalogueData\":{\"1\":14319,\"3\":2898,\"4\":23,\"5\":10965},\"FType\":6},{\"AnalogueData\":{\"11\":34,\"12\":3,\"13\":331,\"14\":11241,\"15\":3},\"FType\":7}]}]}" \
        localhost:5139

Response:

2019-01-18 15:10:04  INFO: [2eabade7: 5139 < 0:0:0:0:0:0:0:1] HEX: 504f5354202f20485454502f312e310d0a486f73743a206c6f63616c686f73743a353133390d0a557365722d4167656e743a206375726c2f372e35342e300d0a4163636570743a202a2f2a0d0a436f6e74656e742d547970653a206170706c69636174696f6e2f6a736f6e3b20636861727365743d7574662d380d0a436f6e74656e742d4c656e6774683a20323130350d0a4578706563743a203130302d636f6e74696e75650d0a0d0a
2019-01-18 15:10:04  WARN: [2eabade7] error - io.netty.buffer.PooledUnsafeDirectByteBuf cannot be cast to org.traccar.NetworkMessage - ClassCastException (BasePipelineFactory:141 < *:136 < ... < WrapperOutboundHandler:74 < ... < WrapperContext:205 < ...)
2019-01-18 15:10:04  INFO: [2eabade7] disconnected
POST / HTTP/1.1
Host: localhost:5139
User-Agent: curl/7.54.0
Accept: */*
Content-Type: application/json; charset=utf-8
Content-Length: 2105
Expect: 100-continue
Anton Tananaev6 years ago

Are you using official version or your modified one?

Digital One6 years ago

Modified version, but tried with the official version and still seeing that issue. I can't seem to POST the JSON. I'm getting:

curl: (52) Empty reply from server
Anton Tananaev6 years ago

Fixed. Please try now.

Digital One6 years ago

Now working perfectly. Thanks for that!

Digital One6 years ago

Alrighty, so I'm working on the geolocation aspect. I'm unsure how GeolocationHandler gets triggered?

I've set the position.setValid(false), and position.setNetwork(network) and have geolocation.processInvalidPositions set to true.

DmtHttpProtocolDecoder.java
...
if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) {
    position.setValid(false);
    position.setNetwork(network);
}
GeolocationHandler.java
...
position.getOutdated() || processInvalidPositions && !position.getValid()) && position.getNetwork() != null
Anton Tananaev6 years ago

Check other decoders for examples.

Digital One6 years ago

I checked several but unsure what actually triggers geolocation.

The other decoders for example Smokey, just shows adding WiFi access points to network and setting network.

It seems from the conditions above should trigger geolocation, but it does not.

Anton Tananaev6 years ago

Just debug the code and see what happens.