Does anyone know how to get a workflow malfunction error message using the java pe api? I am running the QueueSample java code provided by IBM and it is not clear to me how to do this. Any help would be appreciated!
I found the malfunction error message for my workflow in the VWParticipantHistory.getLogFields() array. I modified the example code from the Developing Applications with IBM FileNet P8 APIs redbook:
// Create session object and log onto Process Engine
...
// Get the specific work item
...
// Get VWProcess object from work object
VWProcess process = stepElement.fetchProcess();
// Get workflow definitions from the VWProcess
VWWorkflowDefinition workflowDefinition =
process.fetchWorkflowDefinition(false);
// Get maps for each workflow definition
VWMapDefinition[] workflowMaps = workflowDefinition.getMaps();
// Iterate through each map in the workflow Definition
for (int i = 0; i < workflowMaps.length; i++) {
// Get map ID and map name for each map definition
int mapID = workflowMaps[i].getMapId();
String mapName = workflowMaps[i].getName();
// Get workflow history information for each map
VWWorkflowHistory workflowHistory = process.fetchWorkflowHistory(mapID);
String workflowOriginator = workflowHistory.getOriginator();
// Iterate through each item in the Workflow History
while (workflowHistory.hasNext()) {
// Get step history objects for each workflow history
VWStepHistory stepHistory = workflowHistory.next();
String stepName = stepHistory.getStepName();
System.out.println("step history name = " + stepName);
// Iterate through each item in the Step History
while (stepHistory.hasNext()) {
// Get step occurrence history
// objects for each step history object
VWStepOccurrenceHistory stepOccurenceHistory = stepHistory.next();
Date stepOcurrenceDateReceived = stepOccurenceHistory.getDateReceived();
Date stepOcurrenceDateCompleted = stepOccurenceHistory.getCompletionDate();
while (stepOccurenceHistory.hasNext()) {
// Get step work object information
// for each step occurrence
VWStepWorkObjectHistory stepWorkObjectHistory = stepOccurenceHistory.next();
stepWorkObjectHistory.resetFetch();
// Get participant information for each work object
while (stepWorkObjectHistory.hasNext()) {
VWParticipantHistory participantHistory = stepWorkObjectHistory.next();
String opName = participantHistory.getOperationName();
System.out.println("operation name = " + opName);
Date participantDateReceived = participantHistory.getDateReceived();
String participantComments = participantHistory.getComments();
String participantUser = participantHistory.getUserName();
String participantName = participantHistory.getParticipantName();
VWDataField[] logFields = participantHistory.getLogFields();
System.out.println("** start get log fields **");
for (int index=0; index<logFields.length; index++){
VWDataField dataField = logFields[index];
String name = dataField.getName();
String val = dataField.getStringValue();
System.out.println("name = " + name + " , value = " + val);
}
System.out.println("** end get log fields **");
} // while stepWorkObjectHistory
} // while stepOccurenceHistory
} // while stepHistory
} // while workflowHistory
} // for workflow maps
Related
I get the following error message when running some code in Google Apps Script. I don't understand the Line/Column reference, Code:46:18. It appears to point to either a line with too few columns or a process with too few lines. I assume I am not interpreting the reference correctly.
TypeError: Cannot set property 'format' of undefined
at processInbox(processInbox Code:46:18)
Line 46 of all my code is this and certainly doesn't have 18 columns (and it closes a function that doesn't refer to format):
}
The process referred to by the error message, processInbox, is only 39 lines long.
The script is called by selecting "Run Script" in the menu, "CiviSchedule" in the related Google Sheet, which triggers the doTasks function. This menu and and trigger are created in the onOpen function.
How am I misinterpreting the error message? (Full code follows)
[screenshot of error]
[screenshot of lines 40-46]
The code for reference:
//General Info
//
// As detailed in Managing Scheduled Jobs URL method http://wiki.civicrm.org/confluence/display/CRMDOC/Managing+Scheduled+Jobs#ManagingScheduledJobs-URLmethod :
//
// a valid Username and Password (for a Drupal, Joomla or WordPress user who has adequate permissions
// for the job or jobs being run. The minimal permissions for that user are: “view all contacts”, “access
// CiviCRM”, “access CiviMail”). It also requires you to pass in the CIVICRM_SITE_KEY which is configured
// by editing your copy of civicrm.settings.php
//
// I’d recommend setting up a dedicated account for scheduling reports with only minimal permissions.
// Once you have a username/password setup open File > Project Properties and open the Script Properties
// tab. Click ‘Add row’ link and add your setup account name (username), pass (password), key (site key).
// Save the Script Properties and then in the script editor window enter the BASE_URL below of your Civi
// installation (in Drupal this looks like http://[SITEROOT]/sites/all/modules/civicrm/bin/cron.php?.
// File > Save your script
var BASE_URL = "https://www.fubar.org/sites/all/modules/civicrm/bin/cron.php?";
// To get this script to run automatically open Resources > Current project triggers
// and slect doTasks to run as a day timer (we set reports to run between 7-8am)
// If you want to run earlier or later also adjust the RERUN_HOUR below which sets the next run time
var RERUN_HOUR = 1;
var PS = PropertiesService.getScriptProperties();
var param = PS.getProperties();
param.job = "mail_report";
// helper so we know which value is in which column
var COL = {report_id: 0,
type: 1,
last_run: 2,
next_run: 3,
format: 4,
ss_id: 5,
ss_sht: 6,
total: 7};
function onOpen(){
var ui = SpreadsheetApp.getUi();
ui.createMenu('CiviSchedule')
.addItem('Run Script', 'doTasks')
.addToUi();
}
function doTasks() {
var doc = SpreadsheetApp.getActiveSpreadsheet(); // get spreadsheet
var sheet = doc.getSheetByName("Tasks"); // get sheet
var data = sheet.getRange(3, 1, sheet.getLastRow(), COL.total).getValues(); // get values
var now = new Date(); // time now
// for each row of the sheet interate accross
for (var i = 0; i < data.length; i++){
if (data[i][COL.report_id] != ""){ // if there is instance id do something
// collect row values
var report_id = data[i][COL.report_id]
var type = data[i][COL.type];
var next_run = data[i][COL.next_run] || 0;
// check if it's time to run the report again
if (next_run < now && type != "never"){
// if it is ping the report trigger
var new_next_run = callUrl(report_id, type, {format: data[i][COL.format], ss_id: data[i][COL.ss_id], ss_sht: data[i][COL.ss_sht]} );
// ..and record when to run again
sheet.getRange(parseInt(i)+3, 3, 1, 2).setValues([[now, new_next_run]]);
}
}
}
}
function callUrl(report_id, type, optParam){
// build the url to trigger the report
param.format = optParam.format || "print";
if (optParam.ss_id && optParam.ss_sht){
// if we have a sheet name and id force csv
param.format = 'csv';
// make a search string to find our report
optParam.search_str = 'report/instance/'+report_id+'?reset=1 has:attachment is:unread';
// store our search for later
PS.setProperty('search_str_'+report_id, JSON.stringify(optParam));
// set the script to read the email run 15min later
ScriptApp.newTrigger("processInbox")
.timeBased()
.after(1 * 60 * 1000)
.create();
}
// make url
var qs = BASE_URL
for(var key in param) {
if (key.substring(0, 10) != "search_str"){
var value = param[key];
qs += key + "=" + value + "&";
}
}
qs += "instanceId="+report_id;
try {
//gg var resp = UrlFetchApp.fetch(qs); // hit the url
// now calculate when to run again
var d = new Date();
d.setHours(RERUN_HOUR);
d.setMinutes(0);
switch (type){
case "daily":
d.setDate(d.getDate() + 1);
break;
case "weekly":
d.setDate(d.getDate() + 7);
break;
case "monthly":
// Get the first Monday in the month
d.setDate(1);
d.setMonth(d.getMonth() + 1);
while (d.getDay() !== 1) {
d.setDate(d.getDate() + 1);
}
break;
}
return d;
} catch(e) {
return e.message;
}
}
function processInbox(){
var PS = PropertiesService.getScriptProperties();
var data = PS.getProperties();
for (var key in data) {
try { if (key.substring(0, 10) == "search_str"){
var param_raw = data[key];
var param = JSON.parse(param_raw);
// get last 20 message threads using serach term
var threads = GmailApp.search(param.search_str, 0, 20);
// assume last thread has our latest data
var last_thread = threads.length-1;
if (last_thread > -1){
// get message in the last thread
var msg = threads[last_thread].getMessages()[0];
// get the attachments
var attachments = msg.getAttachments();
for (var k = 0; k < attachments.length; k++) {
// get the attachment as a string
var csv_str = attachments[k].getDataAsString();
// parse string as csv
var csv = Utilities.parseCsv(csv_str);
// create destination object
var doc = SpreadsheetApp.openById(param.ss_id);
var sheet = doc.getSheetByName(param.ss_sht);
// clear any old data
sheet.clear();
// write new data
sheet.getRange(1, 1, csv.length, csv[0].length).setValues(csv);
// mark message are read and archive (you could also label or delete)
threads[last_thread].moveToArchive().markRead();
PS.deleteProperty(key);
}
}
}
} catch(e) {
SpreadsheetApp.getUi().alert('problem: ${e}');
}
}
}
at processInbox(processInbox Code:46:18)
The syntax is
at ${FUNCTION}(${FILE}:${LINE}:${COLUMN})
This would suggest that the code causing the error is elsewhere.
At file
processInbox Code
within function
processInbox
And at line
46
and at column
18
You probably have a same function name processInbox at a different file named processInbox Code. In that file, at line 46, col 18, you'll have your error.
I think that you problem may be that this line:
var data = sheet.getRange(3, 1, sheet.getLastRow(), COL.total).getValues();
should be like this:
var data = sheet.getRange(3, 1, sheet.getLastRow() - 2, COL.total).getValues();
So im using local notifications to send a daily notification to the user, once the notifcation is added i add an id in the userInfo - NSDictionary. The user can remove the medication at any time which will cancel the notification which is why i add the id into the NSDictionary.
var notification = new UILocalNotification();
Random rnd = new Random();
string stringid = rnd.Next(1, 1000000000).ToString();
notification.AlertBody = usermedid + "Please take " + dosage + " of " + medname;
stringid = notification.AlertBody;
App.BadgeCount = App.BadgeCount + 1;
notification.ApplicationIconBadgeNumber = App.BadgeCount;
notification.FireDate = NSDate.FromTimeIntervalSinceNow(60);
notification.RepeatInterval = NSCalendarUnit.Minute;
var userInfo = NSDictionary.FromObjectAndKey(new NSString("UsermeddosageID"),new NSString(usermeddosagetimeid));
notification.UserInfo = userInfo;
UIApplication.SharedApplication.ScheduleLocalNotification(notification);
The code is inserting the id into the NSDictionary but for some reason it wont read it in my IF Statement. Can anybody explain why my code isnt working ?? Any help appreciated..
var array = UIApplication.SharedApplication.ScheduledLocalNotifications;
foreach (var item in array)
{
var userinfo = item.UserInfo;
if (!userinfo.ContainsKey(new NSString(usermeddosagetimeid)))
{
UIApplication.SharedApplication.CancelLocalNotification(item);
}
}
If I understand right, if you want to cancel the notification which contains the key usermeddosagetimeid, the if Statement should be:
if (userinfo.ContainsKey(new NSString(usermeddosagetimeid)))
{
UIApplication.SharedApplication.CancelLocalNotification(item);
}
Instead of !userinfo.ContainsKey(new NSString(usermeddosagetimeid))
BTW, scheduledlocalnotifications is Deprecated since iOS 10, you can use the UNUserNotificationCenter class to schedule local notifications instead.
My program creates a "Deck" of cards in a List, I want to be able to get the image, find the path to parse it to get the information that is in the image name.
For this, I am using an ArrayList to store the cards.
List<Image> mainDeck = new ArrayList<Image>();
To load the image, I am using this code
public List load(List<Image> newDeck) {
count = 0;
for (int i = 0; i < 4; i++) {
for (int k = 0; k < 10; k++) {
newDeck.add(new Image("images/" + prefix.get(i) + "" + (k + 1) + ".png"));
count++;
}// end number card for loop
for (int l = 0; l < 3; l++) {
newDeck.add(new Image("images/" + prefix.get(l) + "" + prefixFace.get(l) + ".png"));
count++;
}// end face card for loop
}// end deck for loop
it then gets called and populated with images that work perfectly, I would like to create a matching array filled with Strings that hold the path for the matching Image array.
The names of images are "c1.png", "c2.png", etc, and I just need the number in the pathname
Once I get the array I should be able to parse the data to get the numbers.
Any help would be much appreciated.
when using get url, I am getting an error, here is that code
for (Image card : mainDeck){
String path = card.getUrl();
String name = path.substring(path.lastIndexOf("/")+1, path.lastIndexOf("."));
nameData.put(card, name);
it is not recognizing card.getUrl();
you don't have to create another arrayList for the paths cause the path data is already saved with the images.
if you want to retrieve the path of an image after creating it then you might use the method getUrl() in the Image class, calling getUrl() from an Image object will return the path that you used to create the image when you called the constructor, note that it will only work if you called the Image constructor using a String as the path for the image, it will not work if you used an inputStream to initialize your image, and also that it was defined in java 9, after getting the path you might split it to get the useful data you want, something like
Image image = new Image("file:/C:/Users/zinou/Desktop/edit.png");
String path = image.getUrl();
String name = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
System.out.println(name);
and if i were to associate every card with its path, i would use a hashMap as in
List<Image> mainDeck = new ArrayList<Image>();
//population of the list
HashMap<Image, String> nameData = new HashMap<Image, String>();
for (Image card : mainDeck) {
String path = card.getUrl();
String name = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
nameData.put(card, name);
}
If you have java 8
you can create a class that extends the Image class and give it an additional attribute (the URL), and add a getter for the URL so you can access it, but then your cards will be instances of the new class you created, so you can get the URL for them, the new class may look like this
public class MyImage extends javafx.scene.image.Image{
String url;
public MyImage(String arg0) {
super(arg0);
url = arg0;
}
public String geturl() {
return url;
}
}
Please consider the following records
I'm trying to flatten and group the data by Robot Name then by date + Left Factory time then group the address(es) for that date and time. Notice that some of the Left Factory times are identical.
I wrote the code below and it works. It gives me the output that I want. I was a Perl developer so what you see below is from that mentality. I'm sure there is a better way of doing it in LINQ. A little help please.
static void Main(string[] args)
{
if (args.Length < 0){
Console.WriteLine("Input file name is required");
return;
}
List<string> rawlst = File.ReadAllLines(args[0]).ToList<string>();
Dictionary<string, Dictionary<DateTime, List<string>>> dicDriver = new Dictionary<string, Dictionary<DateTime, List<string>>>();
foreach (string ln in rawlst)
{
try
{
List<string> parts = new List<string>();
parts = ln.Split(',').ToList<string>();
string[] dtparts = parts[1].Split('/');
string[] dttime = parts[15].Split(':');
DateTime dtrow = new DateTime(
int.Parse(dtparts[2]), int.Parse(dtparts[0]), int.Parse(dtparts[1]),
int.Parse(dttime[0]), int.Parse(dttime[1]), int.Parse(dttime[2]));
string rowAddress = parts[7] + " " + parts[9] + " " + parts[10] + " " + parts[11];
if (!dicDriver.Keys.Contains(parts[3]))
{
Dictionary<DateTime, List<string>> thisRec = new Dictionary<DateTime, List<string>>();
thisRec.Add(dtrow, new List<string>() { rowAddress });
dicDriver.Add(parts[3], thisRec);
}
else
{
Dictionary<DateTime, List<string>> thisDriver = new Dictionary<DateTime, List<string>>();
thisDriver = dicDriver[parts[3]];
if (!thisDriver.Keys.Contains(dtrow))
{
dicDriver[parts[3]].Add(dtrow, new List<string>() { rowAddress });
}
else
{
dicDriver[parts[3]][dtrow].Add(rowAddress);
}
}
}
catch (Exception e)
{
Console.WriteLine("ERROR:" + ln);
}
}
//output
string filename = DateTime.Now.Ticks.ToString() + ".out";
foreach (var name in dicDriver.Keys)
{
foreach (var dd in dicDriver[name])
{
Console.Write(name + "," + dd.Key + ",");
File.AppendAllText(filename, name + "," + dd.Key + Environment.NewLine);
foreach (var addr in dd.Value)
{
Console.Write("\t\t" + addr + Environment.NewLine);
File.AppendAllText(filename, "\t" + addr + Environment.NewLine);
}
}
Console.Write(Environment.NewLine);
File.AppendAllText(filename, Environment.NewLine);
}
Console.ReadLine();
}
You should separate your concerns: separate your input from the processing and from the output.
For example: suppose you would have to read your input from a database instead from a CSV file? Would that seriously change the way your process your fetched data? In your design, fetching the data is mixed with processing: although you know that the data that you want to process contains something like FactoryProcesses, you decide to present eache FactoryProcess as a string. A FactoryProcess is not a string. It describes how and when and who processed something in your factory. That is not a string, is it? However, it might be represented internally as a string, but the outside world should not know this. This way, if you change your FactoryProcess from being read by a CSV-file, to something provided by a database, the users of your FactoryProcess won't see any difference.
Separation of concerns makes your code easier to understand, easier to test, easier to change, and better to re-use.
So let's separate!
IEnumerable<FactoryProcess> ReadFactoryProcesses(string fileName)
{
// TODO: check fileName not null, file exists
using (var fileReader = new StreamReader(fileName))
{
// read the file Line by Line and split each line into one FactoryProcess object
string line = fileReader.ReadLine();
while (line != null)
{
// one line read, convert to FactoryProcess and yield return:
FactoryProcess factoryProcess = this.ToFactoryProcess(line);
yield return factoryProcess;
// read next line:
line = fileReader.ReadLine();
}
}
}
I'll leave the conversion of a read line into a FactoryProcess up to you. Tip: if the items in your lines are separated by a comma, or something similar, consider using Nuget Package CSVHelper. It makes if easier to convert a file into a sequence of FactoryProcesses.
I want to group the data by Robot Name then by date + Left Factory time then group the address(es) for that date and time.
First of all: make sure that the FactoryProcess class has the properties you actually need. Separate this representation from what it is in a file. Apparently you want to tread date + left factory as one item that represents the Date and Time that it left the factory. So Let's create a DateTime property for this.
class FactoryProcess
{
public int Id {get; set}
public int PartNo {get; set;}
public string RobotName {get; set;} // or if desired: use a unique RobotId
...
// DateTimes: ArrivalTime, OutOfFactoryTime, LeftFactoryTime
public DateTime ArrivalTime {get; set;}
public DateTime OutOfFactoryTime {get; set;}
public DateTime LeftFactoryTime {get; set;}
}
The reason that I put Date and Time into one DateTime, is because it will solve problems if an item arrives on 23:55 and leaves on 00:05 next day.
A procedure that converts a read CSV-line to a FactoryProcess should interpret your dates and times as strings and convert to FactoryProcess. You can create a constrcuctor for this, or a special Factory class
public FactoryProcess InterpretReadLine(string line)
{
// TODO: separate the parts, such that you've got the strings dateTxt, arrivalTimeTxt, ...
DateTime date = DateTime.Parse(dateTxt);
TimeSpan arrivalTime = TimeSpan.Parse(arrivalTimeTxt);
TimeSpan outOfFactoryTime = TimeSpan.Parse(outOfFactoryTimeTxt);
TimeSpan leftFactoryTime = TimeSpan.Parse(leftFactoryTimeTxt);
return new FactoryProces
{
Id = ...
PartNo = ..
RobotName = ...
// The DateTimes:
ArrivalTime = date + arrivalTime,
OutOfFactoryTime = date + outOfFactoryTime,
LeftFactoryTime = date + leftFactoryTime,
};
}
Now that you've created a proper method to convert your CSV-file into a sequence of FactoryProcesses, let's process them
I want to group the data by Robot Name then by date + Left Factory time then group the address(es) for that date and time.
var result = fetchedFactoryProcesses.GroupBy(
// parameter KeySelector: make groups of FactoryProcesses with same RobotName:
factoryProcess => factoryProcess.RobotName,
// parameter ResultSelector: from every group of FactoryProcesses with this RobotName
// make one new Object:
(robotName, processesWithThisRobotName) => new
{
RobotName = robotName,
// Group all processes with this RobotName into groups with same LeftFactoryTime:
LeftFactory = processesWithThisRobotName.GroupBy(
// KeySelector: make groups with same LeftFactoryTime
process => process.LeftFactoryTime,
// ResultSelector: from each group of factory processes with the same LeftFactoryTime
(leftFactoryTime, processesWithThisLeftFactoryTime) => new
{
LeftFactoryTime = leftFactoryTime,
FactoryProcesses = processesWithThisLeftFactoryTime,
// or even better: select only the properties you actually plan to use
FactoryProcesses = processesWithThisLeftFactoryTime.Select(process => new
{
Id = process.Id,
PartNo = process.PartNo,
...
// not needed: you know the value, because it is in this group
// RobotName = process.RobotName,
// LeftFactoryTime = process.LeftFactoryTime,
}),
})
});
For completeness: grouping your code together:
void ProcessData(string fileName)
{
var fetchedFactoryProcesses = ReadFactoryProcess(fileName); // fetch the data
var groups = fetchFactoryProcesses.ToGroups(); // put into groups
this.Display(groups); // output result;
}
Because I separated the input from the conversion of strings to FactoryProcesses, and separated this conversion from the grouping, it will be easy to test the classes separately:
your CSV-reader should return any file that is divided into lines, even if it does not contain FactoryProcesses
your conversion from read line to FactoryProcess should convert any string that is in the proper format, whether it is read from a file or gathered any other way
your grouping should group any sequence of FactoryProcesses, whether they come from a CSV-file or from a database or List<FactoryProcess>, which is very convenient, because in your tests it is way easier to create a test list, than a test CSV-file.
If in future you decide to change the source of your sequence of FactoryProcesses, for instance it comes from a database instead of a CSV-file, your grouping won't change. Or if you decide to support entering and leaving factories on different dates (multiple date values) only the conversion changes. If you decide to display the results in a tree-like fashion, or decide to write the groups in a database, your reading, conversion, grouping, etc won't change: what a high degree or re-usability!
Separating your concerns made it much easier to understand how to solve your grouping problem, without the hassle of splitting your read lines and converting Date + LeftFactory into one value.
I'm looking at the Microsoft-provided sample "Process Tasks as they Finish" and adapting that TPL sample for Azure Storage.
The problem I have is marked below where the variable domainData reports the errors in the compiler: Unknown method Select(?) of TableQuerySegment<DynamicTableEntity> (fully qualified namespace removed)
I also get the following error DynamicTableEntity domainData \n\r Unknown type of variable domainData
/// if you have the necessary references the following most likely should compile and give you same error
CloudStorageAccount acct = CloudStorageAccount.DevelopmentStorageAccount;
CloudTableClient client = acct.CreateCloudTableClient();
CloudTable tableSymmetricKeys = client.GetTableReference("SymmetricKeys5");
TableContinuationToken token = new TableContinuationToken() { };
TableRequestOptions opt = new TableRequestOptions() { };
OperationContext ctx = new OperationContext() { ClientRequestID = "ID" };
CancellationToken cancelToken = new CancellationToken();
List<Task> taskList = new List<Task>();
var task2 = tableSymmetricKeys.CreateIfNotExistsAsync(cancelToken);
task2.Wait(cancelToken);
int depth = 3;
while (true)
{
Task<TableQuerySegment<DynamicTableEntity>> task3 = tableSymmetricKeys.ExecuteQuerySegmentedAsync(query, token, opt, ctx, cancelToken);
// Run the method
task3.Wait();
Console.WriteLine("Records retrieved in this attempt = " + task3.Result.Count());// + " | Total records retrieved = " + state.TotalEntitiesRetrieved);
// HELP! This is where I'm doing something the compiler doesn't like
//
IEnumerable<Task<int>> getTrustDataQuery =
from domainData in task3.Result select QueryPartnerForData(domainData, "yea, search for this.", client, cancelToken);
// Prepare for next iteration or quit
if (token == null)
{
break;
}
else
{
token = task3.Result.ContinuationToken;
// todo: persist token token.WriteXml()
}
}
//....
private static object QueryPartnerForData(DynamicTableEntity domainData, string p, CloudTableClient client, CancellationToken cancelToken)
{
throw new NotImplementedException();
}
Your code is missing a query. In order to test the code I created the following query:
TableQuery<DynamicTableEntity> query = new TableQuery<DynamicTableEntity>()
.Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "temp"));
I also added the method QueryPartnerForData which doesn't do anything (simply returns null) and everything works fine. So maybe it's an issue with the QueryPartnerForData method? The best way to find the actual error is by setting a breakpoint here and there.
A StackOverflowException often means you are stuck in an endless loop. Run through the breakpoints a few times and see where your code is stuck. Could it be that QueryPartnerForData calls the other method and that the other method calls QueryPartnerForData again?