my application uses two SwingWorkers, one works in the Homepage to control online users and one works on opening a chat to keep the chat updated.
My problem is that the moment I open the chat (the SwingWorker of the chat starts to work) the SwingWorker of the Homepage no longer works, it is as if it went to standby.
For this reason I tried to "wake up" the thread, but unfortunately I came across the exception that is precisely the title of this article / question.
can any of you help me understand what the problem is?
why is the chat thread blocking the homepage thread?
below you will find the source code (unmodified)
thank you so much in advance for your help!
HOMEPAGE:
private class SWOnlineUserCheck extends SwingWorker<Void, Void>{
#Override
protected Void doInBackground() throws Exception {
while(running){
sleep(3000);
sql = "SELECT USRID,ONLINE FROM USR ORDER BY USRID ASC";
res = db_conn.select(sql);
chatItem = MLP_CHATLIST.getComponents();
while(res.next()){
for(int i=0; i<chatItem.length; i++){
chatItemListStat = (ChatItemList) chatItem[i];
if(chatItemListStat.getUserId() == res.getInt("USRID")){
sql = "SELECT DESCRIPTION FROM KWS WHERE KEYFIELD = 'ONLINESTATUS' AND KEYWORD = '"+res.getString("ONLINE")+"'";
res2 = db_conn.select(sql);
if(res2.next()){
chatItemListStat.ML_STATUS.setText(res2.getString("DESCRIPTION"));
}
if("J".equals(res.getString("ONLINE"))){
chatItemListStat.ML_IMGSTATUS.setIcon(new javax.swing.ImageIcon(getClass().getResource("/OBMS_icons/icons8-green-circle-18.png")));
}
else if("P".equals(res.getString("ONLINE"))){
chatItemListStat.ML_IMGSTATUS.setIcon(new javax.swing.ImageIcon(getClass().getResource("/OBMS_icons/icons8-orange-circle-18.png")));
}
else{
chatItemListStat.ML_IMGSTATUS.setIcon(new javax.swing.ImageIcon(getClass().getResource("/OBMS_icons/icons8-red-circle-18.png")));
}
}
}
}
}
return null;
}
#Override
protected void done(){
}
}
hier i try to wake up the thread of the Homepage:
private void MC_STATUSItemStateChanged(java.awt.event.ItemEvent evt) {
synchronized(this) {
if(running && swonlineusercheck.isDone()){
swonlineusercheck.notify();
}
}
for(var entry:map_status.entrySet()){
if(entry.getValue().equals(MC_STATUS.getItemAt(MC_STATUS.getSelectedIndex()))){
mc_status = entry.getKey();
break;
}
}
sql = "UPDATE USR SET ONLINE = '"+mc_status+"' WHERE USRID = '"+user.getUserId()+"'";
try{
db_conn.update(sql);
}
catch(SQLException ex){
Logger.getLogger(OBMS_HOMEPAGE.class.getName()).log(Level.SEVERE, null, ex);
}
if("J".equals(mc_status)){
ML_STATIMG.setIcon(new javax.swing.ImageIcon(getClass().getResource("/OBMS_icons/icons8-green-circle-18.png")));
}
else if("P".equals(mc_status)){
ML_STATIMG.setIcon(new javax.swing.ImageIcon(getClass().getResource("/OBMS_icons/icons8-orange-circle-18.png")));
}
else{
ML_STATIMG.setIcon(new javax.swing.ImageIcon(getClass().getResource("/OBMS_icons/icons8-red-circle-18.png")));
}
}
CHAT_WINDOW:
private class SWCHAT_WINDOWCheck extends SwingWorker<Void, Void>{
#Override
protected Void doInBackground() throws Exception {
while(running){
if(firstChatQuery){
sql="SELECT * FROM CHT WHERE SENDER IN ('"+chat_sender.getUserId()+"','"+chat_partner.getUserId()+"') "
+ "AND RECEIVER IN ('"+chat_sender.getUserId()+"','"+chat_partner.getUserId()+"') "
+ "AND CAST(DATE AS DATE) = CURRENT_DATE() "
+ "AND CAST(DATE AS TIME) > '"+chatTime+"' ORDER BY DATE ASC";
res = db_conn.select(sql);
}
else{
sql="SELECT * FROM CHT WHERE SENDER IN ('"+chat_sender.getUserId()+"','"+chat_partner.getUserId()+"') "
+ "AND RECEIVER IN ('"+chat_sender.getUserId()+"','"+chat_partner.getUserId()+"') "
+ "AND CHTID > "+lastChatId+" ORDER BY DATE DESC LIMIT 1";
res = db_conn.select(sql);
}
fillChat(res);
}
return null;
}
#Override
protected void done(){
}
}
hier i try to wake up the thread of the Chat window:
private void ChatWrite() throws SQLException{
synchronized(this) {
if(swchatwindowcheck.isDone()){
swchatwindowcheck.notify();
}
}
usrid_sender = chat_sender.getUserId();
usrid_receiver = chat_partner.getUserId();
usrid_writer = usrid_sender;
sql = "INSERT INTO CHT (CHTID,CHGID,SENDER,RECEIVER,WRITER,DATE,TEXT,IMG_VID) "
+"VALUES (NULL,NULL,'"+usrid_sender+"','"+usrid_receiver+"','"+usrid_writer+"'"
+",CURRENT_TIMESTAMP(),'"+MTA_CHATTEXT.getText()+"','')";
db_conn.update(sql);
MTA_CHATTEXT.setText("");
MTA_CHATTEXT.requestFocus();
}
Related
I have a very curious Error that I cant seem to get my head around.
I need to use a ScheduledExecutorService to pass the Survey Entity I created to be edited and then saved as a new Entity.
public void executeScheduled(Survey eventObject, long interval) {
HashMap<String, String> eventRRules = StringUtils.extractSerialDetails(eventObject.getvCalendarRRule());
long delay = 10000;
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
Runnable runnable = new Runnable() {
private int counter = 1;
private int executions = Integer.parseInt(eventRRules.get("COUNT"));
Survey survey = eventObject;
public void run() {
String uid = eventObject.getUniqueEventId();
logger.info("SurveyController - executeScheduled - Iteration: " + counter);
String serialUid = null;
if (counter == 1) {
serialUid = uid + "-" + counter;
} else {
serialUid = StringUtils.removeLastAndConcatVar(eventObject.getUniqueEventId(), Integer.toString(counter));
}
if (++counter > executions) {
service.shutdown();
}
survey.setUniqueEventId(serialUid);
try {
executeCreateSurvey(survey);
} catch(Exception e) {
logger.debug("SurveyController - executeScheduled - Exception caught: ");
e.printStackTrace();
}
}
};
service.scheduleAtFixedRate(runnable, delay, interval, TimeUnit.MILLISECONDS);
}
When the executeCreateSurvey(survey) Method is run without the ScheduleExecutorService, it works flawlessly.
Yet when it is executed inside the run() Method, I get the "detached entity passed to persist" Error each time the save(survey) Method is run within the executeCreateSurvey() Method....
The executeCreateSurvey() Method where the .save() Method is called:
public ResponseEntity<?> executeCreateSurvey(Survey eventObject) {
MailService mailService = new MailService(applicationProperties);
Participant eventOwner = participantRepositoryImpl.createOrFindParticipant(eventObject.getEventOwner());
eventObject.setEventOwner(eventOwner);
Survey survey = surveyRepositoryImpl.createSurveyOrFindSurvey((Survey) eventObject);
// Saves additional information if small errors (content
// errors,.. )
// occurs
String warnMessage = "";
List<Participant> participants = new ArrayList<Participant>();
for (Participant participantDetached : eventObject.getParticipants()) {
// Check if participant already exists
Participant participant = participantRepositoryImpl.createOrFindParticipant(participantDetached);
participants.add(participant);
// Only create PartSur if not existing (Update case)
if (partSurRepository.findAllByParticipantAndSurvey(participant, survey).isEmpty()) {
PartSur partSur = new PartSur(participant, survey);
partSurRepository.save(partSur);
try {
mailService.sendRatingInvitationEmail(partSur);
surveyRepository.save(survey);
} catch (Exception e) {
// no special exception for "security" reasons
String errorMessage = "error sending mail for participant: " + e.getMessage() + "\n";
warnMessage += errorMessage;
logger.warn("createSurvey() - " + errorMessage);
}
}
}
// Delete all PartSurs and Answers from removed participants
List<PartSur> partSursForParticipantsRemoved = partSurRepository.findAllByParticipantNotIn(participants);
logger.warn("createSurvey() - participants removed: " + partSursForParticipantsRemoved.size());
partSurRepositoryImpl.invalidatePartSurs(partSursForParticipantsRemoved);
return new ResponseEntity<>("Umfrage wurde angelegt. Warnungen: " + warnMessage, HttpStatus.OK);
}
What could the reason be for this?
I have not been able to find this Problem anywhere so far.
Fairly new to Android/Java development and using the Open Source Parseplatform as my backend server. I've created a class to manage a parse object and this object update's its data from an async call to the parse server as per this code.
public class DeviceObject {
private String objectID, deviceName, status;
private ParseGeoPoint location;
int batLevel;
public DeviceObject(){
objectID = null;
deviceName = null;
location = null;
batLevel = 0;
status = null;
}
public void getDeviceLatestData() {
if (objectID != null) {
ParseQuery<ParseObject> query = ParseQuery.getQuery("DeviceData");
query.whereEqualTo("DeviceObjectID", objectID);
query.orderByDescending("createdAt");
query.setLimit(1);
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> ParseDeviceList, ParseException e) {
if (e == null) {
if (ParseDeviceList.size() == 0) {
Log.d("debg", "Device not found");
} else {
for (ParseObject ParseDevice : ParseDeviceList) {
status = ParseDevice.getString("Status");
batLevel = ParseDevice.getInt("BatteryLevel");
location = ParseDevice.getParseGeoPoint("Location");
Log.d("debg", "Retrieving: " + deviceName);
Log.d("debg", "Status: " + status + " Battery: " + Integer.toString(batLevel));
}
//callback listener to add marker to map
}
} else {
Log.d("debg", "Error: " + e.getMessage());
}
}
});
}
}
So I create my class object in my Main Activity with the following:
DeviceObject userDevice = new DeviceObject();
userDevice.getDeviceLatestData();
What I can't get my head around is how in my MainActivity I can get notified/callback to continue displaying the information which the userDevice class just got off the parse Server.
I've tried creating an interface and adding a listener as what i've seen suggested however I could not add the listener inside the parse's done function.
The definition of my main activity is, note I need the OnMapReadyCallback as i'm using Google Maps
public class MapMainActivity extends AppCompatActivity implements OnMapReadyCallback {
So in summary i'd like to add something to the main activity so that I can process the data when it has been added to the class from the async call.
For something like this, I recommend using an event bus. Here is a link to a popular one I've had success with in the past.
Basically, you will have another class involved, which will be your bus. Your activity will register for a specific event (which you will create, subclassing as appropriate). Your async call will tell the event bus to fire off that event, and the bus will then tell all subscribers, including your main activity, that the event fired off. That is when you'd call getDeviceLatestData. Below are simple code snippets you may use, but read the documentation on that bus to fully understand it.
Your event:
public static class DataReady Event { /* optional properties */ }
Your DeviceObject:
public class DeviceObject {
private String objectID, deviceName, status;
private ParseGeoPoint location;
int batLevel;
public DeviceObject(){
objectID = null;
deviceName = null;
location = null;
batLevel = 0;
status = null;
}
public void getDeviceLatestData() {
if (objectID != null) {
ParseQuery<ParseObject> query = ParseQuery.getQuery("DeviceData");
query.whereEqualTo("DeviceObjectID", objectID);
query.orderByDescending("createdAt");
query.setLimit(1);
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> ParseDeviceList, ParseException e) {
if (e == null) {
if (ParseDeviceList.size() == 0) {
Log.d("debg", "Device not found");
} else {
for (ParseObject ParseDevice : ParseDeviceList) {
status = ParseDevice.getString("Status");
batLevel = ParseDevice.getInt("BatteryLevel");
location = ParseDevice.getParseGeoPoint("Location");
Log.d("debg", "Retrieving: " + deviceName);
Log.d("debg", "Status: " + status + " Battery: " + Integer.toString(batLevel));
}
//callback listener to add marker to map
EventBus.getDefault().post(new DataReadyEvent());
}
} else {
Log.d("debg", "Error: " + e.getMessage());
}
}
});
}
}
Your MainActivity:
public class MainActivity {
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
#Subscribe(threadMode = ThreadMode.MAIN) // Seems like you're updating UI, so use the main thread
public void onDataReady(DataReadyEvent event) {
/* Do whatever it is you need to do - remember you can add properties to your event and pull them off here if you need to*/
};
}
I'm trying to create a program for an API to place multiple trades at once, and then get prices for the stocks, and then rebalance every so often. I used a tutorial from online to get some of this code, and made a few tweaks.
However, when I run the code, it often connects and will place an order if I restart IB TWS. But if I go to run the code again it does not work, or show any indication that it will connect. Can anyone help me figure out how to keep the connection going, so that I can run the main.java file, and it will execute multiple trades and then end the connection? Do I need to change the client id number in either the code, or the settings of TWS?
There are three files:
Ordermanagement.java:
package SendMarketOrder;
//import statements//
class OrderManagement extends Thread implements EWrapper{
private EClientSocket client = null; //IB API client Socket Object
private Stock stock = new Stock();
private Order order = new Order();
private int orderId;
private double limitprice;
private String Ticker;
//method to create connection class. It's the constructor
public OrderManagement() throws InterruptedException, ClassNotFoundException, SQLException {
// Create a new EClientSocket object
System.out.println("////////////// Creating a Connection ////////////");
client = new EClientSocket(this); //Creation of a socket to connect
//connect to the TWS Demo
client.eConnect(null,7497,1);
try {
Thread.sleep(3000); //waits 3 seconds for user to accept
while (!(client.isConnected()));
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("///////// Connected /////////");
}
public void sendMarketOrder(String cusip, String buyorSell, int shares) throws SQLException, ClassNotFoundException{
//New Order ID
orderId++;
order.m_action = buyorSell;
order.m_orderId = orderId;
order.m_orderType = "MKT";
order.m_totalQuantity = shares;
order.m_account = "DU33xxxxx"; //write own account
order.m_clientId = 1;
//Create a new contract
stock.createContract(cusip);
client.placeOrder(orderId, stock.contract, order);
//Show order in console
SimpleDateFormat time_formatter = new SimpleDateFormat("HH:mm:ss");
String current_time_str = time_formatter.format(System.currentTimeMillis());
System.out.println("////////////////////////////////////////////////\n" +
"#Limit Price: " + order.m_lmtPrice + "///////////////////////////\n" +
"#Client number: " + order.m_clientId + "///////////////////////////\n" +
"#OrderType: " + order.m_orderType + "///////////////////////////\n" +
"#Order Quantity: " + order.m_totalQuantity + "///////////////////////////\n" +
"#Account number: " + order.m_account + "///////////////////////////\n" +
"#Symbol: " + stock.contract.m_secId + "///////////////////////////\n" +
"///////////////////////////////////////"
);
}
Stock.java
public class Stock{
private int StockId; //we can identify the stock
private String Symbol; //Ticker
public Stock() { //default constructor
}
public Stock(int StockId, String Symbol) { //constructor
this.StockId = StockId;
this.Symbol = Symbol;
}
//getter and setters
public int getStockId() {
return StockId;
}
public String getSymbol() {
return Symbol;
}
Contract contract = new Contract ();
public void createContract(String cusip){
contract.m_secId = cusip;
contract.m_secIdType = "CUSIP";
contract.m_exchange = "SMART";
contract.m_secType = "STK";
contract.m_currency = "USD";
}
}
Main.java:
package SendMarketOrder;
import java.sql.SQLException;
public class Main {
public static void main(String[] args) throws InterruptedException, ClassNotFoundException, SQLException {
OrderManagement order = new OrderManagement();
order.sendMarketOrder("922908363","BUY", 100);
order.sendMarketOrder("92204A504","BUY", 50);
order.sendMarketOrder("92204A702","BUY", 100);
System.exit(0);
}
}
These are my current settings TWS settings if that helps:
Thanks in advance for the help!
I changed a few things around in the code and added comments.
package sendmarketorder;//usually lower case pkg names
public class Main {
//you throw a bunch of exceptions that are never encountered
public static void main(String[] args) {
//since there's a Thread.sleep in this class
//it will block until ready
OrderManagement order = new OrderManagement();
//obviously you need some logic to buy/sell
//you can use command line args here if you want
order.sendMarketOrder("922908363", "BUY", 100);
order.sendMarketOrder("92204A504", "BUY", 50);
order.sendMarketOrder("92204A702", "BUY", 100);
//the socket creates a reader thread so this will stop it.
//if you didn't have this line the non-daemon thread would keep a
//connection to TWS and that's why you couldn't reconnect
//System.exit(0);//use better exit logic
}
}
.
package sendmarketorder;
import com.ib.client.*;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
//doesn't extend thread and if you implement EWrapper you have to implement all methods
//in API 9.72 you can extend DefaultWrapper and just override the methods you need
public class OrderManagement implements EWrapper{
private EClientSocket client = null; //IB API client Socket Object
private int orderId = -1;//use as flag to send orders
//private double limitprice;
//private String Ticker;
//keep track of all working orders
private Map<Integer, Order> workingOrders = new HashMap<>();
//method to create connection class. It's the constructor
public OrderManagement(){
// Create a new EClientSocket object
System.out.println("////////////// Creating a Connection ////////////");
client = new EClientSocket(this); //Creation of a socket to connect
//connect to the TWS Demo
client.eConnect(null, 7497, 123);//starts reader thread
try {
while (orderId < 0){ //not best practice but it works
System.out.println("waiting for orderId");
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("///////// Connected /////////");
}
public void sendMarketOrder(String cusip, String buyorSell, int shares) {
//make new stock and order for each stock
Stock stock = new Stock();
Order order = new Order();
//New Order ID, but get from API as you have to increment on every run for life
orderId++;
order.m_action = buyorSell;
order.m_orderId = orderId;
order.m_orderType = "MKT";
order.m_totalQuantity = shares;
//I don't think you're supposed to use these fields
//order.m_account = "DU33xxxxx"; //write own account
//order.m_clientId = 1;
//Create a new contract
stock.createContract(cusip);
//remember which orders are working
workingOrders.put(orderId, order);
client.placeOrder(orderId, stock.contract, order);
//Show order in console
SimpleDateFormat time_formatter = new SimpleDateFormat("HH:mm:ss");
String current_time_str = time_formatter.format(System.currentTimeMillis());
System.out.println("////////////////////////////////////////////////\n"
+ "#Limit Price: " + order.m_lmtPrice + "///////////////////////////\n"
+ "#Client number: " + order.m_clientId + "///////////////////////////\n"
+ "#OrderType: " + order.m_orderType + "///////////////////////////\n"
+ "#Order Quantity: " + order.m_totalQuantity + "///////////////////////////\n"
+ "#Account number: " + order.m_account + "///////////////////////////\n"
+ "#Symbol: " + stock.contract.m_secId + "///////////////////////////\n"
+ "///////////////////////////////////////"
);
}
//always impl the error callback so you know what's happening
#Override
public void error(int id, int errorCode, String errorMsg) {
System.out.println(id + " " + errorCode + " " + errorMsg);
}
#Override
public void nextValidId(int orderId) {
System.out.println("next order id "+orderId);
this.orderId = orderId;
}
#Override
public void orderStatus(int orderId, String status, int filled, int remaining, double avgFillPrice, int permId, int parentId, double lastFillPrice, int clientId, String whyHeld) {
//so you know it's been filled
System.out.println(EWrapperMsgGenerator.orderStatus(orderId, status, filled, remaining, avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeld));
//completely filled when remaining == 0, or possible to cancel order from TWS
if (remaining == 0 || status.equals("Cancelled")){
//remove from map, should always be there
if (workingOrders.remove(orderId) == null) System.out.println("not my order!");
}
//if map is empty then exit program as all orders have been filled
if (workingOrders.isEmpty()){
System.out.println("all done");
client.eDisconnect();//will stop reader thread
//now is when you stop the program, but since all
//non-daemon threads have finished, the jvm will close.
//System.exit(0);
}
}
//impl rest of interface...
}
For some reason in the following function the Cursor is not reading any marks. I don't know what I am doing wrong and I have been debugging this code for ours. When it runs it says the value of tagid and catid are both -1. No ping pong or pang :(
public String getCategoryNameByLawId(final int lawID){
final String[] categoryName = {"Success"+lawID};
final int[] tagID = {-1};
final int[] categoryID = {-1};
runnable = new Runnable() {
#Override
public void run() {
try {
openToRead();
String Query = "SELECT * from " + Constants.TABLE_LAW_TAG;
Cursor c1 = mSqLiteDatabase.rawQuery(Query, null);
if (c1.moveToFirst()) {
categoryName[0] = "ping";
while (c1.isAfterLast() == false) {
categoryName[0] = "pong";
try {
if (c1.getInt(c1.getColumnIndex(Constants.KEY_LAW_ID)) == lawID) {
int indexTagID = c1.getColumnIndex(Constants.KEY_TAG_ID);
tagID[0] = c1.getInt(indexTagID);
categoryName[0] = "pang";
}
} catch (Exception e) {
categoryName[0] = e.getMessage();
}
c1.moveToNext();
}
}
close();
openToRead();
Query = "SELECT * from " + Constants.TABLE_CATEGORY_TAG;
Cursor c2 = mSqLiteDatabase.rawQuery(Query, null);
if (c2.moveToFirst()) {
while (c2.isAfterLast() == false) {
if (c2.getInt(c2.getColumnIndex(Constants.KEY_TAG_ID)) == tagID[0]) {
int indexCategoryID = c2.getColumnIndex(Constants.KEY_CATEGORY_ID);
categoryID[0] = c2.getInt(indexCategoryID);
}
c2.moveToNext();
}
}
/*
exceptionHandler.alert(new RuntimeException(), "catid-" + categoryID[0]);
Query = "SELECT * from " + Constants.TABLE_CATEGORY;
Cursor c3 = mSqLiteDatabase.rawQuery(Query, null);
if (c3.moveToFirst()) {
while (c3.isAfterLast() == false) {
if (c3.getInt(c3.getColumnIndex(Constants.KEY_CATEGORY_ID)) == categoryID[0]) {
int indexCategoryName = c3.getColumnIndex(Constants.KEY_CATEGORY_NAME);
categoryName[0] = c3.getString(indexCategoryName);
}
c3.moveToNext();
}
}
exceptionHandler.alert(new RuntimeException(), "catnam-" + categoryName[0]);*/
close();
}
catch(Exception e){
categoryName[0] ="error";
}
}
};
new Thread(runnable).start();
return categoryName[0].toLowerCase() + " tagid: "+ tagID[0]+ " catid: "+ categoryID[0];
}
start() just starts the thread; it does not wait for it to finish.
The problem is that the value has not yet been found when you're executing return categoryName[0]....
Drop the Runnable indirection, and execute the database code directly.
If you really want to use a thread, you could wait for the thread to finish (call its join()), but this would not make sense because your main thread would be suspended as long as the database code is running. To be able to do other stuff in the main thread, you would have to reorganize your program so that the database code sends a separate message back to the main thread when it has the result. Have it look into CursorLoader (which needs a content provider, though).
I'm trying to perform a batch operation in QuickBook but getting null callbackhandler.
private static void AddBulkCustomer(DataService ds) throws FMSException{
BatchOperation bo = new BatchOperation();
Customer c1 = new Customer();
c1.setGivenName("Customer 3");
c1.setDisplayName("Disp Customer 3");
EmailAddress email = new EmailAddress();
email.setAddress("customer1#zzz.com");
c1.setPrimaryEmailAddr(email);
bo.addEntity(c1, OperationEnum.CREATE, "b3");
c1= null;
c1 = new Customer();
c1.setGivenName("Customer 4");
c1.setDisplayName("Disp Customer 4");
email = null;
email = new EmailAddress();
email.setAddress("customer2#z2zz.com");
c1.setPrimaryEmailAddr(email);
bo.addEntity(c1, OperationEnum.CREATE, "b4");
// String strQuery = " select * from customer where givenname ='"+c1.getGivenName()+"'";
// bo.addQuery(strQuery, "b3Query");
ds.executeBatchAsync(bo, new AsyncCallBackBatch());
}
For AsyncCallback operation
public class AsyncCallBackBatch implements CallbackHandler {
#Override
public void execute(CallbackMessage callbackMsg) {
System.out.println("asyncCallbackBatch is executing... ");
try {
System.out.println("QR = "+callbackMsg.getFMSException().toString());
BatchOperation BO = callbackMsg.getBatchOperation();
if (BO != null) {
List<String> bId = BO.getBIds();
for (String strBId : bId) {
if (BO.isFault(strBId)) {
Fault fault = BO.getFault(strBId);
System.out.println("asyncCallBackBatch Error Code : "+ fault.getError().get(0).getCode() + " "+ "Error : "
+ fault.getError().get(0).getDetail()+ ", Message : "+ fault.getError().get(0).getMessage());
} else if (BO.isEntity(strBId)) {
System.out.println("Batch having entity message.. ");
Customer cust = (Customer) BO.getEntity(strBId);
System.out.println("cust id : " + cust.getId()+ " CustName = " + cust.getGivenName());
} else if (BO.isQuery(strBId)) {
System.out.println("Batch having Query ... Parsing... ");
QueryResult qR = BO.getQueryResponse(strBId);
System.out.println("Query : " + qR.getTotalCount());
} else if (BO.isReport(strBId)) {
System.out.println("Batch having Report... ");
Report report = BO.getReport(strBId);
System.out.println(" " + report.getClass().getName());
} else {
System.out.println("Something went wrong... ");
}
}
}else{
System.out.println("Batch Operation terminated, reason: NULL callbackMsg ");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
OAuthAuthorizer oAuth = new OAuthAuthorizer(consumerKey, consumerSecret, accessToken, accessTokenSecret);
//403352746
try {
Context context = new Context(oAuth, ServiceType.QBO, "403352746");
System.out.println("RealmID : "+context.getRealmID());
context.setCustomerRequestTimeout(99999);
System.out.println("TimeOut Set to = "+context.getCustomerRequestTimeout());
System.out.println("BASE_URL_QBO = "+Config.getProperty(Config.BASE_URL_QBO));
Config.setProperty(Config.BASE_URL_QBO, "https://sandbox-quickbooks.api.intuit.com/v3/company");
System.out.println("BASE_URL_QBO = "+Config.getProperty(Config.BASE_URL_QBO));
DataService ds = new DataService(context);
AddBulkCustomer(ds);
System.out.println("Operation Complete..");
} catch (Exception e) {
e.printStackTrace();
}
}
When I debug, in execute method, I'm getting Null BatchOperation in return. I'm not sure performing Batch operation is allowed in sandbox environment.
I found the solution after so much of testing and communication with Quickbooks Devs thought would be helpful for others.
In sandbox environment even if you set the config properties to sandbox URL it still picks as PROD URL in Callbackhandler.
Config.setProperty(Config.BASE_URL_QBO, "https://sandbox-quickbooks.api.intuit.com/v3/company");
In this case they called this as a bug, currently all you can do is to make a trial account in PROD and then test this.