How to add linked list into table view in java, and how to correctly pass values from class(controller) to another class(controller) - linked-list

I am creating a page (in JavaFX) and wanted to show the contents of the table in the Sqlite database that are stored as LinkedList<> in a code, in my JavaFx I have created TableView that's structure is identical to the ones that in database.
So here is my code:
#FXML
private TableView<Question> tableview;
#FXML
private TableColumn<Question, String> id;
#FXML
private TableColumn<Question, String> question;
LinkedList<Question> all = new LinkedList<Question>();
try {
//list_of_questions();
all = ConnectionProvider.allQuestions();
} catch (SQLException e) {
e.printStackTrace();
}
id.setCellValueFactory(new PropertyValueFactory<>("id"));
question.setCellValueFactory(new PropertyValueFactory<>("name"));
list.addAll(all);
tableview.setItems(list);
Here, method allQuestions of class ConnectionProvider returns LinkedList with data from the table in the database
So, I just want it to be visible in table-view
And also, I wanted to pass the value (quizId) from the previous page to the current page and am not sure how to do this, maybe I should use the constructors

Related

How to fix object set in grid?

In my application i have a class like:
public class Team {
private Country teamId;
private Set<Player> playerSet;
private Set<Player> substitutes;
private Set<Coach> coachSet;
}
When i instantiate a grid like:
Grid<Team> grid = new Grid<>(Team.class);
and set allTeam() from database it shows object for playerSet and coachSet.
My question is i just want to show players name and coach name concate by ,or \n.
Any idea how can i do that?As a beginner it is complicated for me
I see three options.
The first option is the one you already found yourself: concatenate their names in a single String. This can be done like this:
grid.addColumn(team -> {
Set<String> coachNames = new HashSet<>();
for (Coach coach : team.getCoaches()){
coachNames.add(coach.getName());
}
return String.join(", ", coachNames);
});
The second one would be to make use of the Grid item Detail - you could show a coaches grid in the item details. Since you want to display both coaches and players, this option is probably not the best but I wanted to mention the possibility. (Placing two grids inside the item details is possible, but quite strange. Not optimal user experience.)
grid.setItemDetailsRenderer(new ComponentRenderer<>(team -> {
Grid<Coach> coachGrid = new Grid<>(Coach.class);
coachGrid.setItems(team.getCoaches());
return coachGrid;
}));
A third option would be to have the team grid on one side of the view, and on the other you show some relevant stuff of the selected item of the team grid. You can have a separate Grid for the coaches, one for the players, one for the substitutes. You could implement this team detail layout also as a separate view if you wish. If your Team object will get more complicated with more sets, collections and other relative properties, the more will this option become appealing, as this is quite scalable/expandable.
grid.addSelectionListener(event -> {
if(event.getFirstSelectedItem().isPresent()){
buildTeamDetails(event.getFirstSelectedItem().get())
}
})
private void buildTeamDetails(Team team){
// build your team detail layouts here
}
You can configure which columns are shown in the grid by using grid.removeAllColumns() and then adding all columns you want to have in the grid with grid.addColumn(). Within addColumn() you can create a renderer that defines how the fields (coachName and playerSet) are displayed in the grid.
Let's have a class Team like
public class Team {
private String coachName;
private Set<Player> playerSet;
private Set<Object> objects;
//getters and setters
}
and a class Player like
public class Player {
private String firstName;
private String lastName;
// getters and setters
}
Now you want to only have coach and player names in the grid. So (in my example) for coachName we can just use the field's getter and we can create a comma separated String for the playerSet with java streams easily.
Configure the grid like:
grid.setItems(team);
grid.removeAllColumns();
grid.addColumn(new TextRenderer<>((ItemLabelGenerator<Team>) Team::getCoachName))
.setHeader("Coach");
grid.addColumn(new TextRenderer<>((ItemLabelGenerator<Team>) team1 -> team1.getPlayerSet().stream()
.map(player1 -> player1.getFirstName() + " " + player1.getLastName())
.collect(Collectors.joining(", "))))
.setHeader("Players")
.setFlexGrow(1);
Then the result looks like:

vaadin 10 - Push - Label won't update

MainView include InformationCOmponent:
#Push
#Route
public class MainView extends VerticalLayout {
InformationComponent infoComponent;
public MainView(#Autowired StudentRepository studentRepo, #Autowired Job jobImportCsv, #Autowired JobLauncher jobLauncher, #Value("${file.local-tmp-file}") String inputFile) {
[...] // some stuffs
infoComponent = new InformationComponent(studentRepo);
add(infoComponent);
}
//update when job process is over
private void uploadFileSuccceed() {
infoComponent.update(myUploadComponent.getFile());
}
InformationComponent:
public class InformationComponent extends HorizontalLayout {
StudentRepository studentRepo;
Label nbLineInFile = new Label();
VerticalLayout componentLeft = new VerticalLayout();;
VerticalLayout componentRight = new VerticalLayout();;
public InformationComponent(StudentRepository studentRepo) {
[...] // some init and style stuff
addLine("Nombre de lignes dans le fichier", nbLineInFile);
}
private void addLine(String label, Label value) {
componentLeft.add(new Label(label));
componentRight.add(value);
}
public void update(File file) {
try {
long nbLines = Files.lines(file.toPath(), Charset.defaultCharset()).count();
System.out.println("UPDATED! " +nbLines); // value is display in console ok!
UI.getCurrent().access(() -> nbLineInFile.setText(nbLines)); // UI is not updated!!
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
When I call InformationComponent from MainView the Label is not update in the browser.
UI.getCurrent().access(() -> nbLineInFile.setText(nbLines))
also try wwith #Push(PushMode.MANUAL) and ui.push(); but doesn't work either...
Complete source code is here: https://github.com/Tyvain/ProcessUploadedFile-Vaadin_SpringBatch/tree/push-not-working
I suspect the problem here is that uploadFileSuccceed() is run from a background thread, in which case UI.getCurrent() will return null. This would cause a NullPointerException that either kills the background thread or alternatively the exception is caught and silently ignored by the caller. Another alternative is that uploadFileSuccceed() happens through a different browser window and thus also a different UI instance, which means that the changes would be pushed in the context of the wrong UI.
For exactly these reasons, UI.getCurrent().access(...) is generally an anti pattern, even though it's unfortunately quite widely used in old examples.
You can check whether this is the cause of your problem by logging the value of UI.getCurrent() in the beginning of the update method, and comparing that to the value of UI.getCurrent() e.g. in the constructor of InformationComponent.
To properly fix the problem, you should pass the correct UI instance through the entire chain of events originating from whatever triggers the background processing to start. You should also note that it might be tempting to use the getUI() method that is available in any Component subclass, but that method is not thread safe and should thus be avoided in background threads.
As a final notice, I would recommend using the Span or Text component instead of Label in cases like this. In Vaadin 10, the Label component has been changed to use the <label> HTML element, which means that it's mainly intended to be used as the label of an input component.
Based on information provided by Leif you should do something like the following example.
At runtime, when this HorizontalLayout subclass object is attached to a parent UI object, its onAttach method is called. At that point we can remember the UI by storing its reference is a member variable named ui. Actually, an Optional<UI> is returned rather than a UI object, so we need to test for null, though it should never be null at point of onAttach.
public class InformationComponent extends HorizontalLayout {
UI ui;
StudentRepository studentRepo;
Label nbLineInFile = new Label();
VerticalLayout componentLeft = new VerticalLayout();;
VerticalLayout componentRight = new VerticalLayout();;
public InformationComponent(StudentRepository studentRepo) {
[...] // some init and style stuff
addLine("Nombre de lignes dans le fichier", nbLineInFile);
}
private void addLine(String label, Label value) {
componentLeft.add(new Label(label));
componentRight.add(value);
}
public void update(File file) {
try {
long nbLines = Files.lines(file.toPath(), Charset.defaultCharset()).count();
System.out.println("UPDATED! " +nbLines); // value is display in console ok!
this.ui.access(() -> nbLineInFile.setText(nbLines)); // UI is not updated!!
} catch (IOException e) {
throw new RuntimeException(e);
} catch (UIDetachedException e) {
// Do here what is needed to do if UI is no longer attached, user has closed the browser
}
#Override // Called when this component (this `HorizontalLayout`) is attached to a `UI` object.
public void onAttach() {
ui = this.getUI().orElseThrow( () -> new IllegalStateException("No UI found, which should be impossible at point of `onAttach` being called.") );
}

How do I make View's asList() sortable in Google Dataflow SDK?

We have a problem making asList() method sortable.
We thought we could do this by just extending the View class and override the asList method but realized that View class has a private constructor so we could not do this.
Our other attempt was to fork the Google Dataflow code on github and modify the PCollectionViews class to return a sorted list be using the Collections.sort method as shown in the code snippet below
#Override
protected List<T> fromElements(Iterable<WindowedValue<T>> contents) {
Iterable<T> itr = Iterables.transform(
contents,
new Function<WindowedValue<T>, T>() {
#SuppressWarnings("unchecked")
#Override
public T apply(WindowedValue<T> input){
return input.getValue();
}
});
LOG.info("#### About to start sorting the list !");
List<T> tempList = new ArrayList<T>();
for (T element : itr) {
tempList.add(element);
};
Collections.sort((List<? extends Comparable>) tempList);
LOG.info("##### List should now be sorted !");
return ImmutableList.copyOf(tempList);
}
Note that we are now sorting the list.
This seemed to work, when run with the DirectPipelineRunner but when we tried the BlockingDataflowPipelineRunner, it didn't seem like the code change was being executed.
Note: We actually recompiled the dataflow used it in our project but this did not work.
How can we be able to achieve this (as sorted list from the asList method call)?
The classes in PCollectionViews are not intended for extension. Only the primitive view types provided by View.asSingleton, View.asSingleton View.asIterable, View.asMap, and View.asMultimap are supported.
To obtain a sorted list from a PCollectionView, you'll need to sort it after you have read it. The following code demonstrates the pattern.
// Assume you have some PCollection
PCollection<MyComparable> myPC = ...;
// Prepare it for side input as a list
final PCollectionView<List<MyComparable> myView = myPC.apply(View.asList());
// Side input the list and sort it
someOtherValue.apply(
ParDo.withSideInputs(myView).of(
new DoFn<A, B>() {
#Override
public void processElement(ProcessContext ctx) {
List<MyComparable> tempList =
Lists.newArrayList(ctx.sideInput(myView));
Collections.sort(tempList);
// do whatever you want with sorted list
}
}));
Of course, you may not want to sort it repeatedly, depending on the cost of sorting vs the cost of materializing it as a new PCollection, so you can output this value and read it as a new side input without difficulty:
// Side input the list, sort it, and put it in a PCollection
PCollection<List<MyComparable>> sortedSingleton = Create.<Void>of(null).apply(
ParDo.withSideInputs(myView).of(
new DoFn<Void, B>() {
#Override
public void processElement(ProcessContext ctx) {
List<MyComparable> tempList =
Lists.newArrayList(ctx.sideInput(myView));
Collections.sort(tempList);
ctx.output(tempList);
}
}));
// Prepare it for side input as a list
final PCollectionView<List<MyComparable>> sortedView =
sortedSingleton.apply(View.asSingleton());
someOtherValue.apply(
ParDo.withSideInputs(sortedView).of(
new DoFn<A, B>() {
#Override
public void processElement(ProcessContext ctx) {
... ctx.sideInput(sortedView) ...
// do whatever you want with sorted list
}
}));
You may also be interested in the unsupported sorter contrib module for doing larger sorts using both memory and local disk.
We tried to do it the way Ken Knowles suggested. There's a problem for large datasets. If the tempList is large (so sort takes some measurable time as it's proportion to O(n * log n)) and if there are millions of elements in the "someOtherValue" PCollection, then we are unecessarily re-sorting the same list millions of times. We should be able to sort ONCE and FIRST, before passing the list to the someOtherValue.apply's DoFn.

PrimeFaces DataTable: (Multi)selection does not work for dynamically built tables giving only nulls

I'm working with the multiple row selection to give a user ability to delete the selecting records. According to the PDF documentation, and the ShowCase Labs, I must use the code translated to the Java like that:
final DataTable = new DataTable();
...
// (1)
dataTable.setSelectionMode("multiple");
// (2)
dataTable.setValueExpression("selection", createValueExpression(DbeBean.class, "selection", Object[].class));
// (3)
dataTable.setValueExpression("rowKey", createValueExpression("#{" + VARIABLE + ".indexKey}", Object.class));
...
final ClientBehaviorHolder dataTableAsHolder = dataTable;
...
// (4)
dataTableAsHolder.addClientBehavior("rowSelect", createAjaxBehavior(createMethodExpression(metaData.controllerBeanType, "onRowSelect", void.class, new Class<?>[] {SelectEvent.class})));
multiple - This line features the multiple selection, works fine visually at the front-end.
selection - Being invoked, the #{dbeBean.selection} is really bound and the public void setSelection(T[] selection) is only invoked.
rowKey - Being invoked, works fine, the getIndexKey() is invoked and returns the necessary result.
rowSelect - This event handler is invoked too, DbeBean.onRowSelect(SelectEvent e).
I also use lazy data model (I don't really believe it may be the reason but who knows?; by the way, it returns List<T> though setSelection() requires T[] -- why it's like that?):
public abstract class AbstractLazyDataSource<T extends IIndexable<K>, K> extends LazyDataModel<T> {
...
#Override
public final List<T> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters) {
...
final IResultContainer<T> resultContainer = getData(querySpecifier);
final List<T> data = resultContainer.getData();
setRowCount(resultContainer.getTotalEntitiesCount());
return getPage(data, first, pageSize);
}
...
#Override
public final K getRowKey(T object) {
return object.getIndexKey(); // T instanceof IIndexable<K>, have to return a unique ID
}
...
However, the handlers do not work as they are expected to work. Please help me to understand why (2) DbeBean.setSelection(T[] selection) & (4) DbeBean.onRowSelect(SelectEvent e) get only the null value: T[] selection = null, and SelectEvent: e.getObject = null, respectively. What am I doing wrong?
Thanks in advance.
PrimeFaces 3.2
Mojarra 2.1.7
I've got it to work: I simply removed the rowKey property during to the dynamic p:dataTable creation (DataTable), and simply overloaded getRowData in lazy data model. Now it works.

MVC 3 - Widget fine in Create action, but has null values in View action

I'm using ASP.NET MVC3, with Entity Framework.
I have a Widget controller, with standard Widget CRUD actions.
In my Create action, I successfully create a new Widget object, which has two FooBar objects. This is added to my database just fine, and the action the redirects to the View action.
[HttpPost]
public ActionResult Create(Widget model)
{
if (ModelState.IsValid)
{
//At this point, the widget has two FooBar properties. I can see the values for these FooBars just fine.
if (repo.AddWidget(model))
{
ViewBag.Message = "Your widget has been created.");
return RedirectToAction("View", new { id = model.Id });
}
else
{
ViewBag.Error = "Woops, something went wrong. Please try again.");
}
}
return View(model);
}
In the View action, I fetch the newly created Widget from my repository - except now the two FooBar properties are null.
public ActionResult View(int id)
{
var widget = repo.GetWidget(id);
if (widget == null)
{
ViewBag.Error = "No widget found for the specified ID";
return RedirectToAction("Find");
}
//At this point, the widget has two null values for the FooBar1 and FooBar 2 properties
return View(widget);
}
In the database itself I can see the correct FooBar ID values on my Widget.
My model is set up pretty much exactly the same as shown in this tutorial:
http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx
public class WidgetContext : DbContext
{
public DbSet<Widget> Widgets { get; set; }
public DbSet<FooBar> FooBars { get; set; }
}
Can anyone suggest how I might start tracking this issue down?
Update:
I should clarify the values are null whenever I call the View action, not only after a Create.
Looks like FooBar is separate entity and FooBar1 and FooBar2 are navigation properties. In such case you must either explicitly say you want to loade them (we call this eager loading):
var widget = context.Widgets
.Include(w => w.FooBar1)
.Include(w => w.FooBar2)
.SingleOfDefault(w => w.Id == id);
Note: Strongly typed Include requires EF 4.1 for EFv1 or EFv4 use:
var widget = context.Widgets
.Include("FooBar1")
.Include("FooBar2")
.SingleOfDefault(w => w.Id == id);
or create custom strongly typed extension method like this.
or you must turn lazy loading on. Lazy loading makes separate queries to database once properties are first accessed in your view. It requires making both FooBar1 and FooBar2 virtual and context must be alive when view is rendered. Usually this is handled by singe context per HTTP request where context is for example created and disposed in custom controller factory or in custom Http module.
Also next time make your question complete please. You have shown a lot of code but the important parts (Windget class and GetById method) are missing. Unfortuanatelly users here aren't oracles so we need to now necessary details. Both action methods are almost irrelevant to your problem.

Resources