Fetching Parse objects into Arraylist using AsyncTask - android-fragments

I am trying to fetch bunch of parse objects into an Arraylist based on descending order of "createdAt". I am using fragments in my app, which has a fragment called "Recents".
Initially, I was able to store the data in a hashmap and add each of them to the array list and display them as a listview. I was able to see the list on my recents tab.
But, I realized it shouldnt be running on the main thread, so I found Async Task and i tried to implement the same. But I am unable to view any Listview on my screen.
Code for AsyncTask:
package com.astuetz.viewpager.extensions.sample;
/**
* Created by Shankar S on 10-06-15.
*/
import android.os.AsyncTask;
import com.parse.FindCallback;
import com.parse.ParseException;
import com.parse.ParseObject;
import com.parse.ParseQuery;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class getBooks extends AsyncTask<String, Void, ArrayList<HashMap<String, String>>> {
RecentsCardFragment container;
public getBooks(RecentsCardFragment f){
this.container = f;
}
#Override
protected ArrayList<HashMap<String, String>> doInBackground(String... params) {
final ArrayList<HashMap<String, String>> book_items = new ArrayList<>();
try {
ParseQuery<ParseObject> query = ParseQuery.getQuery(params[0]);//params[0] refers to the class name(a String) from which
query.orderByDescending("createdAt"); //parse object is to be queried. In our case, it is "Posted"
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> parseObjects, ParseException e) {
if (e == null) {
for (ParseObject book : parseObjects) {
HashMap<String, String> test = new HashMap<>();
String dept = book.getString("Department");
String title = book.getString("Title");
String author = book.getString("Author");
Number price_num = book.getNumber("Price");
String price = String.valueOf(price_num);
String place = book.getString("Place");
String desp = book.getString("Description");
test.put("dept", dept);
test.put("title", title);
test.put("author", author);
test.put("price", price);
test.put("place", place);
test.put("description", desp);
book_items.add(test);
}
}
}
});
} catch (Exception ex) {
}
return book_items;
}
#Override
protected void onPreExecute(){
super.onPreExecute();
container.showProgress();
}
#Override
protected void onPostExecute(ArrayList<HashMap<String, String>> books) {
super.onPreExecute();
if(RecentsCardFragment.items.size()>0)
{
RecentsCardFragment.items.clear();
}
RecentsCardFragment.items.addAll(books);
container.hideProgress();
}
}
and the code for RecentsFragment:
/*
* Copyright (C) 2013 Andreas Stuetz <andreas.stuetz#gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.astuetz.viewpager.extensions.sample;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewCompat;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.ListView;
import android.os.AsyncTask;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class RecentsCardFragment extends Fragment
{
ListView recentsList;
getBooks task;
private ProgressDialog pdia;
/*
array list of hashmaps that's going to hold all the data
fetch the data from parse and load it onto this
Each hashmap represents one post.
*/
static ArrayList<HashMap<String,String>> items = new ArrayList<>();
protected void startBookfetch()
{
task = new getBooks(this);
task.execute("Posted");
}
//sample hashmaps
HashMap<String,String> test1 = new HashMap<>();
HashMap<String,String> test2 = new HashMap<>();
public void showProgress()
{
pdia = new ProgressDialog(getActivity());
pdia.setMessage("Loading...");
pdia.show();
}
public void hideProgress(){
pdia.dismiss();
}
public static RecentsCardFragment newInstance() {
RecentsCardFragment f = new RecentsCardFragment();
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.recents_card,container,false);
ViewCompat.setElevation(rootView,50);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
recentsList = (ListView)getActivity().findViewById(R.id.recents_list);
startBookfetch();//Calls the async task getBooks to download books from Parse
RecentsAdapter adapter = new RecentsAdapter(getActivity().getApplicationContext(), items);
recentsList.setAdapter(adapter);
}
}
Please help me out! I am not able to view progress Dialog or the listview.
I want the async task to be run when activity is created, not on any button click.
I am trying async task for the first time.

I just realized that I dont need to async task for a task that is already being handled at background. The findinBackground method I use for querying data from Parse already does the task in background only. So, this is absolutely not necessary.
I need to keep the code same as it was earlier.

Related

Test a Reactive-Kafka Consumer and Producer Template using embedded kafka + custom serialised

We need an example on how to test ReactiveKafkaConsumerTemplate and ReactiveKafkaProducerTemplate with an embedded-kafka-broker. Thanks.
CORRECT CODE IS HERE AFTR DISCUSSION
You can have your custom de-serializer accordingly to use custom ReactiveKafkaConsumerTemplate
Custom Serialiser:
import org.apache.kafka.common.serialization.Serializer;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class EmployeeSerializer implements Serializer<Employee> {
#Override
public byte[] serialize(String topic, Employee data) {
byte[] rb = null;
ObjectMapper mapper = new ObjectMapper();
try {
rb = mapper.writeValueAsString(data).getBytes();
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return rb;
}
}
Use it part of embedded-kfka-reactive test:
import java.util.Map;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.connect.json.JsonSerializer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.kafka.core.reactive.ReactiveKafkaProducerTemplate;
import org.springframework.kafka.support.converter.MessagingMessageConverter;
import org.springframework.kafka.test.condition.EmbeddedKafkaCondition;
import org.springframework.kafka.test.context.EmbeddedKafka;
import org.springframework.kafka.test.utils.KafkaTestUtils;
import reactor.kafka.sender.SenderOptions;
import reactor.kafka.sender.SenderRecord;
import reactor.test.StepVerifier;
#EmbeddedKafka(topics = EmbeddedKafkareactiveTest.REACTIVE_INT_KEY_TOPIC,
brokerProperties = { "transaction.state.log.replication.factor=1", "transaction.state.log.min.isr=1" })
public class EmbeddedKafkareactiveTest {
public static final String REACTIVE_INT_KEY_TOPIC = "reactive_int_key_topic";
private static final Integer DEFAULT_KEY = 1;
private static final String DEFAULT_VERIFY_TIMEOUT = null;
private ReactiveKafkaProducerTemplate<Integer, Employee> reactiveKafkaProducerTemplate;
#BeforeEach
public void setUp() {
reactiveKafkaProducerTemplate = new ReactiveKafkaProducerTemplate<>(setupSenderOptionsWithDefaultTopic(),
new MessagingMessageConverter());
}
private SenderOptions<Integer, Employee> setupSenderOptionsWithDefaultTopic() {
Map<String, Object> senderProps = KafkaTestUtils
.producerProps(EmbeddedKafkaCondition.getBroker().getBrokersAsString());
SenderOptions<Integer, Employee> senderOptions = SenderOptions.create(senderProps);
senderOptions = senderOptions.producerProperty(ProducerConfig.TRANSACTIONAL_ID_CONFIG, "reactive.transaction")
.producerProperty(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true)
.producerProperty(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class.getName())
;
return senderOptions;
}
#Test
public void test_When_Publish() {
Employee employee = new Employee();
ProducerRecord<Integer, Employee> producerRecord = new ProducerRecord<Integer, Employee>(REACTIVE_INT_KEY_TOPIC, DEFAULT_KEY, employee);
StepVerifier.create(reactiveKafkaProducerTemplate.send(producerRecord)
.then())
.expectComplete()
.verify();
}
#AfterEach
public void tearDown() {
reactiveKafkaProducerTemplate.close();
}
}
The tests in the framework use an embedded kafka broker.
https://github.com/spring-projects/spring-kafka/tree/main/spring-kafka/src/test/java/org/springframework/kafka/core/reactive
#EmbeddedKafka(topics = ReactiveKafkaProducerTemplateIntegrationTests.REACTIVE_INT_KEY_TOPIC, partitions = 2)
public class ReactiveKafkaProducerTemplateIntegrationTests {
...
added correct serialised with a non-transactional producer. please see the code on top of this page for the answer.

SharedPreferences within a fragment

Once the user selects an item from a list in another fragment it brings you to this fragment. And I'm having issues trying to save the users rating that was selected. when the user goes back it should be the same rating that was previously selected.
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RatingBar;
import android.widget.TextView;
import java.util.Arrays;
public class infoFragment extends Fragment {
TextView degrees;
ImageView image;
String stringtext;
String [] hold;
private RatingBar rating;
SharedPreferences wmbPreference1;
SharedPreferences.Editor editor;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.info_layout, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState){
image = (ImageView) view.findViewById(R.id.imageView);
why can i not use "this"
rating =((RatingBar) view.findViewById(R.id.ratingBar)).setOnRatingBarChangeListener(this);
wmbPreference1 = PreferenceManager.getDefaultSharedPreferences(this);
degrees =(TextView)view.findViewById(R.id.textView);
}
public void onRatingChanged(RatingBar ratingBar, float rating,
boolean fromTouch) {
final int numStars = ratingBar.getNumStars();
editor = wmbPreference1.edit();
editor.putInt("numStars", numStars);
editor.commit();
int ratings = wmbPreference1.getInt("numStars", 0);
}
public void setText(final String string) {
Character[] hold;
if(string == "apple"){
String[] word = { " A \n", "B\n" };
degrees.setText(Arrays.toString(word).replaceAll("\\[|\\]", ""));;
image.setImageResource(R.drawable.APPLE);
}
Should I call onRatingChanged within the conditional statement for it to save?
if(string == "orange"){
String[] word = { " AA\n", "AB\n" };
degrees.setText(Arrays.toString(word).replaceAll("\\[|\\]", ""));;
image.setImageResource(R.drawable.bruce);
}
}
public void sentText(){
new MyTask().execute();
}
private class MyTask extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... strings) {
Bundle b = getArguments();
stringtext = b.getString("text");
return null;
}
protected void onPostExecute(String result){setText(stringtext);
}
}
}
Your Fragment should implement OnRatingBarChangeListener:
public class infoFragment extends Fragment implements OnRatingBarChangeListener
The other thing is that setOnRatingChangeListener does not return a value, so you can't assign the return value to rating as you did.
You should do:
rating = (RatingBar) view.findViewById(R.id.ratingBar);
rating.setOnRatingBarChangeListener(this);

JavaFX TableView: copy text as rendered in cell

I want to implement copy functionality in a TableView. The text to be copied should be the actual text that is rendered in the cell, not the .toString version of the data model to be rendered, that is, it should be the .getText of the cell.
There are several ways of getting the data from a cell. However to get the rendered cell text contents, the procedure seems to be like this:
Get the cell data.
Get the cell factory.
Use the factory to create a cell.
Use the cell's updateItem method to render the data, then getText to get the rendered text.
The last step is not possible due to updateItem being protected.
How can I access the rendered text of any given cell in a TableView?
The process you outline involves getting the text (i.e. data) from the view (the cell), which violates the principles behind the MVC/MVP design. From a practical perspective, it involves creating UI elements (which are expensive to create) to essentially manipulate data (which is typically much less expensive to create and process). Additionally, depending on exactly what you're doing, the UI elements may impose additional threading constraints on your code (as they are essentially single-threaded).
If you need to use the "formatting text" functionality outside of the cell, you should factor it out elsewhere and reuse it in both the "copy" functionality you need and in the cell. At a minimum, this could be done by making the "format text" functionality part of the cell factory:
import java.util.function.Function;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;
public class FormattingTableCellFactory<S, T> implements Callback<TableColumn<S, T>, TableCell<S, T>> {
private final Function<T, String> formatter ;
public FormattingTableCellFactory(Function<T, String> formatter) {
this.formatter = formatter ;
}
public FormattingTableCellFactory() {
this(T::toString);
}
public final Function<T, String> getFormatter() {
return formatter ;
}
#Override
public TableCell<S,T> call(TableColumn<S,T> col) {
return new TableCell<S,T>() {
#Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
setText(item == null ? null : formatter.apply(item));
}
};
}
}
(Obviously you could extend this to produce more sophisticated cells with graphical content, etc.)
And now your copy functionality can simply apply the formatter to the data, without reference to any actual cells. Here's a SSCCE:
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Function;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
private String copy(TableView<Product> table) {
StringBuilder sb = new StringBuilder();
for (Product p : table.getSelectionModel().getSelectedItems()) {
List<String> data = new ArrayList<>();
for (TableColumn<Product, ?> column : table.getColumns()) {
Function<Object, String> formatter = ((FormattingTableCellFactory) column.getCellFactory()).getFormatter();
data.add(formatter.apply(column.getCellObservableValue(p).getValue()));
}
sb.append(String.join("\t", data)).append("\n");
}
return sb.toString() ;
}
#Override
public void start(Stage primaryStage) {
TableView<Product> table = new TableView<>();
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
table.getColumns().add(column("Product", Product::nameProperty, String::toString));
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance();
table.getColumns().add(column("Price", Product::priceProperty, currencyFormat::format));
Random rng = new Random();
for (int i = 1; i <= 100; i++) {
table.getItems().add(new Product("Product "+i, rng.nextDouble()*100));
}
Button copy = new Button("Copy");
copy.setOnAction(e -> System.out.println(copy(table)));
copy.disableProperty().bind(Bindings.isEmpty(table.getSelectionModel().getSelectedItems()));
BorderPane root = new BorderPane(table);
BorderPane.setAlignment(copy, Pos.CENTER);
BorderPane.setMargin(copy, new Insets(10));
root.setBottom(copy);
Scene scene = new Scene(root, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private static <S,T> TableColumn<S,T> column(String title, Function<S,ObservableValue<T>> property, Function<T,String> formatter) {
TableColumn<S,T> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
col.setCellFactory(new FormattingTableCellFactory<>(formatter));
return col ;
}
public static class Product {
private final StringProperty name = new SimpleStringProperty();
private final DoubleProperty price = new SimpleDoubleProperty() ;
public Product(String name, double price) {
setName(name);
setPrice(price);
}
public final StringProperty nameProperty() {
return this.name;
}
public final String getName() {
return this.nameProperty().get();
}
public final void setName(final String name) {
this.nameProperty().set(name);
}
public final DoubleProperty priceProperty() {
return this.price;
}
public final double getPrice() {
return this.priceProperty().get();
}
public final void setPrice(final double price) {
this.priceProperty().set(price);
}
}
public static void main(String[] args) {
launch(args);
}
}
You can get rid of the less typesafe code at the expense of less flexibility:
private final Function<String, String> defaultFormatter = Function.identity() ;
private final Function<Number, String> priceFormatter = DecimalFormat.getCurrencyInstance()::format ;
private String copy(TableView<Product> table) {
return table.getSelectionModel().getSelectedItems().stream().map(product ->
String.format("%s\t%s",
defaultFormatter.apply(product.getName()),
priceFormatter.apply(product.getPrice()))
).collect(Collectors.joining("\n"));
}
and
table.getColumns().add(column("Product", Product::nameProperty, defaultFormatter));
table.getColumns().add(column("Price", Product::priceProperty, priceFormatter));

Populate TableView with ObservableMap JavaFX

I wanted to know if it is possible to use a ObservableMap to populate a TableView ?
I use ObservableMap instead of ObservableList because I need to add and delete often, so I need to minimize the cost.
My hashMap use an BigInteger as key field and a type with many properties as value field.
In my tableView I just want to display the values with a column per properties. I hope that is clear
Thanks
I've been trying to do this. I guess the post is old but I don't see any answers anywhere on the net. The examples use the map key for columns and then a list of maps for every row. I'd like to see the rows as keys and their associated values. It's a long example.
package tablemap;
import static java.lang.Math.random;
import java.util.Map;
import java.util.TreeMap;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TableMap extends Application {
#Override
public void start(Stage primaryStage) {
VBox root = new VBox();
Map<String,LineItem> mapData = new TreeMap<>();
for (int i = 0; i < 3; i++)
mapData.put(String.valueOf(random()), new LineItem(String.valueOf(i),"i"));
ObservableList<Map.Entry<String,LineItem>> listData =
FXCollections.observableArrayList(mapData.entrySet());
TableView<Map.Entry<String,LineItem>> tv = new TableView(listData);
TableColumn<Map.Entry<String,LineItem>,String> keyCol = new TableColumn("Key");
keyCol.setCellValueFactory(
(TableColumn.CellDataFeatures<Map.Entry<String,LineItem>, String> p) ->
new SimpleStringProperty(p.getValue().getKey()));
TableColumn<Map.Entry<String,LineItem>,String> lineNoCol = new TableColumn("Line No");
lineNoCol.setCellValueFactory(
(TableColumn.CellDataFeatures<Map.Entry<String,LineItem>, String> p) ->
new SimpleStringProperty(p.getValue().getValue().getLineNo()));
TableColumn<Map.Entry<String,LineItem>,String> descCol = new TableColumn("Desc");
descCol.setCellValueFactory(
(TableColumn.CellDataFeatures<Map.Entry<String,LineItem>, String> p) ->
new SimpleStringProperty(p.getValue().getValue().getDesc()));
descCol.setCellFactory(TextFieldTableCell.forTableColumn());
descCol.setOnEditCommit((CellEditEvent<Map.Entry<String,LineItem>, String> t) -> {
t.getTableView().getItems().get(t.getTablePosition().getRow())
.getValue().setDesc(t.getNewValue());
});
tv.getColumns().addAll(keyCol,lineNoCol, descCol);
tv.setEditable(true);
tv.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
Button btnOut = new Button("out");
btnOut.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
for (Map.Entry<String,LineItem> me : mapData.entrySet()){
System.out.println("key "+me.getKey()+" entry "+me.getValue().toCSVString());
}
for (Map.Entry<String,LineItem> me : listData){
System.out.println("key "+me.getKey()+" entry "+me.getValue().toCSVString());
}
}
});
root.getChildren().addAll(tv,btnOut);
Scene scene = new Scene(root, 300, 200);
primaryStage.setTitle("Map Table Test");
primaryStage.setScene(scene);
primaryStage.show();
}
}
And the LineItem Class Code
package tablemap;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
/* LineItem class */
public class LineItem {
private final StringProperty lineNo = new SimpleStringProperty();
private final StringProperty desc = new SimpleStringProperty();
public LineItem(String ln, String dsc) {
lineNo.set(ln); desc.set(dsc);
}
public String getLineNo() {return (lineNo.getValue() != null) ?lineNo.get():"";}
public void setLineNo(String lineNo) {this.lineNo.set(lineNo);}
public StringProperty lineNoProperty() {return lineNo;}
public String getDesc() {return (desc.getValue() != null) ?desc.get():"";}
public void setDesc(String desc) {this.desc.set(desc);}
public StringProperty descProperty() {return desc;}
public String toCSVString(){
return lineNo.getValueSafe()+","+
desc.getValueSafe()+"\n";
}
}
You can see after editing data and clicking out that changes in the list are reflected in the map. I still have to check the other way and handle insertions and deletions but that shouldn't be to hard.
I packaged up my Map Table listeners in a subclass of TableView.
package tablemap;
import java.util.AbstractMap;
import java.util.Map;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.MapChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.ObservableMap;
import javafx.scene.control.TableView;
public class MapTableView<K,V> extends TableView<Map.Entry<K,V>>{
private final ObservableList<Map.Entry<K,V>> obsList;
private final ObservableMap<K,V> map;
private final MapChangeListener<K,V> mapChange;
private final ListChangeListener<Map.Entry<K,V>> listChange;
public MapTableView(ObservableMap<K,V> map) {
this.map = map;
obsList = FXCollections.observableArrayList(map.entrySet());
setItems(obsList);
mapChange = new MapChangeListener<K, V>() {
#Override
public void onChanged(MapChangeListener.Change<? extends K, ? extends V> change) {
obsList.removeListener(listChange);
if (change.wasAdded())
obsList.add(new AbstractMap.SimpleEntry(change.getKey(),change.getValueAdded()));
if (change.wasRemoved()){
//obsList.remove(new AbstractMap.SimpleEntry(change.getKey(),change.getValueRemoved()));
// ^ doesn't work always, use loop instead
for (Map.Entry<K,V> me : obsList){
if (me.getKey().equals(change.getKey())){
obsList.remove(me);
break;
}
}
}
obsList.addListener(listChange);
}
};
listChange = (ListChangeListener.Change<? extends Map.Entry<K, V>> change) -> {
map.removeListener(mapChange);
while (change.next()){
//maybe check for uniqueness here
if (change.wasAdded()) for (Map.Entry<K, V> me: change.getAddedSubList())
map.put(me.getKey(),me.getValue());
if (change.wasRemoved()) for (Map.Entry<K, V> me: change.getRemoved())
map.remove(me.getKey());
}
map.addListener(mapChange);
};
map.addListener(mapChange);
obsList.addListener(listChange);
}
//adding to list should be unique
public void addUnique(K key, V value){
boolean isFound = false;
//if a duplicate key just change the value
for (Map.Entry<K,V> me : getItems()){
if (me.getKey().equals(key)){
isFound = true;
me.setValue(value);
break;//only first match
}
}
if (!isFound) // add new entry
getItems().add(new AbstractMap.SimpleEntry<>(key,value));
}
//for doing lenghty map operations
public void removeMapListener(){
map.removeListener(mapChange);
}
//for resyncing list to map after many changes
public void resetMapListener(){
obsList.removeListener(listChange);
obsList.clear();
obsList.addAll(map.entrySet());
obsList.addListener(listChange);
map.addListener(mapChange);
}
}
It seems to work so far. I create with the following code :
final ObservableMap<String, LineItem> obsMap = FXCollections.observableHashMap();
final MapTableView<String,LineItem> mtv = new MapTableView(obsMap);
You can even edit the keys.
final TableColumn<Map.Entry<String,LineItem>,String> keyCol = new TableColumn("Key");
keyCol.setCellValueFactory(
(TableColumn.CellDataFeatures<Map.Entry<String,LineItem>, String> p) ->
new SimpleStringProperty(p.getValue().getKey()));
keyCol.setCellFactory(TextFieldTableCell.forTableColumn());
keyCol.setOnEditCommit((CellEditEvent<Map.Entry<String,LineItem>, String> t) -> {
final String oldKey = t.getOldValue();
final LineItem oldLineItem = obsMap.get(oldKey);
obsMap.remove(oldKey);//should remove from list but maybe doesn't always
obsMap.put(t.getNewValue(),oldLineItem);
});
You can see I added a method to remove and re add the map listeners. To add and remove 100k entries takes .65 secs w/out listeners and 5.2 secs with them.
Here's the whole thing in one file on pastebin. http://pastebin.com/NmdTURFt

Webdriver PageObject Implementation using PageFactory in Java

here is what i have so far:
A working Webdriver based Java class, which logs-in to the application and goes to a Home page:
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;
import org.testng.AssertJUnit;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class MLoginFFTest {
private WebDriver driver;
private String baseUrl;
private String fileName = "screenshot.png";
#BeforeMethod
public void setUp() throws Exception {
FirefoxProfile profile = new FirefoxProfile();
profile.setPreference("network.http.phishy-userpass-length", 255);
profile.setAssumeUntrustedCertificateIssuer(false);
driver = new FirefoxDriver(profile);
baseUrl = "https://a.b.c.d/";
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
#Test
public void testAccountLogin() throws Exception {
driver.get(baseUrl + "web/certLogon.jsp");
driver.findElement(By.name("logonName")).clear();
AssertJUnit.assertEquals(driver.findElement(By.name("logonName"))
.getTagName(), "input");
AssertJUnit.assertEquals(driver.getTitle(), "DA Logon");
driver.findElement(By.name("logonName")).sendKeys("username");
driver.findElement(By.name("password")).clear();
driver.findElement(By.name("password")).sendKeys("password");
driver.findElement(By.name("submit")).click();
driver.findElement(By.linkText("Account")).click();
AssertJUnit.assertEquals(driver.getTitle(), "View Account");
}
#AfterMethod
public void tearDown() throws Exception {
File screenshot = ((TakesScreenshot) driver)
.getScreenshotAs(OutputType.FILE);
try {
FileUtils.copyFile(screenshot, new File(fileName));
} catch (IOException e) {
e.printStackTrace();
}
driver.quit();
}
}
Now as we see there are 2 pages:
1. Login page, where i have to enter username and password, and homepage, where i would be taken, once the authentication succeeds.
Now i want to implement this as PageObjects using Pagefactory: so i have :
package com.example.pageobjects;
import static com.example.setup.SeleniumDriver.getDriver;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;
public abstract class MPage<T> {
private static final String BASE_URL = "https://a.b.c.d/";
private static final int LOAD_TIMEOUT = 30;
private static final int REFRESH_RATE = 2;
public T openPage(Class<T> clazz) {
T page = PageFactory.initElements(getDriver(), clazz);
getDriver().get(BASE_URL + getPageUrl());
ExpectedCondition pageLoadCondition = ((MPage) page).getPageLoadCondition();
waitForPageToLoad(pageLoadCondition);
return page;
}
private void waitForPageToLoad(ExpectedCondition pageLoadCondition) {
Wait wait = new FluentWait(getDriver())
.withTimeout(LOAD_TIMEOUT, TimeUnit.SECONDS)
.pollingEvery(REFRESH_RATE, TimeUnit.SECONDS);
wait.until(pageLoadCondition);
}
/**
* Provides condition when page can be considered as fully loaded.
*
* #return
*/
protected abstract ExpectedCondition getPageLoadCondition();
/**
* Provides page relative URL/
*
* #return
*/
public abstract String getPageUrl();
}
And for login Page not sure how i would implement that, as well as the Test, which would call these pages.
I hope these links will be helpful:
page objects in webdriver
page object using jBehave
I would recommend having one class responsible for before/after methods and they should be than called before and after whole scenario. Right now you would close webdriver just after logging in to your page and I guess this is not desired beahaviour. You can extract one level of abstraction simply for Pages where all the clicking happens (right now your MLoginFFTest class does logging in) for both login page and main page.
Now the other class would simply run methods from your Pages calsses like this:
#Test
public void shouldOpenMainPage(){
LoginPage loginPage = new LoginPage();
MainPage mainPage = loginPage.loginCorrectly();
mainPage.verifyOnMainPage();
mainPage.doSthElse();
verifySth(....);
}
So now your file structure could be sth like
++pages/LoginPage.class
++pages/MainPage.class
++steps/SomeTest.class
Hope this helps.

Resources