I'm trying to use Databroker of MD-SAL to save a list of data, after modifying the yang file and InstanceIdentifier many times but always facing similar validation issue, for example
java.util.concurrent.ExecutionException: TransactionCommitFailedException{message=canCommit encountered an unexpected failure, errorList=[RpcError [message=canCommit encountered an unexpected failure, severity=ERROR, errorType=APPLICATION, tag=operation-failed, applicationTag=null, info=null, cause=org.opendaylight.yangtools.yang.data.impl.schema.tree.SchemaValidationFailedException: Child /(urn:opendaylight:params:xml:ns:yang:testDataBroker?revision=2015-01-05)service-datas is not present in schema tree.]]}
at org.opendaylight.yangtools.util.concurrent.MappingCheckedFuture.wrapInExecutionExc
My goal is to use rpc save-device-info to get data from rest. Then use databroker api to save data in the memory and finally test if the data could be succesfully replicated into other cluster nodes.
Yang file:
module testDataBroker {
yang-version 1;
namespace "urn:opendaylight:params:xml:ns:yang:testDataBroker";
prefix "testDataBroker";
revision "2015-01-05" {
description "Initial revision of testDataBroker model";
}
container service-datas {
list service-data {
key "service-id";
uses service-id;
uses device-info;
}
}
grouping device-info {
container device-info {
leaf device-name {
type string;
config false;
}
leaf device-description {
type string;
config false;
}
}
}
grouping service-id {
leaf service-id {
type string;
mandatory true;
}
}
rpc save-device-info {
input {
uses service-id;
uses device-info;
}
output {
uses device-info;
}
}
rpc get-device-info {
output {
uses device-info;
}
}
}
Java Code
#Override public Future<RpcResult<SaveDeviceInfoOutput>> saveDeviceInfo(SaveDeviceInfoInput input) {
String name = input.getDeviceInfo().getDeviceName();
String description = input.getDeviceInfo().getDeviceDescription();
String serviceId = input.getServiceId();
WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
DeviceInfo deviceInfo = new DeviceInfoBuilder().setDeviceDescription(description).setDeviceName(name).build();
ServiceData serviceData = new ServiceDataBuilder().setServiceId(serviceId).setDeviceInfo(deviceInfo).build();
InstanceIdentifier<ServiceData> instanceIdentifier =
InstanceIdentifier.builder(ServiceDatas.class).child(ServiceData.class, serviceData.getKey()).build();
writeTransaction.put(LogicalDatastoreType.CONFIGURATION, instanceIdentifier, serviceData, true);
boolean isFailed = false;
try {
writeTransaction.submit().get();
log.info("Create containers succeeded!");
} catch (InterruptedException | ExecutionException e) {
log.error("Create containers failed: ", e);
isFailed = true;
}
return isFailed ?
RpcResultBuilder.success(new SaveDeviceInfoOutputBuilder())
.withError(RpcError.ErrorType.RPC, "Create container failed").buildFuture() :
RpcResultBuilder.success(new SaveDeviceInfoOutputBuilder().setDeviceInfo(input.getDeviceInfo()))
.buildFuture();
}
Really need your help. Thanks.
Update:
With the same version of md-sal bundles, I installed feature odl-toaster on only one ODL instead of cluster nodes. It seems like rpc from odl-toaster is working properly on single node.
I didn't realize that rpc is also clustered. Sometimes the rpc request hit on other nodes which didn't deploy the same bundles. Now the problem has been solved after the bundle is distrubted on each node.
Related
I'm struggling to save the uploaded file on AWS S3 bucket.
Using the latest Spring Boot 3.0.x DataBuffer feature I'm handling the Flux of PartEvents:
https://github.com/engilyin/useful-articles/blob/feature/%23183953976-s3-attachment-storage/backend/src/main/java/com/engilyin/usefularticles/services/sys/MultipartUploadService.java
public <T extends MultipartDataAccumulator<?>> Mono<T> loadData(Flux<PartEvent> rawPartEvents, T accumulator) {
return rawPartEvents.windowUntil(PartEvent::isLast)
.concatMap(p -> p.switchOnFirst((signal, partEvents) -> handlePart(signal, partEvents, accumulator)))
.then(Mono.just(accumulator));
}
private Publisher<PartEvent> handlePart(Signal<? extends PartEvent> signal,
Flux<PartEvent> partEvents,
MultipartDataAccumulator<?> accumulator) {
if (signal.hasValue()) {
PartEvent event = signal.get();
if (event instanceof FormPartEvent formEvent) {
accumulator.pushField(formEvent.name(), formEvent.value());
return Mono.empty();
} else if (event instanceof FilePartEvent fileEvent) {
log.debug("!!! FilePartEvent!");
String filename = accumulator.generateFilename(fileEvent.filename());
long fileSize = accumulator.attachmentSize();
return attachmentService.save(filename, fileSize, partEvents.map(PartEvent::content))
.then(Mono.empty());
} else {
return Mono.error(new RuntimeException("Unexpected event: " + event));
}
} else {
return partEvents; // either complete or error signal
}
}
And it works well for local file storage:
https://github.com/engilyin/useful-articles/blob/feature/%23183953976-s3-attachment-storage/backend/src/main/java/com/engilyin/usefularticles/services/storage/LocalFileAttachmentService.java
However it fails to upload onto the S3 storage:
https://github.com/engilyin/useful-articles/blob/feature/%23183953976-s3-attachment-storage/backend/src/main/java/com/engilyin/usefularticles/services/storage/S3AttachmentService.java
and
https://github.com/engilyin/useful-articles/blob/feature/%23183953976-s3-attachment-storage/backend/src/main/java/com/engilyin/usefularticles/services/storage/S3Service.java
public Mono<Boolean> save(String filename, long contentLength, Flux<DataBuffer> contentBuffers) {
Flux<ByteBuffer> buffers = Flux.from(contentBuffers.map(db -> {
log.debug("Next part: {}", db);
var buf = db.toByteBuffer();
DataBufferUtils.release(db);
// DataBufferUtils.releaseConsumer();
return buf;
}));
return s3Service.uploadBuffers(attachmentConfigProperties.getBucketName(), filename, contentLength, buffers);
}
public Mono<Boolean> uploadBuffers(String bucketName,
String objectKey,
long contentLength,
Flux<ByteBuffer> buffers) {
CompletableFuture<PutObjectResponse> future = s3AsyncClient.putObject(PutObjectRequest.builder()
.bucket(bucketName)
.contentLength(contentLength)
.key(objectKey)
//.contentType(MediaType.APPLICATION_OCTET_STREAM.toString())
.build(), AsyncRequestBody.fromPublisher(buffers));
return Mono.fromFuture(future).doOnError(this::handleError).map(this::checkResult);
}
I tried similar approach within some Integration JUnit test and it works just fine:
https://github.com/engilyin/useful-articles/blob/feature/%23183953976-s3-attachment-storage/backend/src/integration-test/java/com/engilyin/usefularticles/s3/S3Test.java
It seems like for some reason s3AsyncClient can't start pumping the data and } else if (event instanceof FilePartEvent fileEvent) { happens multiple times due to errors recognized on by s3AsyncClient to start handling the data from the stream.
PLEASE NOTE: it MUST not buffer whole file data, store it on the disk etc.
Would appreciate any help and ideas.
Thanks
I want to implement Play Install Referrer API and I found document and I read that but I have have some confusion. First I have implemented all code provided by google. But I want to know which type of url I need to create so that user can click on link and go to play store and install my app and then I get the referral detail..
I use this code:
InstallReferrerClient mReferrerClient;
mReferrerClient = newBuilder(this).build();
mReferrerClient.startConnection(this);
#Override
public void onInstallReferrerSetupFinished ( int responseCode){
switch (responseCode) {
case InstallReferrerClient.InstallReferrerResponse.OK:
// Connection established
/* ReferrerDetails response = null;
try {
response = mReferrerClient.getInstallReferrer();
response.getInstallReferrer();
response.getReferrerClickTimestampSeconds();
response.getInstallBeginTimestampSeconds();
} catch (RemoteException e) {
e.printStackTrace();
}*/
break;
case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
// API not available on the current Play Store app
break;
case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE:
// Connection could not be established
break;
}
}
#Override
public void onInstallReferrerServiceDisconnected () {
}
But which type of link I create so user go to play store and after install play store referral api give me data..
Sample url - "https://play.google.com/store/apps/details?id=com.dummy.app&referrer=referralCode%3D311566%26source%3DFacebook+App"
When using the Google Play Referrer API -
InstallReferrerClient mReferrerClient;
mReferrerClient = newBuilder(this).build();
mReferrerClient.startConnection(this);
#Override
public void onInstallReferrerSetupFinished ( int responseCode){
switch (responseCode) {
case InstallReferrerClient.InstallReferrerResponse.OK:
// Connection established
/* ReferrerDetails response = null;
try {
response = mReferrerClient.getInstallReferrer();
response.getInstallReferrer();
response.getReferrerClickTimestampSeconds();
response.getInstallBeginTimestampSeconds();
} catch (RemoteException e) {
e.printStackTrace();
}*/
// End the connection once you get the data
referrerClient.endConnection();
break;
case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
// API not available on the current Play Store app
break;
case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE:
// Connection could not be established
break;
}
}
#Override
public void onInstallReferrerServiceDisconnected () {
}
getInstallReferrer()
will return String 'referralCode=311566&source=Facebook App'
play install referral library i wants to describe this in simple wording, being a developer you wants to know about these elements how much time you app bundle take to install on the user devices from play store, and referral url , referral click time and many others elements , google make it easy for you know you have to use play install referral library for this purpose.
add this dependency
implementation 'com.android.installreferrer:installreferrer:1.1'
you can follow the guidelines from here:
play installer referral guidelines
declare this variable in any java activity
InstallReferrerClient referrerClient;
in on create method use this code below :
referrerClient = InstallReferrerClient.newBuilder(this).build();
referrerClient.startConnection(new InstallReferrerStateListener() {
#Override
public void onInstallReferrerSetupFinished(int responseCode) {
switch (responseCode) {
case InstallReferrerClient.InstallReferrerResponse.OK:
// Connection established.
break;
case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
// API not available on the current Play Store app.
break;
case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE:
// Connection couldn't be established.
break;
}
}
#Override
public void onInstallReferrerServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
});
inside onInstallReferrerSetupFinished stabled you can get these data easily,you code will be after that like this
ReferrerDetails response = null;
try {
response = referrerClient.getInstallReferrer();
} catch (RemoteException e) {
e.printStackTrace();
}
String referrerUrl = response.getInstallReferrer();
long referrerClickTime = response.getReferrerClickTimestampSeconds();
long appInstallTime = response.getInstallBeginTimestampSeconds();
boolean instantExperienceLaunched = response.getGooglePlayInstantParam();
whole code will be like this
referrerClient = InstallReferrerClient.newBuilder(this).build();
referrerClient.startConnection(new InstallReferrerStateListener() {
#Override
public void onInstallReferrerSetupFinished(int responseCode) {
switch (responseCode) {
case InstallReferrerClient.InstallReferrerResponse.OK:
// Connection established.
ReferrerDetails response = null;
try {
response = referrerClient.getInstallReferrer();
} catch (RemoteException e) {
e.printStackTrace();
}
String referrerUrl = response.getInstallReferrer();
long referrerClickTime = response.getReferrerClickTimestampSeconds();
long appInstallTime = response.getInstallBeginTimestampSeconds();
boolean instantExperienceLaunched = response.getGooglePlayInstantParam();
break;
case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
// API not available on the current Play Store app.
break;
case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE:
// Connection couldn't be established.
break;
}
}
#Override
public void onInstallReferrerServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
});
We have a .NET Core 2.1 AWS Lambda that I'm trying to hook into our existing logging system.
I'm trying to log through Serilog using a UDP sink to our logstash instance for ingestion into our ElasticSearch logging database that is hosted on a private VPC. Running locally through a console logs fine, both to the console itself and through UDP into Elastic. However, when it runs as a lambda, it only logs to the console (i.e CloudWatch), and doesn't output anything indicating that anything is wrong. Possibly because UDP is stateless?
NuGet packages and versions:
Serilog 2.7.1
Serilog.Sinks.Udp 5.0.1
Here is the logging code we're using:
public static void Configure(string udpHost, int udpPort, string environment)
{
var udpFormatter = new JsonFormatter(renderMessage: true);
var loggerConfig = new LoggerConfiguration()
.Enrich.FromLogContext()
.MinimumLevel.Information()
.Enrich.WithProperty("applicationName", Assembly.GetExecutingAssembly().GetName().Name)
.Enrich.WithProperty("applicationVersion", Assembly.GetExecutingAssembly().GetName().Version.ToString())
.Enrich.WithProperty("tags", environment);
loggerConfig
.WriteTo.Console(outputTemplate: "[{Level:u}]: {Message}{N---ewLine}{Exception}")
.WriteTo.Udp(udpHost, udpPort, udpFormatter);
var logger = loggerConfig.CreateLogger();
Serilog.Log.Logger = logger;
Serilog.Debugging.SelfLog.Enable(Console.Error);
}
// this is output in the console from the lambda, but doesn't appear in the Database from the lambda
// when run locally, appears in both
Serilog.Log.Logger.Information("Hello from Serilog!");
...
// at end of lambda
Serilog.Log.CloseAndFlush();
And here is our UDP input on logstash:
udp {
port => 5000
tags => [ 'systest', 'serilog-nested' ]
codec => json
}
Does anyone know how I might go about resolving this? Or even just seeing what specifically is wrong so that I can start to find a solution.
Things tried so far include:
Pinging logstash from the lambda - impossible, lambda doesn't have ICMP
Various things to try and get the UDP sink to output errors, as seen above, various attempts at that. Even putting in a completely fake address yields no error though
Adding the lambda to a VPC where I know logging is possible from
Sleeping around at the end of the lambda. SO that the logs have time to go through before the lambda exits
Checking the logstash logs to see if anything looks odd. It doesn't really. And the fact that local runs get through fine makes me think it's not that.
Using UDP directly. It doesn't seem to reach the server. I'm not sure if that's connectivity issues or just UDP itself from a lambda.
Lots of cursing and swearing
In line with my comment above you can create a log subscription and stream to ES like so, I'm aware that this is NodeJS so it's not quite the right answer but you might be able to figure it out from here:
/* eslint-disable */
// Eslint disabled as this is adapted AWS code.
const zlib = require('zlib')
const { Client } = require('#elastic/elasticsearch')
const elasticsearch = new Client({ ES_CLUSTER_DETAILS })
/**
* This is an example function to stream CloudWatch logs to ElasticSearch.
* #param event
* #param context
* #param callback
*/
export default (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = true
const payload = new Buffer(event.awslogs.data, 'base64')
zlib.gunzip(payload, (err, result) => {
if (err) {
return callback(null, err)
}
const logObject = JSON.parse(result.toString('utf8'))
const elasticsearchBulkData = transform(logObject)
const params = { body: [] }
params.body.push(elasticsearchBulkData)
esClient.bulk(params, (err, resp) => {
if (err) {
callback(null, 'success')
return
}
})
callback(null, 'success')
})
}
function transform(payload) {
if (payload.messageType === 'CONTROL_MESSAGE') {
return null
}
let bulkRequestBody = ''
payload.logEvents.forEach((logEvent) => {
const timestamp = new Date(1 * logEvent.timestamp)
// index name format: cwl-YYYY.MM.DD
const indexName = [
`cwl-${process.env.NODE_ENV}-${timestamp.getUTCFullYear()}`, // year
(`0${timestamp.getUTCMonth() + 1}`).slice(-2), // month
(`0${timestamp.getUTCDate()}`).slice(-2), // day
].join('.')
const source = buildSource(logEvent.message, logEvent.extractedFields)
source['#id'] = logEvent.id
source['#timestamp'] = new Date(1 * logEvent.timestamp).toISOString()
source['#message'] = logEvent.message
source['#owner'] = payload.owner
source['#log_group'] = payload.logGroup
source['#log_stream'] = payload.logStream
const action = { index: {} }
action.index._index = indexName
action.index._type = 'lambdaLogs'
action.index._id = logEvent.id
bulkRequestBody += `${[
JSON.stringify(action),
JSON.stringify(source),
].join('\n')}\n`
})
return bulkRequestBody
}
function buildSource(message, extractedFields) {
if (extractedFields) {
const source = {}
for (const key in extractedFields) {
if (extractedFields.hasOwnProperty(key) && extractedFields[key]) {
const value = extractedFields[key]
if (isNumeric(value)) {
source[key] = 1 * value
continue
}
const jsonSubString = extractJson(value)
if (jsonSubString !== null) {
source[`$${key}`] = JSON.parse(jsonSubString)
}
source[key] = value
}
}
return source
}
const jsonSubString = extractJson(message)
if (jsonSubString !== null) {
return JSON.parse(jsonSubString)
}
return {}
}
function extractJson(message) {
const jsonStart = message.indexOf('{')
if (jsonStart < 0) return null
const jsonSubString = message.substring(jsonStart)
return isValidJson(jsonSubString) ? jsonSubString : null
}
function isValidJson(message) {
try {
JSON.parse(message)
} catch (e) { return false }
return true
}
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n)
}
One of my colleagues helped me get most of the way there, and then I managed to figure out the last bit.
I updated Serilog.Sinks.Udp to 6.0.0
I updated the UDP setup code to use the AddressFamily.InterNetwork specifier, which I don't believe was available in 5.0.1.
I removed enriching our log messages with "tags", since I believe it being present on the UDP endpoint somehow caused some kind of clash and I've seen it stop logging without a trace before.
And voila!
Here's the new logging setup code:
loggerConfig
.WriteTo.Udp(udpHost, udpPort, AddressFamily.InterNetwork, udpFormatter)
.WriteTo.Console(outputTemplate: "[{Level:u}]: {Message}{NewLine}{Exception}");
When I run my code I get:
Breaking on exception: String expected
What I am trying to do is connect to my server using a websocket. However, it seems that no matter if my server is online or not the client still crashes.
My code:
import 'dart:html';
WebSocket serverConn;
int connectionAttempts;
TextAreaElement inputField = querySelector("#inputField");
String key;
void submitMessage(Event e) {
if (serverConn.readyState == WebSocket.OPEN) {
querySelector("#chatLog").text = inputField.value;
inputField.value = "";
}
}
void recreateConnection(Event e) {
connectionAttempts++;
if (connectionAttempts <= 5) {
inputField.value = "Connection failed, reconnecting. Attempt" + connectionAttempts.toString() + "out of 5";
serverConn = new WebSocket("ws://127.0.0.1:8887");
serverConn.onClose.listen(recreateConnection);
serverConn.onError.listen(recreateConnection);
} else {
inputField.value = "Connections ran out, please refresh site";
}
}
void connected(Event e) {
serverConn.sendString(key);
if (serverConn.readyState == WebSocket.OPEN) {
inputField.value = "CONNECTED!";
inputField.readOnly = false;
}
}
void main() {
serverConn = new WebSocket("ws://127.0.0.1:8887");
serverConn.onClose.listen(recreateConnection);
serverConn.onError.listen(recreateConnection);
serverConn.onOpen.listen(connected);
//querySelector("#inputField").onInput.listen(submitMessage);
querySelector("#sendInput").onClick.listen(submitMessage);
}
My Dart Editor says nothing about where the problem comes from nor does it give any warning until run-time.
You need to initialize int connectionAttempts; with a valid value;
connectionAttempts++; fails with an exception on null.
You also need an onMessage handler to receive messages.
serverConn.onMessage.listen((MessageEvent e) {
recreateConnection should register an onOpen handler as well.
After serverConn = new WebSocket the listener registered in main() will not work
If you register a listener where only one single event is expected you can use first instead of listen
serverConn.onOpen.first.then(connected);
According to #JAre s comment.
Try to use a hardcoded string
querySelector("#chatLog").text = 'someValue';
to ensure this is not the culprit.
I am trying to submit data to a server where it is picked and stored in salesforce. The error I am getting is "Attempt to de-reference a null object" at the server. so I am wondering what the problem is...
Below is the sample code:
public static List<String> processAgentVisitSurvey(ProcessSurveySubmission.SurveySubmission submission, Map<String, Submission_Answer__c> answers, Person__c person) {
// Load the TDR
TDR__c tdr = loadTdr(person);
if (tdr == null) {
//Send an email saying that an unregistered person is trying to act a TDR
// Send back the error message
return new String[] { '0', 'User with handset Id ' + submission.imei + ' is not a TDR', 'SUPRESSMSG' };
}
This is the source of the error message.
There is a class the redirects to this method:
private static List<String> additionalProcessing(
SurveySubmission surveySubmission,
Survey__c survey,
Person__c interviewer,
Id intervieweeId
) {
List<String> returnValues = new List<String>();
Map<String, Submission_Answer__c> answers = parseSubmissionToMap(surveySubmission);
// Find the name of the method that this survey hooks into to do its post processing
try {
if (survey.Post_Processing_Method__c.equalsIgnoreCase('None')) {
returnValues.add('0');
returnValues.add('There is no post processing method specified for this survey');
returnValues.add('SUPRESSMSG');
}
else if (survey.Post_Processing_Method__c.equals('CKW_Registration')) {
return CkwRegistration.processCkwRegistration(answers, interviewer);
}
else if (survey.Post_Processing_Method__c.equals('CKW_Baseline')) {
return CkwRegistration.processCkwBaseline(answers, interviewer);
}
else if (survey.Post_Processing_Method__c.equals('CKW_Staff_Update')) {
return CkwRegistration.processCkwUpdate(answers, interviewer);
}
else if (survey.Post_Processing_Method__c.equals('Subcounty_Registration')) {
return CkwRegistration.processSubcounties(answers, interviewer);
}
else if (survey.Post_Processing_Method__c.equals('TDR_AGENT_VISIT')) {
return TdrHelpers.processAgentVisitSurvey(surveySubmission, answers, interviewer);
}
else if (survey.Post_Processing_Method__c.equals('UDOM_RAIN_GUAGE')) {
return UDoMSurveyProcessing.processDailyRainGauge(surveySubmission, answers, interviewer);
}
else if (survey.Post_Processing_Method__c.equals('UDOM_RAIN_GUAGE_REG')) {
return UDoMSurveyProcessing.registerRainGauge(surveySubmission, answers, interviewer);
}
else if (survey.Post_Processing_Method__c.equals('MTN_CHANNELS')) {
return MtnChannelsHelpers.processChannelsFFPSSurvey(surveySubmission, answers, interviewer);
}
else if (survey.Post_Processing_Method__c.equals('FHI_GROUP_REGISTRATION')) {
return FHISurveysHelpers.processGroupRegistration(surveySubmission, answers, interviewer, survey.Survey_Name__c);
}
else if (survey.Post_Processing_Method__c.equals('FHI_HOUSEHOLD_REGISTRATION')) {
return FHISurveysHelpers.processHouseholdRegistration(surveySubmission, answers, interviewer, survey.Survey_Name__c);
}
// else if (survey.Post_Processing_Method__c.equals('Colombia_Farmer_Registration')) {
// return ColombiaFarmerRegistrationPostProcessor.processSubmission(surveySubmission, answers, interviewer);
// }
else if (survey.Post_Processing_Method__c.equals('FIELD_OFFICER_SUPPORT')) {
return FieldOfficeHelpers.processFoSurvey(surveySubmission, answers, interviewer);
}
// else if (survey.Post_Processing_Method__c.equals('DATA_VALIDATOR_SPOT_CHECK')) {
// return DataValidatorHelpers.processSpotCheck(surveySubmission, answers, interviewer);
// }
// else if (survey.Post_Processing_Method__c.equals('DATA_VALIDATOR_BACK_CHECK')) {
// return DataValidatorHelpers.processBackCheck(surveySubmission, answers, interviewer);
// }
else if (survey.Post_Processing_Method__c.equals('EQUIPMENT_TRACKING')) {
return EquipmentTrackingHelpers.processFieldOfficerSubmission(surveySubmission, answers, interviewer);
}
}
catch (Exception e) {
returnValues.add('0');
returnValues.add(e.getMessage());
returnValues.add('An error occured. Please contact support');
}
return returnValues;
}
which I think is fine...
Please help coz I do not seem to see any problem
Thank you. I hope the code provide is enough.
Usually when I run across that error my first instinct is to look for any queries. In APEX when you return a null value (expected or not) into a single item such as Person__c person = [query that returns objects}; that error is thrown.
The SOLUTION is to ensure data gets returned into a concrete SObject such as...
List<Person__c> persons = [Here is a query or method call];
Then you would check the list with persons.size() This obeys salesforce's Bulkify everything approach they enforce as well as a more robust backend.
Sorry I couldn't provide more support, the error wasn't very evident in your code samples without a line number or debug log.
Good Luck!
Be aware: This error can also appear if you are trying to reference an uninstantiated property of a class.
Example: If you declare a List property of a class, but never instantiate it, and then attempt to add to that list, you will get this error.