Unable to acquire a mutex held by a ACE_Condition wait - ace

I have the following code which is used to Push and Pend from a queue. The caller code has multiple MsgQ objects. It is possible that the Push and the Pend functions are waiting on the _notFull->wait() and the _notEmpty->wait() conditional waits. These waits are protected by the _mut mutex. The notFull and the notEmpty waits operate on the empty and full variables.
When the destructor is called, the _deleteQueue is called internally, from which I would like to signal to the waiting threads to cleanup and stop waiting for a signal to come. Once that is done, I delete my objects. However, in the _deleteQueue function, when I attempt to do _mut->acquire(), I am unable to acquire the mutex. Even if I ignore the acquire, I am unable to broadcast to these waiting threads. Where am I going wrong?
Thanks,
Vikram.
MsgQ::~MsgQ()
{
_deleteQueue();
delete _mut;_mut=NULL;
delete _notFull;_notFull=NULL;
delete _notEmpty;_notEmpty=NULL;
delete _PostMutex; _PostMutex = NULL;
delete _PendMutex; _PendMutex = NULL;
delete _PostInProgressMutex; _PostInProgressMutex = NULL;
delete _PendInProgressMutex; _PendInProgressMutex = NULL;
delete _DisconnectMutex; _DisconnectMutex = NULL;
free( _ptrQueue ); _ptrQueue = NULL;
}
int MsgQ::Post(Message* msg)
{
_PostMutex->acquire();
_postInProgress++;
_PostMutex->release();
if (msg)
msg->print();
_mut->acquire();
while (full)
{
_notFull->wait();
}
if (!_disconnectInProgress)
_queuePush(msg);
_mut->release();
_PostMutex->acquire();
_postInProgress--;
if (_postInProgress==0)
{
_PostInProgressMutex->signal();
}
_PostMutex->release();
return _notEmpty->signal();
}
int MsgQ::Pend(Message*& msg)
{
_PendMutex->acquire();
_pendInProgress++;
_PendMutex->release();
_mut->acquire();
while (empty)
_notEmpty->wait();
if (!_disconnectInProgress)
{
_queuePop(msg);
}
_mut->release();
_PendMutex->acquire();
_pendInProgress--;
if (_pendInProgress == 0)
{
_PendInProgressMutex->signal();
}
_PendMutex->release();
return _notFull->signal();
}
void MsgQ::_deleteQueue ()
{
_PostMutex->acquire();
if (_postInProgress != 0)
{
_PostMutex->release();
TRACE("Acquiring Mutex.");
_mut->acquire();
full = 0;
_notFull->broadcast();
_mut->release();
_PostInProgressMutex->wait();
}
else
{
_PostMutex->release();
}
_PendMutex->acquire();
if (_pendInProgress != 0)
{
_PendMutex->release();
TRACE("Acquiring Mutex.");
_mut->acquire();
empty = 0;
_notEmpty->broadcast();
_mut->release();
_PendInProgressMutex->wait();
}
else
{
_PendMutex->release();
}
}
void MsgQ::_initQueue()
{
_ptrQueue = (Message **)(malloc (size * sizeof (Message*)));
if (_ptrQueue == NULL)
{
cout << "queue could not be created!" << endl;
}
else
{
for (int i = 0; i < size; i++)
*(_ptrQueue + i) = NULL;
empty = 1;
full = 0;
head = 0;
tail = 0;
try{
_mut = new ACE_Mutex() ;
_notFull = new ACE_Condition<ACE_Mutex>(*_mut);
_notEmpty = new ACE_Condition<ACE_Mutex>(*_mut);
_PostMutex = new ACE_Mutex();
_PendMutex = new ACE_Mutex();
_PostInProgressMutex = new ACE_Condition<ACE_Mutex>(*_PostMutex);
_PendInProgressMutex = new ACE_Condition<ACE_Mutex>(*_PendMutex);
_DisconnectMutex = new ACE_Mutex();
_postInProgress = 0;
_pendInProgress = 0;
_disconnectInProgress = false;
}catch(...){
cout << "you should not be here" << endl;
}
}
}

There seem to be many problems with the code so I would suggest reworking it:
You have a potential for deadlock because you are acquiring _mut before you go into a wait condition in both Post and Pend functions.
Instead of using acquire and release on a ACE_Mutex I would suggest looking at using ACE_Guard class which can acquire mutex when created and release it when destroyed.
Why not use ACE_Message_Queue instead of creating your own?

Related

How can I force my window to keep itself updated?

Final Update
The solution was to create a TTimer, set its Interval to any value greater than 0, and assign its OnTimer property to an empty function.
I have a TThread that adds new controls to the main form at regular intervals, via Queue(). But the queued functions are never executed until the form receives user input, or the cursor moves over it, and then it executes all the queued functions at once.
With careful logging I have determined conclusively that the functions are being queued as intended by the thread. They simply aren't being executed by the main VCL loop until the form gets user interaction.
It's as if the main application loop doesn't run when there is no user interaction.
How can I force the form to execute queued functions immediately?
If it matters, the form and TThread are created by a .dll, which is called by another .dll, which itself is called by a console application.
Like this:
console application -> dll -> dll created by C++ Builder
Edit
void __fastcall GirkovArpa::Execute() {
while (!Terminated) {
if (GlobalMessageQueue.size() > 0) {
EnterCriticalSection(&myCritSect);
std::cout << ""; // this line is required, else thread won't execute
std::string GlobalMessage = GlobalMessageQueue.at(0);
std::string copy;
copy.assign(GlobalMessage);
GlobalMessageQueue.erase(GlobalMessageQueue.begin());
LeaveCriticalSection(&myCritSect);
Queue([&, copy]() {
// do stuff
});
}
}
}
Edit 2
Node.JS console app => Node DLL addon => C++Builder GUI DLL
My console application is specifically NodeJS. It loads a "NodeJS addon" (a type of DLL), which loads the DLL created with C++ Builder, which exports this function:
void myExportedFunction(const char *str) {
EnterCriticalSection(&myCritSect);
GlobalMessageQueue.push_back(std::string(str));
// CheckSynchronize();
LeaveCriticalSection(&myCritSect);
}
If CheckSynchronize() is not commented out, I get a Segmentation Fault error.
My TThread runs on an infinite loop, checking GlobalMessageQueue, and if it finds it's not empty, it queues a lambda which creates a TControl on the main form.
But the queued lambdas are not executed until the user interacts with the window (simply moving the cursor over the window will suffice).
Edit 3
Here is my full lambda:
Queue([&, copy]() {
std::vector<std::string> words;
boost::split(words, copy, boost::is_any_of(" "));
// CREATE $TControl $Name $Text $Parent
if (words.at(0) == "CREATE") {
if (words.at(1) == "TEXTBOX") {
String formName = stringToString(words.at(4));
TForm *form = getFormByName(formName);
TEdit *textbox = new TEdit(form);
textbox->Parent = form;
textbox->Name = words.at(2).c_str();
textbox->Text = words.at(3).c_str();
textbox->Show();
textbox->OnClick = MyForm->OnClick;
}
if (words.at(1) == "RADIO") {
String formName = stringToString(words.at(4));
TForm *form = getFormByName(formName);
TRadioButton *radio = new TRadioButton(form);
radio->Parent = form;
radio->Name = words.at(2).c_str();
radio->Caption = words.at(3).c_str();
radio->Show();
radio->OnClick = MyForm->OnClick;
}
if (words.at(1) == "BUTTON") {
String formName = stringToString(words.at(4));
TForm *form = getFormByName(formName);
TButton *button = new TButton(form);
button->Parent = form;
button->Name = words.at(2).c_str();
button->Caption = words.at(3).c_str();
button->Show();
button->OnClick = MyForm->OnClick;
}
if (words.at(1) == "FORM") {
createDialog(words.at(2).c_str(), words.at(3).c_str());
}
}
if (words.at(0) == "CHANGE") {
for (int j = 0; j < Screen->FormCount; j++) {
TForm *form = Screen->Forms[j];
if (form->Name == words.at(1).c_str()) {
TRttiContext ctx;
TRttiType *type = ctx.GetType(form->ClassInfo());
TRttiProperty *prop = type->GetProperty(words.at(2).c_str());
TValue value;
if (prop->PropertyType->TypeKind == tkUString) {
value = TValue::From<UnicodeString>(words.at(3).c_str());
} else if (prop->PropertyType->TypeKind == tkInteger) {
value = TValue::From<Integer>(StrToInt(words.at(3).c_str()));
} else {
std::cout << "ERROR" << std::endl;
}
prop->SetValue(form, value);
}
for (int i = 0; i < form->ControlCount; i++) {
TControl *control = form->Controls[i];
if (control->Name == words.at(1).c_str()) {
TRttiContext ctx;
TRttiType *type = ctx.GetType(control->ClassInfo());
TRttiProperty *prop = type->GetProperty(words.at(2).c_str());
TValue value;
if (prop->PropertyType->TypeKind == tkUString) {
value = TValue::From<UnicodeString>(words.at(3).c_str());
} else if (prop->PropertyType->TypeKind == tkInteger) {
value = TValue::From<Integer>(StrToInt(words.at(3).c_str()));
} else {
std::cout << "ERROR" << std::endl;
}
prop->SetValue(control, value);
}
}
}
}
// GET NAME PROP
if (words.at(0) == "GET") {
for (int j = 0; j < Screen->FormCount; j++) {
TForm *form = Screen->Forms[j];
if (form->Name == words.at(1).c_str()) {
TRttiContext ctx;
TRttiType *type = ctx.GetType(form->ClassInfo());
TRttiProperty *prop = type->GetProperty(words.at(2).c_str());
TValue result = prop->GetValue(form);
if (result.Kind == tkUString) {
String leString = result.AsString();
std::wstring w(std::wstring(leString.t_str()));
std::string STR(w.begin(), w.end());
std::string output = words.at(1) + " " + words.at(2);
String o = output.c_str();
tellJavaScript(AnsiString(o + ": " + leString).c_str());
} else if (result.Kind == tkInteger) {
int result_int = result.AsInteger();
String result_String = IntToStr(result_int);
String name = words.at(1).c_str();
String prop = words.at(2).c_str();
tellJavaScript(AnsiString(name + " " + prop + ": " + result_String).c_str());
} else {
// assume boolean
String result_String = BoolToStr(result.AsBoolean());
String name = words.at(1).c_str();
String prop = words.at(2).c_str();
tellJavaScript(AnsiString(name + " " + prop + ": " + result_String).c_str());
}
}
for (int i = 0; i < form->ControlCount; i++) {
TControl *control = form->Controls[i];
if (control->Name == words.at(1).c_str()) {
TRttiContext ctx;
TRttiType *type = ctx.GetType(control->ClassInfo());
TRttiProperty *prop = type->GetProperty(words.at(2).c_str());
TValue result = prop->GetValue(control);
if (result.Kind == tkUString) {
String leString = result.AsString();
std::wstring w(std::wstring(leString.t_str()));
std::string STR(w.begin(), w.end());
std::string output = words.at(1) + " " + words.at(2);
String o = output.c_str();
tellJavaScript(AnsiString(o + ": " + leString).c_str());
} else if (result.Kind == tkInteger) {
int result_int = result.AsInteger();
String result_String = IntToStr(result_int);
String name = words.at(1).c_str();
String prop = words.at(2).c_str();
tellJavaScript(AnsiString(name + " " + prop + ": " + result_String).c_str());
} else {
// assume boolean
String result_String = BoolToStr(result.AsBoolean());
String name = words.at(1).c_str();
String prop = words.at(2).c_str();
tellJavaScript(AnsiString(name + " " + prop + ": " + result_String).c_str());
}
}
}
}
}
if (words.at(0) == "DELETE") {
for (int j = 0; j < Screen->FormCount; j++) {
TForm *form = Screen->Forms[j];
if (form->Name == words.at(1).c_str()) {
form->Close();
}
for (int i = 0; i < form->ControlCount; i++) {
TControl *control = form->Controls[i];
if (control->Name == words.at(1).c_str()) {
control->Free();
}
}
}
}
if (words.at(0) == "EXECUTE") {
for (int j = 0; j < Screen->FormCount; j++) {
TForm *form = Screen->Forms[j];
if (form->Name == words.at(1).c_str()) {
std::cout << "EXECUTE <<" << words.at(2) << ">>" << std::endl;
TRttiContext context;
TRttiType *rttiType = context.GetType(form->ClassType());
TRttiMethod *method = rttiType->GetMethod(words.at(2).c_str());
DynamicArray<TRttiParameter *> parameters = method->GetParameters();
TValue args[10];
if (parameters.Length) {
for (int y = parameters.Low; y <= parameters.High; y++) {
String paramType = parameters[y]->ParamType->ToString();
if (paramType == "UnicodeString") {
args[y] = TValue::From<UnicodeString>(stringToString(words.at(y + 3)));
} else if (paramType == "Integer") {
args[y] = TValue::From<Integer>(StrToInt(stringToString(words.at(y + 3))));
}
}
TValue value = method->Invoke(form, args, parameters.High);
} else {
TValue value = method->Invoke(form, NULL, -1);
}
}
for (int i = 0; i < form->ControlCount; i++) {
TControl *control = form->Controls[i];
if (control->Name == words.at(1).c_str()) {
std::cout << "EXECUTE <<" << words.at(2) << ">>" << std::endl;
TRttiContext context;
TRttiType *rttiType = context.GetType(control->ClassType());
TRttiMethod *method = rttiType->GetMethod(words.at(2).c_str());
DynamicArray<TRttiParameter *> parameters = method->GetParameters();
TValue args[10];
if (parameters.Length) {
for (int y = parameters.Low; y <= parameters.High; y++) {
String paramType = parameters[y]->ParamType->ToString();
if (paramType == "UnicodeString") {
args[y] = TValue::From<UnicodeString>(stringToString(words.at(y + 3)));
} else if (paramType == "Integer") {
args[y] = TValue::From<Integer>(StrToInt(stringToString(words.at(y + 3))));
}
}
TValue value = method->Invoke(control, args, parameters.High);
} else {
TValue value = method->Invoke(control, NULL, -1);
}
}
}
}
}
});
It's as if the main application loop doesn't run when there is no user interaction.
It doesn't, actually. Well, more accurately, when there is no pending window messages at all. Once the main thread's message queue is emptied, the VCL calls the Win32 WaitMessage() function, which blocks the calling thread until a new message appears in the message queue. Even traditional non-VCL message loops tend to block the calling thread when there are no messages to process.
How can I force the form to execute queued functions immediately?
You can't force it.
If it matters, the form and TThread are created by a .dll, which is called by another .dll, which itself is called by a console application.
It DOES matter, because TThread::Queue() and TThread:::Synchronize() DO NOT work well inside of a DLL.
TThread::Queue() and TThread::Synchronize() put their requests into an internal queue inside the RTL, set a signal to indicate the queue has pending requests, and then post a message to the TApplication window to "wake up" the main thread (in case the message loop is "sleeping" waiting for a new message to arrive). That request queue is processed at the main thread's earliest convenience.
By default, a VCL message loop processes the TThread queue only when:
the message loop enters an idle state, after all pending messages have been processed and the message queue becomes empty.
the TApplication window receives the "wake up" message.
When the TThread queue is inside a DLL, and the DLL is not sharing the same RTL instance with the main EXE, then the main message loop in the EXE does not know about the TThread queue in the DLL, so it can't process the pending requests during idle times. That just leaves the "wake up" message, which the DLL will post to its own TApplication instance, not to the main EXE's TApplication. The main thread message loop will still dispatch window messages to a DLL's TApplication window.
To solve this, you will have to either:
enable Runtime Packages in the DLL and main EXE, or even change the DLL to be a Package, so that they can share common instances of the RTL and VCL. That does mean you will have to deploy the RTL and VCL .bpl files with your app, though.
export a function from your DLL that calls the RTL's CheckSynchronize() function, and then call that DLL function in your EXE code periodically, such as in a UI timer, or in the TApplication.OnIdle event, etc.
You're correct that the main loop of a typical Windows program does not run until there's some sort of input (usually user input, but there are other kinds as well).
I'm not familiar with the C++ Builder framework.
If you have control of code that makes the main loop, you can modify it to process additional sources of information, such as watching for another thread to signal a synchronization object.
Other options:
Have the thread that's adding items to the queue post a custom message to the main thread's window (or just a thread message) whenever it does one of its regular updates.
Set up a timer on the main thread. It will periodically "wake up" the main loop, just as the user input would.

async.Future async.Completer - how to "continue" if an error

Some help with the following would be appreciated. I am writing some console test programs, and I want to be able to enter some parameters from the terminal (I don't want to use command line arguments - too many parameters). I have tried some variations, but I cannot find how to accomplish this. The following is the latest version of my test for terminal input. The problem with this program is that if an error is encountered, the Completer closes automatically, and I want to continue from either the Main() or from fGetNumber() function. While I can see why this program doesn't work, it illustrates what I need to achieve - re-enter the number, but I cannot find how to achieve that. If a valid number is entered, there is no problem. If an invalid number is entered, I cannot find out how to re-enter the number.
The code is as follows, and the problem I have is highlighted by "//////////" :
import "dart:async" as async;
import "dart:io";
void main() {
fGetNumber("Enter Nr of Iterations : ", 0, 999999)
.then((int iIters){
print ("In Main : Iterations selected = ${iIters}");
if (iIters == null) {
print ("In Main: Invalid Number of iterations : ${iIters}.");
} else {
fProcessData(iIters);
}
print ("Main Completed");
});
}
async.Future<int> fGetNumber(String sPrompt, int iMin, int iMax) {
print ("In fGetNumber");
int iIters = 0;
async.Completer<int> oCompleter = new async.Completer();
while (!oCompleter.isCompleted) { /////////// This loop does not work ///////
return fGetUserInput(sPrompt).then((String sIters) {
iIters = int.parse(sIters);
if (iIters < iMin || iIters > iMax) throw new Exception("Invalid");
oCompleter.complete(iIters);
return oCompleter.future;
}).catchError((_) => print ("Invalid - number must be from ${iMin} to ${iMax}")
).whenComplete(() => print ("fGetNumber - whenComplete"));// always gets here
}
print ("In fGetNumber (at end of function)"); //// it never gets here
}
async.Future<String> fGetUserInput(String sPrompt) {
print ("In fGetUserInput");
async.Completer<String> oCompleter = new async.Completer();
stdout.write(sPrompt);
async.Stream<String> oStream = stdin.transform(new StringDecoder());
async.StreamSubscription oSub;
oSub = oStream.listen((String sData) {
oCompleter.complete("$sData");
oSub.cancel();
});
return oCompleter.future;
}
void fProcessData(int iIters) {
print ("In fProcessData");
for (int iPos = 1; iPos <= iIters; iPos++ ) {
if (iPos%100 == 0) print ("Processed = ${iPos}");
}
print ("In fProcessData - completed ${iIters}");
}
// This loop does not work
Of course it does - you enter it exactly once, where you immediately return and therefore leave the loop and method.
// always gets here
That's because whenComplete() always gets called, on success or on error.
// it never gets here
Because you already returned out of the method.
So what can be done?
The easiest way would be to not rely on fGetUserInput(). Listen to stdin in fGetNumber and only complete the completer / cancel the subscription if the input is valid:
async.Future<int> fGetNumber(String sPrompt, int iMin, int iMax) {
print ("In fGetNumber");
async.Completer<String> oCompleter = new async.Completer();
stdout.write(sPrompt);
async.Stream<String> oStream = stdin.transform(new StringDecoder());
async.StreamSubscription oSub;
oSub = oStream.listen((String sData) {
try {
int iIters = int.parse(sData);
if (iIters < iMin || iIters > iMax) throw new Exception("Invalid");
oCompleter.complete(iIters);
oSub.cancel();
} catch(e) {
print("Invalid - number must be from ${iMin} to ${iMax}");
stdout.write(sPrompt);
}
});
return oCompleter.future;
}
Are there alternatives?
Of course. There are likely many, many ways to do this. This one for example:
async.Future<int> fGetNumber(String sPrompt, int iMin, int iMax) {
print ("In fGetNumber");
async.Completer<int> oCompleter = new async.Completer();
fGetUserInput(sPrompt, oCompleter, (String sIters) {
try {
int iIters = int.parse(sIters);
if (iIters < iMin || iIters > iMax) throw new Exception("Invalid");
return iIters;
} catch(e) {
print ("Invalid - number must be from ${iMin} to ${iMax}");
stdout.write(sPrompt);
}
return null;
});
return oCompleter.future;
}
void fGetUserInput(String sPrompt, async.Completer oCompleter, dynamic inputValidator(String sData)) {
print ("In fGetUserInput");
stdout.write(sPrompt);
async.Stream<String> oStream = stdin.transform(new StringDecoder());
async.StreamSubscription oSub;
oSub = oStream.listen((String sData) {
var d = inputValidator(sData);
if(d != null) {
oCompleter.complete(d);
oSub.cancel();
}
});
}
If you really feel there should be something addressed by the Dart team, you could write a feature request. But the Completer is designed to only be completed once. Whatever code you write, you can't just loop to complete it again and again.

duplicate SSID in scanning wifi result

i'm trying to make an app that can create a list of available wifi access point. here's part of the code i used:
x = new BroadcastReceiver()
{
#Override
public void onReceive(Context c, Intent intent)
{
results = wifi.getScanResults();
size = results.size();
if (results != null) {
for (int i=0; i<size; i++){
ScanResult scanresult = wifi.getScanResults().get(i);
String ssid = scanresult.SSID;
int rssi = scanresult.level;
String rssiString = String.valueOf(rssi);
textStatus.append(ssid + "," + rssiString);
textStatus.append("\n");
}
unregisterReceiver(x); //stops the continuous scan
textState.setText("Scanning complete!");
} else {
unregisterReceiver(x);
textState.setText("Nothing is found. Please make sure you are under any wifi coverage");
}
}
};
both textStatus and textState is a TextView.
i can get this to work but sometimes the result shows duplicate SSID but with different signal level, in a single scan. there might be 3-4 same SSIDs but with different signal level.
is it really different SSIDs and what differs them? can anyone explain?
Are you having several router modems for the same network? For example: A company has a big wireless network with multiple router modems installed in several places so every room has Wifi. If you do that scan you will get a lot of results with the same SSIDs but with different acces points, and thus different signal level.
EDIT:
According to Walt's comment you can also have multiple results despite having only one access point if your modem is dual-band.
use below code to to remove duplicate ssids with highest signal strength
public void onReceive(Context c, Intent intent) {
ArrayList<ScanResult> mItems = new ArrayList<>();
List<ScanResult> results = wifiManager.getScanResults();
wifiListAdapter = new WifiListAdapter(ConnectToInternetActivity.this, mItems);
lv.setAdapter(wifiListAdapter);
int size = results.size();
HashMap<String, Integer> signalStrength = new HashMap<String, Integer>();
try {
for (int i = 0; i < size; i++) {
ScanResult result = results.get(i);
if (!result.SSID.isEmpty()) {
String key = result.SSID + " "
+ result.capabilities;
if (!signalStrength.containsKey(key)) {
signalStrength.put(key, i);
mItems.add(result);
wifiListAdapter.notifyDataSetChanged();
} else {
int position = signalStrength.get(key);
ScanResult updateItem = mItems.get(position);
if (calculateSignalStength(wifiManager, updateItem.level) >
calculateSignalStength(wifiManager, result.level)) {
mItems.set(position, updateItem);
wifiListAdapter.notifyDataSetChanged();
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
This is my simple Solution please and it is work for me
private void scanWifiListNew() {
wifiManager.startScan();
List<ScanResult> wifiList = wifiManager.getScanResults();
mWiFiList = new ArrayList<>();
for(ScanResult result: wifiList){
checkItemExists(mWiFiList, result);
}
setAdapter(mWiFiList);
}
private void printList(List<ScanResult> list){
for(ScanResult result: list){
int level = WifiManager.calculateSignalLevel(result.level, 100);
System.out.println(result.SSID + " Level is " + level + " out of 100");
}
}
private void checkItemExists(List<ScanResult> newWiFiList, ScanResult resultNew){
int indexToRemove = -1;
if(newWiFiList.size() > 0) {
for (int i = 0; i < newWiFiList.size(); i++) {
ScanResult resultCurrent = newWiFiList.get(i);
if (resultCurrent.SSID.equals(resultNew.SSID)) {
int levelCurrent = WifiManager.calculateSignalLevel(resultCurrent.level, 100);
int levelNew = WifiManager.calculateSignalLevel(resultNew.level, 100);
if (levelNew > levelCurrent) {
indexToRemove = i;
break;
}else indexToRemove = -2;
}
}
if(indexToRemove > -1){
newWiFiList.remove(indexToRemove);
newWiFiList.add(indexToRemove,resultNew);
}else if(indexToRemove == -1)newWiFiList.add(resultNew);
} else newWiFiList.add(resultNew);
}
private void setAdapter(List<ScanResult> list) {
listAdapter = new WifiListAdapter(getActivity().getApplicationContext(), list);
wifiListView.setAdapter(listAdapter);
}

A quicker way to delete list item versions

My requirement is to delete all the SPListItem versions except the first 25... so I have to start deleting from 26 or index 25. One of the SPListItem in a library has so many versions... may be more than 100k that the web interface is not able to show all the versions. The size of the database is almost 900GB.
I wrote this code but I think the issue is with the item.Versions property. It tries to load all the versions in memory
foreach (SPListItem item in library.Items)
{
foundMoreVersionsThanRequired = false;
int tempVersionToKepp = howManyVersionsToKeep + 1;
for (int i = 0; i <= tempVersionToKepp; i++)
{
SPListItemVersion objVersion = null;
try
{
objVersion = item.Versions[i];
if (objVersion != null && i == tempVersionToKepp)
{
foundMoreVersionsThanRequired = true;
break;
}
}
catch
{
foundMoreVersionsThanRequired = false;
break;
}
}
if (foundMoreVersionsThanRequired)
{
int tempIndex = howManyVersionsToKeep + 1;
SPListItemVersion objVersion = null;
do
{
try
{
objVersion = item.Versions[tempIndex];
if (objVersion != null)
{
objVersion.Delete();
}
else
break;
}
catch
{
break;
}
} while (true);
}
count++;
}
I am positive that the issue is with "item.Versions" property. It seems that when you call item.Versions it loads all the objects in the memory and that is causing a lot of issues.
Any way to delete an SPListItem version directly?
why not just set the list to only keep 25 versions within SharePoint itself from the web?

blackberry app download issue

I am building an AppWorld sort of thing in blackberry.I have Categories,sub categories and apps within.I want to do in-app download,but as of now i am calling the browser and passing the url and downloading of the content happens.How to make in-app download or download from within my app just like the AppWorld of blackberry.
YOu need to use code module manager API to download and install applications.
Code in bits and pieces
_moduleGroup = new CodeModuleGroup(appVendorName);
_moduleGroup.setVersion(JADParser.getValue("MIDlet-Version"));
_moduleGroup.setVendor(vendorName);
_moduleGroup.setFriendlyName(appName);
_moduleGroup.setDescription(JADParser.getValue("MIDlet-Description"));
String dependency = JADParser.getValue("RIM-COD-Module-Dependencies");
if (dependency != null)
{
dependency = dependency.trim();
String[] dependencyList = vStringUtils.split(dependency, ',');
for (int i = 0; i < dependencyList.length; i++)
{
_moduleGroup.addDependency(dependencyList[i]);
}
}
for (i = 0; i < count; i++)
{
if (!writeCODFile(getCodFileData(i), getCodFileName(i)))
{
throw new Exception();
}
}
private boolean writeCODFile(byte[] data, String fileName)
{
boolean isSuccess = true;
int moduleId = 0;
if (data.length > MODULE_SIZE_LIMIT)
{
moduleId = CodeModuleManager.createNewModule(data.length, data, MODULE_SIZE_LIMIT);
isSuccess = CodeModuleManager.writeNewModule(moduleId, MODULE_SIZE_LIMIT, data, MODULE_SIZE_LIMIT, data.length - MODULE_SIZE_LIMIT);
}
else
{
moduleId = CodeModuleManager.createNewModule(data.length, data, data.length);
}
if (moduleId > 0 && isSuccess)
{
int ret = CodeModuleManager.saveNewModule(moduleId, true, _transactionId);
if (ret == CodeModuleManager.CMM_OK_MODULE_OVERWRITTEN || ret == CodeModuleManager.CMM_OK)
{
return true;
}
}
return false;
}

Resources