How I count all the number of records in a RecordStore - lwuit

I have a LWUIT app that should display the number of records in a LWUIT list.
To get all the records I use a method called getRecordData() that returns all records as a String array, it works fine.
But how do I count the number of these records?
import java.util.*;
import com.sun.lwuit.events.*;
import javax.microedition.midlet.*;
import com.sun.lwuit.*;
import com.sun.lwuit.plaf.*;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms .*;
public class number_of_records extends MIDlet {
private RecordStore recordStore;
// Refresh2( ) method for getting the time now
public String Refresh2()
{
java.util.Calendar calendar = java.util.Calendar.getInstance();
Date myDate = new Date();
calendar.setTime(myDate);
StringBuffer time = new StringBuffer();
time.append(calendar.get(java.util.Calendar.HOUR_OF_DAY)).append(':');
time.append(calendar.get(java.util.Calendar.MINUTE)) ;
// time.append(calendar.get(java.util.Calendar.SECOND));
String tt = time.toString();
return tt;
}
// return all records of recordStore RecordStore
public String [] getRecordData( )
{
String[] str = null;
int counter = 0;
try
{
RecordEnumeration enumeration = recordStore.enumerateRecords(null, null, false);
str = new String[recordStore.getNumRecords()];
while(enumeration.hasNextElement())
{
try
{
str[counter] = (new String(enumeration.nextRecord()));
counter ++;
}
catch(javax.microedition.rms.RecordStoreException e)
{
}
}
}
catch(javax.microedition.rms.RecordStoreNotOpenException e)
{
}
catch(java.lang.NullPointerException n)
{
}
return str;
}
public void startApp()
{
com.sun.lwuit.Display.init(this);
final Button addition = new Button("add a goal");
final com.sun.lwuit.TextField tf = new com.sun.lwuit.TextField();
final com.sun.lwuit.List mylist = new com.sun.lwuit.List();
final Button All = new Button("All Goals");
final com.sun.lwuit.Form ff = new com.sun.lwuit.Form();
final com.sun.lwuit.Form g = new com.sun.lwuit.Form();
ff.getStyle().setBgColor(0X99CCFF);
All.getStyle().setBgColor(0X0066CC);
Style g_style5 = g.getSelectedStyle() ;
g.addComponent(tf);
g.addComponent(addition);
addition.getStyle().setBgColor(0X0066CC);
g.addComponent(All);
g.getStyle().setBgColor(0X99CCFF);
addition.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
//
String s =tf.getText();
if( s!=null && s.length() > 0)
{
try
{
// Store the time in the String k
String k = Refresh2();
// The record and the time stored in KK String
String kk =tf.getText()+"-"+k;
// Add an item (the kk String) to mylist List.
mylist.addItem(kk);
byte bytestream[] = kk.getBytes() ;
// Add a record to recordStore.
int i = recordStore.addRecord(bytestream, 0, bytestream.length);
}
catch(Exception ex) { }
// Inform the User that he added the a record.
Dialog validDialog = new Dialog(" ");
Style Dialogstyle = validDialog.getSelectedStyle() ;
validDialog.setScrollable(false);
validDialog.getDialogStyle().setBgColor(0x0066CC);
validDialog.setTimeout(1000); // set timeout milliseconds
TextArea textArea = new TextArea("...."); //pass the alert text here
textArea.setFocusable(false);
textArea.setText("A goal has been added"+"" );
validDialog.addComponent(textArea);
validDialog.show(0, 10, 10, 10, true);
}
// Information to user that he/she didn’t add a record
else if((s==null || s.length()<= 0))
{
Dialog validDialo = new Dialog(" ");
validDialo.setScrollable(false);
validDialo.getDialogStyle().setBgColor(0x0066CC);
validDialo.setTimeout(5000); // set timeout milliseconds
TextArea textArea = new TextArea("...."); //pass the alert text here
textArea.setFocusable(false);
textArea.setText("please enter scorer name or number");
validDialo.addComponent(textArea);
validDialo.show(50, 50, 50, 50, true);
}
}
});
/*Action here for displaying all records of recordStore RecordStore in a new form */
All.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
try
{
recordStore = RecordStore.openRecordStore("My Record Store", true);
}
catch(Exception ex) {}
try
{
com.sun.lwuit.Label l = new com.sun.lwuit.Label(" Team Goals") ;
ff.addComponent(l);
// Store the records of recordStore in string array
String [] record= getRecordData();
int j1;
String valueToBeInserted2="";
int k=getRecordData().length;
for( j1=0;j1< getRecordData().length;j1++)
{
valueToBeInserted2=valueToBeInserted2 + " " + record[j1];
if(j1==getRecordData().length)
{
mylist.addItem(record[j1]);
int m = getRecordData().length;
// Counting the number of records
String goals =""+getRecordData().length;
/* I tried to use for…loop to count them by length of the recordStore and render it.
This list also should display the number of records on the form.
But it didn’t !!!
*/
mylist.addItem(goals);
}
}
ff.addComponent(mylist);
}
catch(java.lang.IllegalArgumentException e)
{
}
finally
{
ff.show();
}
}
}
);
g.show();
}
public void pauseApp()
{
}
public void destroyApp(boolean unconditional) {
}
}
I Wrote this code but it gives NullPointerException at recordStore.enumerateRecords (null, null,true);
So I think the problem here.
please help.
myButton.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvet av)
{
try
{
RecordEnumeration enumeration = recordStore.enumerateRecords (null, null,true);
int o =recordStore.getNumRecords () ;
}
catch(Exception e)
{
}
}
});

what you need is enumeration.numRecords(); i reckon recordStore.getNumRecords() should work also, since this is what you are using the populate the array, you could even use the length of the array itself. These options are all in the code, it would be better to explore a bit more and also check the documentation to resolve trivial problems.

you could use the length of the array or set a RecordListener to your recordstore and increase a counter when added a record to recordstore.

here is the solution of my problem , I do a for loop to get the number of
elements of the array.
the counter should be the length of array
count.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent av)
{
try
{
recordStore = RecordStore.openRecordStore("recordStore", true);
}
catch(Exception e)
{ }
try
{
RecordEnumeration enumeration = recordStore.enumerateRecords (null, null,true);
}
catch(Exception e)
{
}
String record[] = getRecordData();
int j;
j = record.length-1;
Dialog validDialog = new Dialog(" ");
Style Dialogstyle = validDialog.getSelectedStyle() ;
validDialog.setScrollable(false);
validDialog.getDialogStyle().setBgColor(0x0066CC);
validDialog.setTimeout(1000); // set timeout milliseconds
TextArea textArea = new TextArea("....");
textArea.setFocusable(false);
textArea.setText("Number Counted"+j );
validDialog.addComponent(textArea);
validDialog.show(0, 10, 10, 10, true);
}});

Related

AutoCompleteTextField list does not always scroll to top?

The AutoCompleteTextField seems to work exactly as intended until I start backspacing in the TextField. I am not sure what the difference is, but if I type in something like "123 M" then I get values that start with "123 M". If I backspace and delete the M leaving "123 " in the field, the list changes, but it does not scroll to the top of the list.
I should note that everything works fine on the simulator and that I am experiencing this behavior when running a debug build on my iPhone.
EDIT: So this does not only seem to happen when backspacing. This image shows the results I have when typing in an address key by key. In any of the pictures where the list isn't viewable or is clipped, I am able to drag down on the list to get it to then display properly. I have not tried this on an Android device.
EDIT2:
public class CodenameOneTest {
private Form current;
private Resources theme;
private WaitingClass w;
private String[] properties = {"1 MAIN STREET", "123 E MAIN STREET", "12 EASTER ROAD", "24 MAIN STREET"};
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
// Enable Toolbar on all Forms by default
Toolbar.setGlobalToolbar(true);
}
public void start() {
if(current != null) {
current.show();
return;
}
Form form = new Form("AutoCompleteTextField");
form.setLayout(new BorderLayout());
final DefaultListModel<String> options = new DefaultListModel<>();
AutoCompleteTextField ac = new AutoCompleteTextField(options) {
protected boolean filter(String text) {
if(text.length() == 0) {
options.removeAll();
return false;
}
String[] l = searchLocations(text);
if(l == null || l.length == 0) {
return false;
}
options.removeAll();
for(String s : l) {
options.addItem(s);
}
return true;
};
};
Container container = new Container(BoxLayout.y());
container.setScrollableY(true); // If you comment this out then the field works fine
container.add(ac);
form.addComponent(BorderLayout.CENTER, container);
form.show();
}
String[] searchLocations(String text) {
try {
if(text.length() > 0) {
if(w != null) {
w.actionPerformed(null);
}
w = new WaitingClass();
String[] properties = getProperties(text);
if(Display.getInstance().isEdt()) {
Display.getInstance().invokeAndBlock(w);
}
else {
w.run();
}
return properties;
}
}
catch(Exception e) {
Log.e(e);
}
return null;
}
private String[] getProperties(String text) {
List<String> returnList = new ArrayList<>();
List<String> propertyList = Arrays.asList(properties);
for(String property : propertyList) {
if(property.startsWith(text)) {
returnList.add(property);
}
}
w.actionPerformed(null);
return returnList.toArray(new String[returnList.size()]);
}
class WaitingClass implements Runnable, ActionListener<ActionEvent> {
private boolean finishedWaiting;
public void run() {
while(!finishedWaiting) {
try {
Thread.sleep(30);
}
catch(InterruptedException ex) {
ex.printStackTrace();
}
}
}
public void actionPerformed(ActionEvent e) {
finishedWaiting = true;
return;
}
}
public void stop() {
current = Display.getInstance().getCurrent();
if(current instanceof Dialog) {
((Dialog)current).dispose();
current = Display.getInstance().getCurrent();
}
}
public void destroy() {
}
}
I used this code on an iPhone 4s:
public void start() {
if(current != null){
current.show();
return;
}
Form hi = new Form("AutoComplete", new BorderLayout());
if(apiKey == null) {
hi.add(new SpanLabel("This demo requires a valid google API key to be set in the constant apiKey, "
+ "you can get this key for the webservice (not the native key) by following the instructions here: "
+ "https://developers.google.com/places/web-service/get-api-key"));
hi.getToolbar().addCommandToRightBar("Get Key", null, e -> Display.getInstance().execute("https://developers.google.com/places/web-service/get-api-key"));
hi.show();
return;
}
Container box = new Container(new BoxLayout(BoxLayout.Y_AXIS));
box.setScrollableY(true);
for(int iter = 0 ; iter < 30 ; iter++) {
box.add(createAutoComplete());
}
hi.add(BorderLayout.CENTER, box);
hi.show();
}
private AutoCompleteTextField createAutoComplete() {
final DefaultListModel<String> options = new DefaultListModel<>();
AutoCompleteTextField ac = new AutoCompleteTextField(options) {
#Override
protected boolean filter(String text) {
if(text.length() == 0) {
return false;
}
String[] l = searchLocations(text);
if(l == null || l.length == 0) {
return false;
}
options.removeAll();
for(String s : l) {
options.addItem(s);
}
return true;
}
};
ac.setMinimumElementsShownInPopup(5);
return ac;
}
String[] searchLocations(String text) {
try {
if(text.length() > 0) {
ConnectionRequest r = new ConnectionRequest();
r.setPost(false);
r.setUrl("https://maps.googleapis.com/maps/api/place/autocomplete/json");
r.addArgument("key", apiKey);
r.addArgument("input", text);
NetworkManager.getInstance().addToQueueAndWait(r);
Map<String,Object> result = new JSONParser().parseJSON(new InputStreamReader(new ByteArrayInputStream(r.getResponseData()), "UTF-8"));
String[] res = Result.fromContent(result).getAsStringArray("//description");
return res;
}
} catch(Exception err) {
Log.e(err);
}
return null;
}
I was able to create this issue but not the issue you describe.

How to implement boolean retrieval using hitcollector in below scenario

I am running my code on TREC documents and right now implementing scoring scheme to get number of relevant documents. However now i want to implement boolean retrieval, I am trying to use HitCollector.
below is my code..
public class BatchSearch {
private BatchSearch() {}
/** Simple command-line based search demo. */
public static void main(String[] args) throws Exception {
String usage =
"Usage:\tjava BatchSearch [-index dir] [-simfn similarity] [-field f] [-queries file]";
if (args.length > 0 && ("-h".equals(args[0]) || "-help".equals(args[0]))) {
System.out.println(usage);
System.out.println("Supported similarity functions:\ndefault: DefaultSimilary (tfidf)\n");
System.exit(0);
}
String index = "index";
String field = "contents";
String queries = null;
String simstring = "default";
for(int i = 0;i < args.length;i++) {
if ("-index".equals(args[i])) {
index = args[i+1];
i++;
} else if ("-field".equals(args[i])) {
field = args[i+1];
i++;
} else if ("-queries".equals(args[i])) {
queries = args[i+1];
i++;
} else if ("-simfn".equals(args[i])) {
simstring = args[i+1];
i++;
}
}
Similarity simfn = null;
if ("default".equals(simstring)) {
simfn = new DefaultSimilarity();
} else if ("bm25".equals(simstring)) {
simfn = new BM25Similarity();
} else if ("dfr".equals(simstring)) {
simfn = new DFRSimilarity(new BasicModelP(), new AfterEffectL(), new NormalizationH2());
} else if ("lm".equals(simstring)) {
simfn = new LMDirichletSimilarity();
}
if (simfn == null) {
System.out.println(usage);
System.out.println("Supported similarity functions:\ndefault: DefaultSimilary (tfidf)");
System.out.println("bm25: BM25Similarity (standard parameters)");
System.out.println("dfr: Divergence from Randomness model (PL2 variant)");
System.out.println("lm: Language model, Dirichlet smoothing");
System.exit(0);
}
IndexReader reader = DirectoryReader.open(FSDirectory.open(new File(index)));
IndexSearcher searcher = new IndexSearcher(reader);
searcher.setSimilarity(simfn);
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_41);
BufferedReader in = null;
if (queries != null) {
in = new BufferedReader(new InputStreamReader(new FileInputStream(queries), "UTF-8"));
} else {
in = new BufferedReader(new InputStreamReader(new FileInputStream("queries"), "UTF-8"));
}
QueryParser parser = new QueryParser(Version.LUCENE_41, field, analyzer);
while (true) {
String line = in.readLine();
if (line == null || line.length() == -1) {
break;
}
line = line.trim();
if (line.length() == 0) {
break;
}
String[] pair = line.split(" ", 2);
Query query = parser.parse(pair[1]);
doBatchSearch(in, searcher, pair[0], query, simstring);
}
reader.close();
}
/**
* This function performs a top-1000 search for the query as a basic TREC run.
*/
public static void doBatchSearch(BufferedReader in, IndexSearcher searcher, String qid, Query query, String runtag)
throws IOException {
// Collect enough docs to show 5 pages
TopDocs results = searcher.search(query, 1000);
ScoreDoc[] hits = results.scoreDocs;
HashMap<String, String> seen = new HashMap<String, String>(1000);
int numTotalHits = results.totalHits;
int start = 0;
int end = Math.min(numTotalHits, 1000);
for (int i = start; i < end; i++) {
Document doc = searcher.doc(hits[i].doc);
String docno = doc.get("docno");
// There are duplicate document numbers in the FR collection, so only output a given
// docno once.
if (seen.containsKey(docno)) {
continue;
}
seen.put(docno, docno);
System.out.println(qid+" Q0 "+docno+" "+i+" "+hits[i].score+" "+runtag);
}
}
}
The scoring is done in doBatchSearch and now i want to implement HitCollector here.

GWT-RPC method returns empty list on success

I am creating a webpage having CellTable.I need to feed this table with data from hbase table.
I have written a method to retrieve data from hbase table and tested it.
But when I call that method as GWT asynchronous RPC method then rpc call succeeds but it returns nothing.In my case it returns empty list.The alert box show list's size as 0.
Following is the related code.
Please help.
greetingService.getDeviceIDData(new AsyncCallback<List<DeviceDriverBean>>(){
public void onFailure(Throwable caught) {
// Show the RPC error message to the user
System.out.println("RPC Call failed");
Window.alert("Data : RPC call failed");
}
public void onSuccess(List<DeviceDriverBean> result) {
//on success do something
Window.alert("Data : RPC call successful");
//deviceDataList.addAll(result);
Window.alert("Result size: " +result.size());
// Add a text column to show the driver name.
TextColumn<DeviceDriverBean> nameColumn = new TextColumn<DeviceDriverBean>() {
#Override
public String getValue(DeviceDriverBean object) {
Window.alert(object.getName());
return object.getName();
}
};
table.addColumn(nameColumn, "Name");
// Add a text column to show the device id
TextColumn<DeviceDriverBean> deviceidColumn = new TextColumn<DeviceDriverBean>() {
#Override
public String getValue(DeviceDriverBean object) {
return object.getDeviceId();
}
};
table.addColumn(deviceidColumn, "Device ID");
table.setRowCount(result.size(), true);
// more code here to add columns in celltable
// Push the data into the widget.
table.setRowData(0, result);
SimplePager pager = new SimplePager();
pager.setDisplay(table);
VerticalPanel vp = new VerticalPanel();
vp.add(table);
vp.add(pager);
// Add it to the root panel.
RootPanel.get("datagridContainer").add(vp);
}
});
Code to retrieve data from hbase (server side code)
public List<DeviceDriverBean> getDeviceIDData()
throws IllegalArgumentException {
List<DeviceDriverBean> deviceidList = new ArrayList<DeviceDriverBean>();
// Escape data from the client to avoid cross-site script
// vulnerabilities.
/*
* input = escapeHtml(input); userAgent = escapeHtml(userAgent);
*
* return "Hello, " + input + "!<br><br>I am running " + serverInfo +
* ".<br><br>It looks like you are using:<br>" + userAgent;
*/
try {
Configuration config = HbaseConnectionSingleton.getInstance()
.HbaseConnect();
HTable testTable = new HTable(config, "driver_details");
byte[] family = Bytes.toBytes("details");
Scan scan = new Scan();
int cnt = 0;
ResultScanner rs = testTable.getScanner(scan);
for (Result r = rs.next(); r != null; r = rs.next()) {
DeviceDriverBean deviceDriverBean = new DeviceDriverBean();
byte[] rowid = r.getRow(); // Category, Date, Sentiment
NavigableMap<byte[], byte[]> map = r.getFamilyMap(family);
Iterator<Entry<byte[], byte[]>> itrt = map.entrySet()
.iterator();
deviceDriverBean.setDeviceId(Bytes.toString(rowid));
while (itrt.hasNext()) {
Entry<byte[], byte[]> entry = itrt.next();
//cnt++;
//System.out.println("Count : " + cnt);
byte[] qual = entry.getKey();
byte[] val = entry.getValue();
if (Bytes.toString(qual).equalsIgnoreCase("account_number")) {
deviceDriverBean.setAccountNo(Bytes.toString(val));
} else if (Bytes.toString(qual).equalsIgnoreCase("make")) {
deviceDriverBean.setMake(Bytes.toString(val));
} else if (Bytes.toString(qual).equalsIgnoreCase("model")) {
deviceDriverBean.setModel(Bytes.toString(val));
} else if (Bytes.toString(qual).equalsIgnoreCase("driver_name")) {
deviceDriverBean.setName(Bytes.toString(val));
} else if (Bytes.toString(qual).equalsIgnoreCase("premium")) {
deviceDriverBean.setPremium(Bytes.toString(val));
} else if (Bytes.toString(qual).equalsIgnoreCase("year")) {
deviceDriverBean.setYear(Bytes.toString(val));
} else {
System.out.println("No match found");
}
/*
* System.out.println(Bytes.toString(rowid) + " " +
* Bytes.toString(qual) + " " + Bytes.toString(val));
*/
}
deviceidList.add(deviceDriverBean);
}
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (Exception e) {
// System.out.println("Message: "+e.getMessage());
e.printStackTrace();
}
return deviceidList;
}
Could this be lazy fetching on the server side by hbase. This means if you return the list hbase won't get a trigger to actually read the list and you will simple get an empty list. I don't know a correct solution, in the past I've seen a similar problem on GAE. This could by solved by simply asking the size of the list just before returning it to the client.
I don't have the exact answer, but I have an advise. In similar situation I put my own trace to check every step in my program.
On the server side before return put : System.out.println("size of table="+deviceidList.size());
You can put this trace in the loop for deviceidList;

wicket download output stream

I want to download csv file , i take the response content and write to it , apprently wicket write after me and the content iam getting is the page html where it should be my csv
I have seen in the example the usage of throw new AbortException();
I am using version 6.7 , do you know if my version wicket has somthing instead of it ?
or rather I am doing somthing wrong ....
can you please help me ...
add(new Link<Void>("export") {
#Override
public void onClick() {
WebResponse response = (WebResponse) getResponse();
response.setAttachmentHeader("export.csv");
response.setContentType("text/csv");
OutputStream out = getResponse().getOutputStream();
try {
c.exportData(dataSource.getListForExport(), columns, out);
} catch (Exception ex) {
System.err.println(ex);
}
}
});
public <T> void exportData(List<T> list, List<IGridColumn<IDataSource<T>, T, String>> columns, OutputStream outputStream)
throws IOException {
long startTime = System.nanoTime();
PrintWriter out = new PrintWriter(new OutputStreamWriter(outputStream, Charset.forName(characterSet)));
try {
if (isExportHeadersEnabled()) {
boolean first = true;
for (IGridColumn<IDataSource<T>, T, String> col : columns) {
if (first) {
first = false;
} else {
out.print(delimiter);
System.out.println(delimiter);
}
if (col.getId().equals("checkBox")) {
continue;
}
out.print(quoteValue(col.getId()));
System.out.println(col.getId());
}
out.print("\r\n");
System.out.println("\r\n");
}
Iterator<? extends T> rowIterator = list.iterator();
while (rowIterator.hasNext()) {
T row = rowIterator.next();
boolean first = true;
for (IGridColumn<IDataSource<T>, T, String> col : columns) {
if (first) {
first = false;
} else {
out.print(delimiter);
System.out.println(delimiter);
}
if (col.getId().equals("checkBox")) {
continue;
}
Object o = (new PropertyModel<>(row, col.getId())).getObject();// ((AbstractColumn<T,
if (o != null) {
Class<?> c = o.getClass();
String s;
IConverter converter = Application.get().getConverterLocator().getConverter(c);
if (converter == null) {
s = o.toString();
} else {
s = converter.convertToString(o, Session.get().getLocale());
}
out.print(quoteValue(s));
System.out.println(quoteValue(s));
}
}
out.print("\r\n");
System.out.println("\r\n");
}
} catch (Exception ex) {
System.out.println(ex);
} finally {
System.out.println(out);
out.close();
// measure
System.out.print(System.nanoTime() - startTime);
}
}
The best way to do this is using dynamic resources. I'll suggest you to read chapter "Resource managment with Wicket" of this magnific free Wicket guide: https://code.google.com/p/wicket-guide/.
Here you have a similar example given in this guide in the section "Custom resources".
public class RSSProducerResource extends AbstractResource {
#Override
protected ResourceResponse newResourceResponse(Attributes attributes) {
ResourceResponse resourceResponse = new ResourceResponse();
resourceResponse.setContentType("text/xml");
resourceResponse.setTextEncoding("utf-8");
resourceResponse.setWriteCallback(new WriteCallback()
{
#Override
public void writeData(Attributes attributes) throws IOException
{
OutputStream outputStream = attributes.getResponse().getOutputStream();
Writer writer = new OutputStreamWriter(outputStream);
SyndFeedOutput output = new SyndFeedOutput();
try {
output.output(getFeed(), writer);
} catch (FeedException e) {
throw new WicketRuntimeException("Problems writing feed to response...");
}
}
});
return resourceResponse;
}
// method getFeed()...
}
And then you need to add the link in the desired page or component:
add(new ResourceLink("rssLink", new RSSProducerResource()));

Reactive Extensions Group By, Unique BufferWindow till time span with cancellation

I have a Hot stream of events coming of following type:
Event
{
string name;
int state ; // its 1 or 2 ie active or unactive
}
there is a function which provides parent name of given name - string GetParent(string name)
I need to buffer event per parent for 2 minutes, if during this 2 minute , i recv any event for child with state =2 for a given parent , this buffer should cancel and should output 0 otherwise i get the count of the events recvd .
I know I have to use GroupBy to partition, and then buffer and then count but i am unable to think of a way by which i create Buffer which is unique per parent, i though of using Distinct but this doesnt solve the problem, for i only dont want to create buffer till the parent is active (as once the parent's buffer gets cancelled or 2 minutes is over, the parent buffer can be created again)
So I understand I need to create a custom buffer which checks the condition for creating buffer, but how do i do this via reactive extensions.
Any help will be greatly appreciated.
regards
Thanks Brandon for your help. This is the main program I am using for testing. Its not working.As I am new to reactive extension problem can be in the way i am testing
namespace TestReactive
{
class Program
{
static int abc = 1;
static void Main(string[] args)
{
Subject<AEvent> memberAdded = new Subject<AEvent>();
//ISubject<AEvent, AEvent> syncedSubject = new ISubject<AEvent, AEvent>();
var timer = new Timer { Interval = 5 };
timer.Enabled = true;
timer.Elapsed += (sender, e) => MyElapsedMethod(sender, e, memberAdded);
var bc = memberAdded.Subscribe();
var cdc = memberAdded.GroupBy(e => e.parent)
.SelectMany(parentGroup =>
{
var children = parentGroup.Publish().RefCount();
var inactiveChild = children.SkipWhile(c => c.state != 2).Take(1).Select(c => 0);
var timer1 = Observable.Timer(TimeSpan.FromSeconds(1));
var activeCount = children.TakeUntil(timer1).Count();
return Observable.Amb(activeCount, inactiveChild)
.Select(count => new { ParentName = parentGroup.Key, Count = count });
});
Observable.ForEachAsync(cdc, x => WriteMe("Dum Dum " + x.ParentName+x.Count));
// group.Dump("Dum");
Console.ReadKey();
}
static void WriteMe(string sb)
{
Console.WriteLine(sb);
}
static void MyElapsedMethod(object sender, ElapsedEventArgs e, Subject<AEvent> s)
{
AEvent ab = HelperMethods.GetAlarm();
Console.WriteLine(abc + " p =" + ab.parent + ", c = " + ab.name + " ,s = " + ab.state);
s.OnNext(ab);
}
}
}
public static AEvent GetAlarm()
{
if (gp> 4)
gp = 1;
if (p > 4)
p = 1;
if (c > 4)
c = 1;
AEvent a = new AEvent();
a.parent = "P" + gp + p;
a.name = "C" + gp + p + c;
if (containedKeys.ContainsKey(a.name))
{
a.state = containedKeys[a.name];
if (a.state == 1)
containedKeys[a.name] = 2;
else
containedKeys[a.name] = 1;
}
else
{
containedKeys.TryAdd(a.name, 1);
}
gp++; p++; c++;
return a;
}
So this method , generates a event for Parent at each tick. It generates event for parent P11,P22,P33,P44 with State =1 and then followed by events for Parent P11,P22,P33,P44 with State =2
I am using Observable.ForEach to print the result, I see its being called 4 times and after that its nothing, its like cancellation of group is not happening
Assuming that a two minute buffer for each group should open as soon as the first event for that group is seen, and close after two minutes or a zero state is seen, then I think the following works:
public static IObservable<EventCount> EventCountByParent(
this IObservable<Event> source, IScheduler scheduler)
{
return Observable.Create<EventCount>(observer => source.GroupByUntil(
evt => GetParent(evt.Name),
evt => evt,
group =>
#group.Where(evt => evt.State == 2)
.Merge(Observable.Timer(
TimeSpan.FromMinutes(2), scheduler).Select(_ => Event.Null)))
.SelectMany(
go =>
go.Aggregate(0, (acc, evt) => (evt.State == 2 ? 0 : acc + 1))
.Select(count => new EventCount(go.Key, count))).Subscribe(observer));
}
With EventCount (implementing equality overrides for testing) as:
public class EventCount
{
private readonly string _name;
private readonly int _count;
public EventCount(string name, int count)
{
_name = name;
_count = count;
}
public string Name { get { return _name; } }
public int Count { get { return _count; } }
public override string ToString()
{
return string.Format("Name: {0}, Count: {1}", _name, _count);
}
protected bool Equals(EventCount other)
{
return string.Equals(_name, other._name) && _count == other._count;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((EventCount) obj);
}
public override int GetHashCode()
{
unchecked
{
return ((_name != null ? _name.GetHashCode() : 0)*397) ^ _count;
}
}
}
And Event as:
public class Event
{
public static Event Null = new Event(string.Empty, 0);
private readonly string _name;
private readonly int _state;
public Event(string name, int state)
{
_name = name;
_state = state;
}
public string Name { get { return _name; } }
public int State { get { return _state; } }
}
I did a quick (i.e. not exhaustive) test with Rx-Testing:
public class EventCountByParentTests : ReactiveTest
{
private readonly TestScheduler _testScheduler;
public EventCountByParentTests()
{
_testScheduler = new TestScheduler();
}
[Fact]
public void IsCorrect()
{
var source = _testScheduler.CreateHotObservable(
OnNext(TimeSpan.FromSeconds(10).Ticks, new Event("A", 1)),
OnNext(TimeSpan.FromSeconds(20).Ticks, new Event("B", 1)),
OnNext(TimeSpan.FromSeconds(30).Ticks, new Event("A", 1)),
OnNext(TimeSpan.FromSeconds(40).Ticks, new Event("B", 1)),
OnNext(TimeSpan.FromSeconds(50).Ticks, new Event("A", 1)),
OnNext(TimeSpan.FromSeconds(60).Ticks, new Event("B", 2)),
OnNext(TimeSpan.FromSeconds(70).Ticks, new Event("A", 1)),
OnNext(TimeSpan.FromSeconds(140).Ticks, new Event("A", 1)),
OnNext(TimeSpan.FromSeconds(150).Ticks, new Event("A", 1)));
var results = _testScheduler.CreateObserver<EventCount>();
var sut = source.EventCountByParent(_testScheduler).Subscribe(results);
_testScheduler.Start();
results.Messages.AssertEqual(
OnNext(TimeSpan.FromSeconds(60).Ticks, new EventCount("B", 0)),
OnNext(TimeSpan.FromSeconds(130).Ticks, new EventCount("A", 4)),
OnNext(TimeSpan.FromSeconds(260).Ticks, new EventCount("A", 2)));
}
}
something like....
source.GroupBy(e => GetParent(e.name))
.SelectMany(parentGroup =>
{
var children = parentGroup.Publish().RefCount();
var inactiveChild = children.SkipWhile(c => c.state != 2).Take(1).Select(c => 0);
var timer = Observable.Timer(TimeSpan.FromMinutes(2));
var activeCount = children.TakeUntil(timer).Count();
return Observable.Amb(activeCount, inactiveChild)
.Select(count => new { ParentName = parentGroup.Key, Count = count };
});
This will give you a sequence of { ParentName, Count } objects.