Im working on implementing simple data provider with 2 level cache using RxJava2
public static void main(String args[]) {
Observable.concat(getFromMemory(), getFromFileCache(), getFromNetwork())
.firstElement()
.subscribe((integer) ->
{
System.out.println("Completed with val: " + integer);
});
}
static Observable<Integer> getFromMemory() {
return Observable.create(e -> {
System.out.println("Source: Memory");
e.onNext(1);
e.onComplete();
});
}
static Observable<Integer> getFromFileCache() {
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
return Observable.create(e -> {
System.out.println("Source: FileCache");
e.onNext(2);
e.onComplete();
});
}
static Observable<Integer> getFromNetwork() {
try {
Thread.sleep(2000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
return Observable.create(e -> {
System.out.println("Source: Network");
e.onNext(3);
e.onComplete();
});
}
Goal is to look for object in memory cache,
if not found - read from file, if not found - call network to get resource. Cache update is not important in this sample.
When executing this code, I see console log:
Source: Memory
Source: FileCache
Source: Network
Completed with val: 1
Which mean file cache and network call will be executed, despite memory cache returns value.
Im using rxJava 2, which operator can I use, to combine sources, but stop executing on first valueFound? I experimented with first(default) and take, no luck so far
Actually, its a bug in rxJava2 - upgrading to 2.1.0 helped:
Github issue: https://github.com/ReactiveX/RxJava/issues/5100
Related
I have a Azure Mobile Apps Xamarin.Forms PCL client and have Offline Sync enabled. I tried to Pull data from my backend and afterwards query data from the offline storage with a Where clause. That throws the following exception and I don't know why.
Sync error: 'fahrerinfo.Imei.Equals("02032032030232")' is not supported in a 'Where' Mobile Services query expression.
public async Task SyncAsync()
{
ReadOnlyCollection<MobileServiceTableOperationError> syncErrors = null;
try
{
await OfflineSyncStoreManager.Instance.TruckFahrerTable.PullAsync("allTruckFahrerItems",
OfflineSyncStoreManager.Instance.TruckFahrerTable.CreateQuery());
Debug.WriteLine("SyncAsync: PUSH/PULL completed.");
}
catch (MobileServicePushFailedException e)
{
Debug.WriteLine("SyncAsync: PUSH failed.");
Debug.WriteLine(e.Message);
}
catch (Exception e)
{
Debug.WriteLine("SyncAsync: PUSH/PULL failed.");
Debug.WriteLine(e.Message);
//Debugger.Break();
}
}
public async Task<ObservableCollection<TruckFahrer>> GetTruckFaherAsync(bool syncItems)
{
try
{
if (syncItems)
{
await OfflineSyncStoreManager.Instance.SyncAsync().ConfigureAwait(false);
}
var deviceInfo = DependencyService.Get<IDeviceInfo>().GetPhoneInfo();
var imeiString = deviceInfo[trucker_rolsped.PhoneInfo.PhoneInfo.ImeiKey];
var imei = imeiString.Equals("000000000000000") ? deviceInfo[trucker_rolsped.PhoneInfo.PhoneInfo.IdKey] : imeiString;
IEnumerable<TruckFahrer> items =
await OfflineSyncStoreManager.Instance.TruckFahrerTable
//.Where(fahrerinfo => fahrerinfo.Imei.Equals(imei)) TODO: Why does that throw an exception???
.ToEnumerableAsync();
// TODO: Because above does not work
items = items.Where(fahrer => fahrer.Imei.Equals(imei));
return new ObservableCollection<TruckFahrer>(items);
}
catch (MobileServiceInvalidOperationException msioe)
{
Debug.WriteLine(#"Invalid sync operation: {0}", msioe.Message);
Debugger.Break();
}
catch (Exception e)
{
Debug.WriteLine(#"Sync error: {0}", e.Message);
Debugger.Break();
}
return null;
}
Thanks for any hint,
Eric
Are you a Java developer too? I'm and had this issue because in Java we need to compare strings with String#equals method, haha.
For some reason MobileServices doesn't allow us to use Equals in this situation.
To fix your problem, use == instead. As you can see here C# difference between == and Equals() both have the same effect in this case.
Where(fahrerinfo => fahrerinfo.Imei == imei)
I'm trying to call SearchFactory optimize to run a scheduled index maintenance job (compacting segments - the application is a write intensive). But it does not seem to invoke immediately until I shutdown the Tomcat. My code is calling simply like this.
public synchronized void optimizeIndexes() {
getFullTextEntityManager().flushToIndexes(); //apply any changes before optimizing
getFullTextEntityManager().getSearchFactory().optimize();
logger.info("[Lucene] optimization has performed on all the indexes...");
}
I got it to work around by loaning IndexWriter from HSearch backend.
private synchronized void optimizeBareMetal() {
try {
LuceneBackendQueueProcessor backend = (LuceneBackendQueueProcessor) getIndexManager().getBackendQueueProcessor();
LuceneBackendResources resources = backend.getIndexResources();
AbstractWorkspaceImpl workspace = resources.getWorkspace();
IndexWriter indexWriter = workspace.getIndexWriter();
indexWriter.forceMerge(1, true);
indexWriter.commit();
} catch (LockObtainFailedException e) {
e.printStackTrace();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private synchronized DirectoryBasedIndexManager getIndexManager() {
SearchFactoryImplementor searchFactory = (SearchFactoryImplementor) getFullTextEntityManager().getSearchFactory();
IndexManagerHolder indexManagerHolder = searchFactory.getIndexManagerHolder();
return (DirectoryBasedIndexManager) indexManagerHolder.getIndexManager(getEntityClass().getName());
}
I have a client server application and I'm using rxjava to do server requests from the client. The client should only do one request at a time so I intent to use a thread queue scheduler similar to the trampoline scheduler.
Now I try to implement a mechanism to watch changes on the server. Therefore I send a long living request that blocks until the server has some changes and sends back the result (long pull).
This long pull request should only run when the job queue is idle. I'm looking for a way to automatically stop the watch request when a regular request is scheduled and start it again when the queue becomes empty. I thought about modifying the trampoline scheduler to get this behavior but I have the feeling that this is a common problem and there might be an easier solution?
You can hold onto the Subscription returned by scheduling the long poll task, unsubscribe it if the queue becomes non-empty and re-schedule if the queue becomes empty.
Edit: here is an example with the basic ExecutorScheduler:
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class IdleScheduling {
static final class TaskQueue {
final ExecutorService executor;
final AtomicReference<Future<?>> idleFuture;
final Runnable idleRunnable;
final AtomicInteger wip;
public TaskQueue(Runnable idleRunnable) {
this.executor = Executors.newFixedThreadPool(1);
this.idleRunnable = idleRunnable;
this.idleFuture = new AtomicReference<>();
this.wip = new AtomicInteger();
this.idleFuture.set(executor.submit(idleRunnable));
}
public void shutdownNow() {
executor.shutdownNow();
}
public Future<?> enqueue(Runnable task) {
if (wip.getAndIncrement() == 0) {
idleFuture.get().cancel(true);
}
return executor.submit(() -> {
task.run();
if (wip.decrementAndGet() == 0) {
startIdle();
}
});
}
void startIdle() {
idleFuture.set(executor.submit(idleRunnable));
}
}
public static void main(String[] args) throws Exception {
TaskQueue tq = new TaskQueue(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println("Idle interrupted...");
return;
}
System.out.println("Idle...");
}
});
try {
Thread.sleep(1500);
tq.enqueue(() -> System.out.println("Work 1"));
Thread.sleep(500);
tq.enqueue(() -> {
System.out.println("Work 2");
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
}
});
tq.enqueue(() -> System.out.println("Work 3"));
Thread.sleep(1500);
} finally {
tq.shutdownNow();
}
}
}
Here's my code:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import org.apache.lucene.index.CorruptIndexException;
public class Main
{
public static void main()
{
//Index index = new Index();
String[] titleAndContent = parseFile("files/methode.txt");
Index index = new Index("files",null);
try
{
index.openIndex(true);
index.addDocument(titleAndContent[0], titleAndContent[1], "files/methode.txt");
}
catch (CorruptIndexException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static String[] parseFile(String path)
{
String[] titleAndContent = new String[2];
File file = new File(path);
try
{
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
String line = new String();
String content = new String();
try
{
while((line = br.readLine()) != null)
{
if (line.substring(0,min(6,line.length())).equals("title:"))
{
titleAndContent[0] = line.substring(6,line.length());
}
else
{
if (line.substring(0,min(8,line.length())).equals("content:"))
{
content += line.substring(8,line.length())+"\n";
}
else
{
content += line+"\n";
}
}
}
}
catch (IOException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
titleAndContent[1] = content;
try
{
fr.close();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
catch (FileNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return titleAndContent;
}
public static int max (int a, int b)
{
if (a<b)
{
return b;
}
return a;
}
public static int min (int a, int b)
{
if (a<b)
{
return a;
}
return b;
}
}
The problem is, I can't compile my Lucene projet under Eclipse. It keeps telling me:
ERROR: index path not specified
Usage: java org.apache.lucene.index.CheckIndex pathToIndex [-fix] [-segment X] [-segment Y]
-fix: actually write a new segments_N file, removing any problematic segments
-segment X: only check the specified segments. This can be specified multiple
times, to check more than one segment, eg '-segment _2 -segment _a'.
You can't use this with the -fix option
**WARNING**: -fix should only be used on an emergency basis as it will cause
documents (perhaps many) to be permanently removed from the index. Always make
a backup copy of your index before running this! Do not run this tool on an index
that is actively being written to. You have been warned!
Run without -fix, this tool will open the index, report version information
and report any exceptions it hits and what action it would take if -fix were
specified. With -fix, this tool will remove any segments that have issues and
write a new segments_N file. This means all documents contained in the affected
segments will be removed.
This tool exits with exit code 1 if the index cannot be opened or has any
corruption, else 0.
I tried everything to make it work, and as the whole web says, I used
-ea:org.apache.lucene... pathToIndex -fix
as argument of compilation. But whatever I put instead of pathToIndex, it keeps telling me
Unexpected argument pathToIndex (or whatever instead)
How can I get this f... project work?
Thank you in advance.
Edit: Of course I've imported all Lucene JARs.
Actually, I started the project over by creating a simple Main class and a main method inside it and tried to compile it immediately. And it worked fine, this time. Note you should show the Main class on your screen tab before compiling in Eclipse.
I try to use get result from a api called j-calais, and then out put the result on a web page, i write all the code in client, but it cant compile right, dont know why??? please help. the source code like below:
there is no obvious error arise, but it cant be compile successfully..... thanks a lot:
public void onModuleLoad() {
// Create table for stock data.
stocksFlexTable.setText(0, 0, "Type");
stocksFlexTable.setText(0, 1, "Name");
// Assemble Add Stock panel.
addPanel.add(newSymbolTextBox);
addPanel.add(addStockButton);
// Assemble Main panel.
mainPanel.add(stocksFlexTable);
mainPanel.add(addPanel);
mainPanel.add(lastUpdatedLabel);
// Associate the Main panel with the HTML host page.
RootPanel.get("stockList").add(mainPanel);
// Move cursor focus to the input box.
newSymbolTextBox.setFocus(true);
// Listen for mouse events on the Add button.
addStockButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
try {
addStock();
} catch (Exception e) {
e.printStackTrace();
}
}
});
// Listen for keyboard events in the input box.
newSymbolTextBox.addKeyPressHandler(new KeyPressHandler() {
public void onKeyPress(KeyPressEvent event) {
if (event.getCharCode() == KeyCodes.KEY_ENTER) {
try {
addStock();
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
private void addStock() throws Exception {
final String url_s = newSymbolTextBox.getText().toUpperCase().trim();
newSymbolTextBox.setFocus(true);
newSymbolTextBox.setText("");
int row = stocksFlexTable.getRowCount();
CalaisClient client = new CalaisRestClient("ysw5rx69jkvdnzqf6sgjduqj");
System.out.print("read success...\n");
URL url = new URL(url_s);
CalaisResponse response = client.analyze(url);
for (CalaisObject entity : response.getEntities()) {
System.out.println(entity.getField("_type") + ":"
+ entity.getField("name"));
stocks.add(entity.getField("_type"));
stocksFlexTable.setText(row, 0, entity.getField("_type"));
stocksFlexTable.setText(row, 1, entity.getField("name"));
}
for (CalaisObject topic : response.getTopics()) {
System.out.println(topic.getField("categoryName"));
}
}
}
GWT only handles unchecked exceptions so you can throw Runtime Exceptions
or write your own Exception that extends from Runtime Exception then it will not cause any compile time problem
void f() throws NullPointerException // will not cause any problem because it is Runtime exception so unchecked
void f() throws IllegalAccessException // it is checked exception so there will be problem at compile time