Cassandra cluster is not scaling. 3 Nodes are even a little faster then 6 nodes (Code and data provided) - cassandra

I am using Datastax Enterprise 4.8 for testing purposes in my bachelor thesis. I am loading wheather data into the cluster (about 33 Mio rows).
The data looks something like the following
//id;unix timestamp; validity; station info; temp in °C; humidity in %
3;1950040101;5;24; 5.7000;83.0000
3;1950040102;5;24; 5.6000;83.0000
3;1950040103;5;24; 5.5000;83.0000
I know my data model is not very clean (I use decimal for the timestamp but I just wanted to try it this way).
CREATE TABLE temp{
id int,
timestamp decimal,
validity decimal,
structure decimal,
temperature float,
humidity float,
PRIMARY KEY((id),timestamp));
I roughly based it on an article on the datastax website:
https://academy.datastax.com/resources/getting-started-time-series-data-modeling
The insertion is done based on the often mentioned article on lostechies
https://lostechies.com/ryansvihla/2016/04/29/cassandra-batch-loading-without-the-batch%E2%80%8A-%E2%80%8Athe-nuanced-edition/
This is my insertion code:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.ResultSetFuture;
import com.datastax.driver.core.Session;
import com.datastax.driver.extras.codecs.jdk8.InstantCodec;
import com.google.common.base.Stopwatch;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;
public class BulkLoader {
private final int threads;
private final String[] contactHosts;
private final Cluster cluster;
private final Session session;
private final ExecutorService executor;
public BulkLoader(int threads, String... contactHosts) {
this.threads = threads;
this.contactHosts = contactHosts;
this.cluster = Cluster.builder().addContactPoints(contactHosts).build();
cluster.getConfiguration().getCodecRegistry()
.register(InstantCodec.instance);
session = cluster.newSession();
// fixed thread pool that closes on app exit
executor = MoreExecutors
.getExitingExecutorService((ThreadPoolExecutor) Executors
.newFixedThreadPool(threads));
}
public static class IngestCallback implements FutureCallback<ResultSet> {
public void onSuccess(ResultSet result) {
}
public void onFailure(Throwable t) {
throw new RuntimeException(t);
}
}
public void ingest(Iterator<Object[]> boundItemsIterator, String insertCQL)
throws InterruptedException {
final PreparedStatement statement = session.prepare(insertCQL);
while (boundItemsIterator.hasNext()) {
BoundStatement boundStatement = statement.bind(boundItemsIterator
.next());
boundStatement.setConsistencyLevel(ConsistencyLevel.QUORUM);
ResultSetFuture future = session.executeAsync(boundStatement);
Futures.addCallback(future, new IngestCallback(), executor);
}
}
public void stop() {
session.close();
cluster.close();
}
public static List<Object[]> readCSV(File csv) {
BufferedReader fileReader = null;
List<Object[]> result = new LinkedList<Object[]>();
try {
fileReader = new BufferedReader(new FileReader(csv));
String line = "";
while ((line = fileReader.readLine()) != null) {
String[] tokens = line.split(";");
if (tokens.length < 6) {
System.out.println("Unvollständig");
continue;
}
Object[] tmp = new Object[6];
tmp[0] = (int) Integer.parseInt(tokens[0]);
tmp[1] = new BigDecimal(Integer.parseInt(tokens[1]));
tmp[2] = new BigDecimal(Integer.parseInt(tokens[2]));
tmp[3] = new BigDecimal(Integer.parseInt(tokens[2]));
tmp[4] = (float) Float.parseFloat(tokens[4]);
tmp[5] = (float) Float.parseFloat(tokens[5]);
result.add(tmp);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
public static void main(String[] args) {
Stopwatch watch = Stopwatch.createStarted();
File folder = new File(
"C:/VirtualMachines/Kiosk/BachelorarbeitStraubinger/workspace/bulk/src/main/resources");
List<Object[]> data = new LinkedList<Object[]>();
BulkLoader loader = new BulkLoader(16, "10.2.57.38", "10.2.57.37",
"10.2.57.36", "10.2.57.35", "10.2.57.34", "10.2.57.33");
int cnt = 0;
File[] listOfFiles = folder.listFiles();
for (File file : listOfFiles) {
if (file.isFile() && file.getName().contains(".th")) {
data = readCSV(file);
cnt += data.size();
try {
loader.ingest(
data.iterator(),
"INSERT INTO wheather.temp (id, timestamp, validity, structure, temperature, humidity) VALUES(?,?,?,?,?,?)");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(file.getName()
+ " -> Datasets importet: " + cnt);
}
}
}
System.out.println("total time seconds = "
+ watch.elapsed(TimeUnit.SECONDS));
watch.stop();
loader.stop();
}
}
The replication factor is 3 and i run test on 6 or 3 nodes. With vNodes enabled and num_tokens = 256.
I get roughly the same insert times when running it on either cluster. Any ideas why that is?

It is likely that you're maxing out the client application / client server. If you're reading from a static file, you may benefit from breaking it up into a few pieces and running them in parallel, or even looking at Brian Hess' loader ( https://github.com/brianmhess/cassandra-loader ) or the real cassandra bulk loader ( http://www.datastax.com/dev/blog/using-the-cassandra-bulk-loader-updated ) , which turns the data into a series of sstables and streams those in directly. Both are likely faster than your existing code.

Physics.
You're probably maxing out the throughput your app is capable of. Normally the answer would be to have multiple clients/app servers but it looks like you are reading from a CSV. I suggest either cutting up the CSV in pieces and running multiple instances of your app or generate fake data and multiple instances of that.
Edit: I also think it's worth noting that with a data model like that, a payload size that small, and proper hardware, I'd imagine each node could be capable of 15-20K inserts/second (Not accounting for node density/compaction).

Related

Fastest way to return view in customRestService using a bean

I have written a custom rest Service on an Xpage, which is tied to a bean. The Xpage is:
<xe:restService
id="restServiceCustom"
pathInfo="custom"
ignoreRequestParams="false"
state="false"
preventDojoStore="true">
<xe:this.service>
<xe:customRestService
contentType="application/json"
serviceBean="XXXX.PCServiceBean">
</xe:customRestService>
</xe:this.service>
</xe:restService>
I cobbled together my java agent from some excellent posts around the net. I have just started on the GET. My code runs but I it seems pretty slow (on my dev server). I want to make it as fast as possible. I am using a ViewEntryCollection and I am "flushing" at each record which I assume is streaming.
I am putting my own "[" in the code, so I assume that I am not doing something right, as I never saw any examples of anyone else doing this.
Any suggestions would be greatly appreciated.
package com.XXXXX.bean;
import java.io.IOException;
import java.io.Writer;
import java.util.Vector;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.openntf.domino.Database;
import org.openntf.domino.Session;
import org.openntf.domino.View;
import org.openntf.domino.ViewEntry;
import org.openntf.domino.ViewEntryCollection;
import org.openntf.domino.utils.Factory;
import com.ibm.commons.util.io.json.JsonException;
import com.ibm.commons.util.io.json.util.JsonWriter;
import com.ibm.domino.services.ServiceException;
import com.ibm.domino.services.rest.RestServiceEngine;
import com.ibm.xsp.extlib.component.rest.CustomService;
import com.ibm.xsp.extlib.component.rest.CustomServiceBean;
public class PCServiceBean extends CustomServiceBean {
#Override
public void renderService(CustomService service, RestServiceEngine engine) throws ServiceException {
try {
HttpServletRequest request = engine.getHttpRequest();
HttpServletResponse response = engine.getHttpResponse();
response.setHeader("Content-Type", "application/json; charset=UTF-8");
String method = request.getMethod();
if (method.equals("GET")) {
this.doGet(request, response);
} else if (method.equals("POST")) {
this.doPost(request, response);
} else if (method.equals("PUT")) {
this.doPut(request, response);
} else if (method.equals("DELETE")) {
this.doDelete(request, response);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void doDelete(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
}
private void doPut(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
}
private void doPost(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
}
private void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, JsonException {
Session session = Factory.getSession();
Database DB = session.getDatabase(session.getCurrentDatabase().getServer(), "scoApps\\PC\\PCData.nsf");
View pcView = DB.getView("viewAllByStatus");
int i = 1;
Writer out = response.getWriter();
JsonWriter writer = new JsonWriter(out, false);
writer.out("[");
ViewEntryCollection vec = pcView.getAllEntries();
int count = vec.getCount();
for (ViewEntry entry : vec) {
Vector<?> columnValues = entry.getColumnValues();
writer.startObject();
writer.startProperty("unid");
writer.outStringLiteral(String.valueOf(columnValues.get(1)));
writer.endProperty();
writer.startProperty("status");
writer.outStringLiteral(String.valueOf(columnValues.get(0)));
writer.endProperty();
writer.startProperty("assetTag");
writer.outStringLiteral(String.valueOf(columnValues.get(2)));
writer.endProperty();
writer.startProperty("serialNumber");
writer.outStringLiteral(String.valueOf(columnValues.get(3)));
writer.endProperty();
writer.startProperty("model");
writer.outStringLiteral(String.valueOf(columnValues.get(4)));
writer.endProperty();
writer.startProperty("currentLocation");
writer.outStringLiteral(String.valueOf(columnValues.get(5)));
writer.endProperty();
writer.endObject();
if (i != count) {
i = i + 1;
writer.out(",");
writer.flush();
}
}
writer.out("]");
writer.flush();
}
}
Change your code to
JsonWriter writer = new JsonWriter(out, false);
writer.startArray();
ViewEntryCollection vec = pcView.getAllEntries();
int count = vec.getCount();
for (ViewEntry entry : vec) {
Vector<?> columnValues = entry.getColumnValues();
writer.startArrayItem();
writer.startObject();
writer.startProperty("unid");
writer.outStringLiteral(String.valueOf(columnValues.get(1)));
writer.endProperty();
...
writer.endObject();
writer.endArrayItem();
}
writer.endArray();
writer.flush();
It uses JsonWriter's
startArray() and endArray() instead of out("[") and out("]")
startArrayItem() and endArrayItem() instead of out(",") and flush()
The JSON response string gets shorter if you set JsonWriter's compact option to true:
JsonWriter writer = new JsonWriter(out, true);
I see two problems.
First - use ViewNavigator. Here's good explanation of its performance gain.
https://www.mindoo.com/web/blog.nsf/dx/17.01.2013085308KLEB9S.htm
Second - prepare your JSON in advance. This is very good technique to avoid unnecessary code (and time to process it) to get JSON data from Domino documents.
https://quintessens.wordpress.com/2015/09/05/working-with-json-in-your-xpages-application/

Commons Configuration2 ReloadingFileBasedConfiguration

I am trying to implement the Apache Configuration 2 in my codebase
import java.io.File;
import java.util.concurrent.TimeUnit;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.builder.ConfigurationBuilderEvent;
import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder;
import org.apache.commons.configuration2.builder.fluent.Parameters;
import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
import org.apache.commons.configuration2.event.EventListener;
import org.apache.commons.configuration2.ex.ConfigurationException;
import org.apache.commons.configuration2.reloading.PeriodicReloadingTrigger;
import org.apache.commons.configuration2.CompositeConfiguration;
public class Test {
private static final long DELAY_MILLIS = 10 * 60 * 5;
public static void main(String[] args) {
// TODO Auto-generated method stub
CompositeConfiguration compositeConfiguration = new CompositeConfiguration();
PropertiesConfiguration props = null;
try {
props = initPropertiesConfiguration(new File("/tmp/DEV.properties"));
} catch (ConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
compositeConfiguration.addConfiguration( props );
compositeConfiguration.addEventListener(ConfigurationBuilderEvent.ANY,
new EventListener<ConfigurationBuilderEvent>()
{
#Override
public void onEvent(ConfigurationBuilderEvent event)
{
System.out.println("Event:" + event);
}
});
System.out.println(compositeConfiguration.getString("property1"));
try {
Thread.sleep(14*1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Have a script which changes the value of property1 in DEV.properties
System.out.println(compositeConfiguration.getString("property1"));
}
protected static PropertiesConfiguration initPropertiesConfiguration(File propsFile) throws ConfigurationException {
if(propsFile.exists()) {
final ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration> builder =
new ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration>(PropertiesConfiguration.class)
.configure(new Parameters().fileBased()
.setFile(propsFile)
.setReloadingRefreshDelay(DELAY_MILLIS)
.setThrowExceptionOnMissing(false)
.setListDelimiterHandler(new DefaultListDelimiterHandler(';')));
final PropertiesConfiguration propsConfiguration = builder.getConfiguration();
PeriodicReloadingTrigger trigger = new PeriodicReloadingTrigger(builder.getReloadingController(),
null, 1, TimeUnit.SECONDS);
trigger.start();
return propsConfiguration;
} else {
return new PropertiesConfiguration();
}
}
}
Here is a sample code that I using to check whether the Automatic Reloading works or not. However when the underlying property file is updated, the configuration doesn't reflect it.
As per the documentation :
One important point to keep in mind when using this approach to reloading is that reloads are only functional if the builder is used as central component for accessing configuration data. The configuration instance obtained from the builder will not change automagically! So if an application fetches a configuration object from the builder at startup and then uses it throughout its life time, changes on the external configuration file become never visible. The correct approach is to keep a reference to the builder centrally and obtain the configuration from there every time configuration data is needed.
https://commons.apache.org/proper/commons-configuration/userguide/howto_reloading.html#Reloading_File-based_Configurations
This is different from what the old implementation was.
I was able to successfully execute your sample code by making 2 changes :
make the builder available globally and access the configuration from the builder :
System.out.println(builder.getConfiguration().getString("property1"));
add the listener to the builder :
`builder.addEventListener(ConfigurationBuilderEvent.ANY, new EventListener() {
public void onEvent(ConfigurationBuilderEvent event) {
System.out.println("Event:" + event);
}
});
Posting my sample program, where I was able to successfully demonstrate it
import java.io.File;
import java.util.concurrent.TimeUnit;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.builder.ConfigurationBuilderEvent;
import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder;
import org.apache.commons.configuration2.builder.fluent.Parameters;
import org.apache.commons.configuration2.event.EventListener;
import org.apache.commons.configuration2.reloading.PeriodicReloadingTrigger;
public class TestDynamicProps {
public static void main(String[] args) throws Exception {
Parameters params = new Parameters();
ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration> builder =
new ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration>(PropertiesConfiguration.class)
.configure(params.fileBased()
.setFile(new File("src/main/resources/override.properties")));
PeriodicReloadingTrigger trigger = new PeriodicReloadingTrigger(builder.getReloadingController(),
null, 1, TimeUnit.SECONDS);
trigger.start();
builder.addEventListener(ConfigurationBuilderEvent.ANY, new EventListener<ConfigurationBuilderEvent>() {
public void onEvent(ConfigurationBuilderEvent event) {
System.out.println("Event:" + event);
}
});
while (true) {
Thread.sleep(1000);
System.out.println(builder.getConfiguration().getString("property1"));
}
}
}
The problem with your implementation is, that the reloading is done on the ReloadingFileBasedConfigurationBuilder Object and is not being returned to the PropertiesConfiguration Object.

TestNG Close Browsers after Parallel Test Execution

I want to close browsers after completion of all test. Problem is I am not able to close the browser since the object created ThreadLocal driver does not recognize the driver after completion of test value returning is null.
Below is my working code
package demo;
import java.lang.reflect.Method;
import org.openqa.selenium.By;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class ParallelMethodTest {
private static ThreadLocal<dummy> driver;
private int input;
private int length;
#BeforeMethod
public void beforeMethod() {
System.err.println("Before ID" + Thread.currentThread().getId());
System.setProperty("webdriver.chrome.driver", "chromedriver.exe");
if (driver == null) {
driver = new ThreadLocal<dummy>();
}
if (driver.get()== null) {
driver.set(new dummy());
}
}
#DataProvider(name = "sessionDataProvider", parallel = true)
public static Object[][] sessionDataProvider(Method method) {
int len = 12;
Object[][] parameters = new Object[len][2];
for (int i = 0; i < len; i++) {
parameters[i][0] = i;
parameters[i][1]=len;
}
return parameters;
}
#Test(dataProvider = "sessionDataProvider")
public void executSessionOne(int input,int length) {
System.err.println("Test ID---" + Thread.currentThread().getId());
this.input=input;
this.length=length;
// First session of WebDriver
// find user name text box and fill it
System.out.println("Parameter size is:"+length);
driver.get().getDriver().findElement(By.name("q")).sendKeys(input + "");
System.out.println("Input is:"+input);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#AfterMethod
public void afterMethod() {
System.err.println("After ID" + Thread.currentThread().getId());
driver.get().close();
}
}
package demo;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.AfterClass;
public class dummy {
public WebDriver getDriver() {
return newDriver;
}
public void setNewDriver(WebDriver newDriver) {
this.newDriver = newDriver;
}
private WebDriver newDriver;
public dummy() {
newDriver = new ChromeDriver();
newDriver.get("https://www.google.co.in/");
}
#AfterClass
public void close(){
if(newDriver!=null){
System.out.println("In After Class");
newDriver.quit();
}
}
}
Thanks in Advance.
private static ThreadLocal<dummy> driver is added at the class level. What is happening is that you have already declared the variable at class level. i.e. memory is already allocated to it. Multiple threads are just setting and resetting the values of the same variable.
What you need to do is create a factory that will return an instance of Driver based on a parameter you pass to it.Logic can be anything but taking a general use case example the factory will create a new object and return only if an existing object doesn't exist. Declare and initialise the driver (from factory) in your #Test Methods
Sample code for the factory would be something like
static RemoteWebDriver firefoxDriver;
static RemoteWebDriver someOtherDriver;
static synchronized RemoteWebDriver getDriver(String browser, String browserVersion, String platform, String platformVersion)
{
if (browser == 'firefox')
{
if (firefoxDriver == null)
{
DesiredCapabilities cloudCaps = new DesiredCapabilities();
cloudCaps.setCapability("browser", browser);
cloudCaps.setCapability("browser_version", browserVersion);
cloudCaps.setCapability("os", platform);
cloudCaps.setCapability("os_version", platformVersion);
cloudCaps.setCapability("browserstack.debug", "true");
cloudCaps.setCapability("browserstack.local", "true");
firefoxDriver = new RemoteWebDriver(new URL(URL),cloudCaps);
}
}
else
{
if (someOtherDriver == null)
{
DesiredCapabilities cloudCaps = new DesiredCapabilities();
cloudCaps.setCapability("browser", browser);
cloudCaps.setCapability("browser_version", browserVersion);
cloudCaps.setCapability("os", platform);
cloudCaps.setCapability("os_version", platformVersion);
cloudCaps.setCapability("browserstack.debug", "true");
cloudCaps.setCapability("browserstack.local", "true");
someOtherDriver = new RemoteWebDriver(new URL(URL),cloudCaps);
}
return someOtherDriver;
}
You have a concurrency issue: multiple threads can create a ThreadLocal instance because dummy == null can evaluate to true on more than one thread when run in parallel. As such, some threads can execute driver.set(new dummy()); but then another thread replaces driver with a new ThreadLocal instance.
In my experience it is simpler and less error prone to always use ThreadLocal as a static final to ensure that multiple objects can access it (static) and that it is only defined once (final).
You can see my answers to the following Stack Overflow questions for related details and code samples:
How to avoid empty extra browser opens when running parallel tests with TestNG
Session not found exception with Selenium Web driver parallel execution of Data Provider test case
This is happening because you are creating the driver instance in beforeMethod function so it's scope ends after the function ends.
So when your afterMethod start it's getting null because webdriver instance already destroy as beforeMethod function is already completed.
Refer below links:-
http://www.java-made-easy.com/variable-scope.html
What is the default scope of a method in Java?

JavaFX Image Loading in Background and Threads

I thought this would be a simple question but I am having trouble finding an answer. I have a single ImageView object associated with a JavaFX Scene object and I want to load large images in from disk and display them in sequence one after another using the ImageView. I have been trying to find a good way to repeatedly check the Image object and when it is done loading in the background set it to the ImageView and then start loading a new Image object. The code I have come up with (below) works sometimes and sometimes it doesn't. I am pretty sure I am running into issues with JavaFX and threads. It loads the first image sometimes and stops. The variable "processing" is a boolean instance variable in the class.
What is the proper way to load an image in JavaFX in the background and set it to the ImageView after it is done loading?
public void start(Stage primaryStage) {
...
ImageView view = new ImageView();
((Group)scene.getRoot()).getChildren().add(view);
...
Thread th = new Thread(new Thread() {
public void run() {
while(true) {
if (!processing) {
processing = true;
String filename = files[count].toURI().toString();
Image image = new Image(filename,true);
image.progressProperty().addListener(new ChangeListener<Number>() {
#Override public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number progress) {
if ((Double) progress == 1.0) {
if (! image.isError()) {
view.setImage(image);
}
count++;
if (count == files.length) {
count = 0;
}
processing = false;
}
}
});
}
}
}
});
}
I actually think there's probably a better general approach to satisfying whatever your application's requirements are than the approach you are trying to use, but here is my best answer at implementing the approach you describe.
Create a bounded BlockingQueue to hold the images as you load them. The size of the queue may need some tuning: too small and you won't have any "buffer" (so you won't be able to take advantage of any that are faster to load than the average), too large and you might consume too much memory. The BlockingQueue allows you to access it safely from multiple threads.
Create a thread that simply loops and loads each image synchronously, i.e. that thread blocks while each image loads, and deposits them in the BlockingQueue.
Since you want to try to display images up to once per FX frame (i.e. 60fps), use an AnimationTimer. This has a handle method that is invoked on each frame render, on the FX Application Thread, so you can implement it just to poll() the BlockingQueue, and if an image was available, set it in the ImageView.
Here's an SSCCE. I also indicated how to do this where you display each image for a fixed amount of time, as I think that's a more common use case and might help others looking for similar functionality.
import java.io.File;
import java.net.MalformedURLException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javafx.animation.AnimationTimer;
import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
public class ScreenSaver extends Application {
#Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
Button startButton = new Button("Choose image directory...");
startButton.setOnAction(e -> {
DirectoryChooser chooser= new DirectoryChooser();
File dir = chooser.showDialog(primaryStage);
if (dir != null) {
File[] files = Stream.of(dir.listFiles()).filter(file -> {
String fName = file.getAbsolutePath().toLowerCase();
return fName.endsWith(".jpeg") | fName.endsWith(".jpg") | fName.endsWith(".png");
}).collect(Collectors.toList()).toArray(new File[0]);
root.setCenter(createScreenSaver(files));
}
});
root.setCenter(new StackPane(startButton));
primaryStage.setScene(new Scene(root, 800, 800));
primaryStage.show();
}
private Parent createScreenSaver(File[] files) {
ImageView imageView = new ImageView();
Pane pane = new Pane(imageView);
imageView.fitWidthProperty().bind(pane.widthProperty());
imageView.fitHeightProperty().bind(pane.heightProperty());
imageView.setPreserveRatio(true);
Executor exec = Executors.newCachedThreadPool(runnable -> {
Thread t = new Thread(runnable);
t.setDaemon(true);
return t ;
});
final int imageBufferSize = 5 ;
BlockingQueue<Image> imageQueue = new ArrayBlockingQueue<Image>(imageBufferSize);
exec.execute(() -> {
int index = 0 ;
try {
while (true) {
Image image = new Image(files[index].toURI().toURL().toExternalForm(), false);
imageQueue.put(image);
index = (index + 1) % files.length ;
}
} catch (MalformedURLException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
// This will show a new image every single rendering frame, if one is available:
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
Image image = imageQueue.poll();
if (image != null) {
imageView.setImage(image);
}
}
};
timer.start();
// This wait for an image to become available, then show it for a fixed amount of time,
// before attempting to load the next one:
// Duration displayTime = Duration.seconds(1);
// PauseTransition pause = new PauseTransition(displayTime);
// pause.setOnFinished(e -> exec.execute(createImageDisplayTask(pause, imageQueue, imageView)));
// exec.execute(createImageDisplayTask(pause, imageQueue, imageView));
return pane ;
}
private Task<Image> createImageDisplayTask(PauseTransition pause, BlockingQueue<Image> imageQueue, ImageView imageView) {
Task<Image> imageDisplayTask = new Task<Image>() {
#Override
public Image call() throws InterruptedException {
return imageQueue.take();
}
};
imageDisplayTask.setOnSucceeded(e -> {
imageView.setImage(imageDisplayTask.getValue());
pause.playFromStart();
});
return imageDisplayTask ;
}
public static void main(String[] args) {
launch(args);
}
}

Adding gauge in location finder class in j2me

I am working on a j2me application which contain a class to find the location of mobile using GPS.I need to include gauge while the location provider API is called and it finds the location.I am new to j2me so still not clear with all the concepts.I am pasting my code below.Please help me through this.Thanks in advance..
package org.ets.utils;
import javax.microedition.lcdui.*;
import javax.microedition.location.*;
import javax.microedition.io.*;
import java.io.*;
import org.ets.midlet.ETS_infozech;
import javax.microedition.midlet.*;
public class Locfinder {
public Locfinder(ETS_infozech midlet)
{
this.midlet = midlet;
}
public static String ex()
{
try {
checkLocation();
} catch (Exception ex)
{
ex.printStackTrace();
}
//System.out.println(string);
return string;
}
public static void checkLocation() throws Exception
{
Location l;
LocationProvider lp;
Coordinates c;
// Set criteria for selecting a location provider:
// accurate to 500 meters horizontally
Criteria cr= new Criteria();
cr.setHorizontalAccuracy(500);
// Get an instance of the provider
lp= LocationProvider.getInstance(cr);
//Request the location, setting a one-minute timeout
l = lp.getLocation(60);
c = l.getQualifiedCoordinates();
if(c != null ) {
// Use coordinate information
double lat = c.getLatitude();
double lon = c.getLongitude();
string = " LAT-" + lat + " LONG-" + lon;
}
}
}
There's no way you can link a Gauge to some task.
You have to set values to the Gauge manually. So you'd create a Gauge and add it to your Form. Then start your code to perform the look-up.
In between your lines of code, you'd add myGauge.setValue(some_value); to increase the indicator.
Of course, this becomes difficult when most of the task is contained in a single line of code, like e.g. lp.getLocation(60);.
I think, in that case, I would create a Thread that automatically increases the value on the Gauge in the 60 seconds, but can be stopped/overridden by a manual setting.
class Autoincrementer implements Runnable {
private boolean running;
private Gauge gauge;
private int seconds;
private int secondsElapsed;
public Autoincrementer(Gauge gauge) {
this.gauge = gauge;
this.seconds = gauge.getMaxValue();
this.running = true;
this.secondsElapsed = 0;
}
public void run() {
if (running) {
secondsElapsed++;
gauge.setValue(secondsElapsed);
if (secondsElapsed>=gauge.getMaxValue()) running = false; // Stop the auto incrementing
try {
Thread.sleep(1000); // Sleep for 1 second
} catch (Exception e) {}
}
}
public void stop() {
running = false;
}
}
You would then create a Gauge and add it to your Form
myGauge = new Gauge("Process", false, 60, 0);
myForm.append(myGauge);
Then start the auto-increment.
myIncrementer = new Autoincrementer(myGauge);
new Thread(myIncrementer).start();
And then call your look-up code.
checkLocation();
Inside your look-up code, add code to stop the auto-incrementing and set the Gauge object to 100%, if the look-up was successful (meaning before the timeout).
myIncrementer.stop();
myGauge.setValue(60);
LWUIT 1.5 can help you in this. Am not sure for Location API which you are using.
But you will get Gauge using LWUIT 1.5. Use Lwuit instead of LCDUI.
http://www.oracle.com/technetwork/java/javame/javamobile/download/lwuit/index.html

Resources