How to edit value of ValueProxy of gwt requestfactory at client side? - gwt

I have 2 models: ContactGroup and Contact. ContactGroup contains many Contacts.
In the page, I have to display a list of groups and number of contacts in the correspondence group like this:
Group Foo (12 contacts)
Group Bar (20 contacts)
So I at server side I used a DTO ContactGroupInfo:
public class ContactGroupInfo {
private Integer contactCount;
private Long id;
private String name;
public Integer getContactCount() { return this.contactCount; }
public Long getId() { return this.id; }
public String getName() { return this.name; }
public void setContactCount(Integer count) { this.contactCount = count; }
public void setId(Long id) { this.id = id; }
public void setName(String name) { this.name = name; }
}
In this ContactGroupInfo, I added contactCount field which is not a field in ContactGroup entity.
And at client side, I used a ValueProxy:
#ProxyFor(value = ContactGroupInfo.class, locator = ContactGroupService.class)
public interface LightContactGroupProxy extends ValueProxy {
Integer getContactCount();
Long getId();
String getName();
void setContactCount(Integer count);
void setId(Long id);
void setName(String name);
}
So when server side returns to client side a list of LightContactGroupProxy, I stored that list a in ArrayList to render to a CellTable.
And here is the problem comes to me: when I need to edit the name of the group at client side, I can't edit the LightContactGroupProxy object directly.
So I have to send the new name to server to return a new LightContactGroupProxy with the new name. This is not effective because I have to count contacts again (althought I know the number of contacts does not change).
Or I have to send both the number of contacts and new name to server to create a new LightContactGroupProxy with the new name. This is not I want, because if LightContactGroupProxy has many other fields I have to send many fields.
I don't know why GWT teams designs the immutable proxy. So please, someone has experience on requestfactory please show me the correct way to handle ValueProxy returned from server so that we can use them to render and edit?
Thank you

Maybe you should try something like this :
ContactGroupContext ctx = requestFactory.newContactGroupContext();
LightContactGroupProxy editableProxy = ctx.edit(lightContactGroupProxy);
editableProxy.setName(newName);
ctx.saveInfoAndReturn(editableProxy).fire(receiver); // or just ctx.fire();
Anyway, I wouldn't use ValueProxy in this case, I would directly get the ContactGroup entities with a transiant property contactCount. The property could be a primitive, or a ValueProxy if you don't want it to be calculated every time a ContactGroup is requested.

Related

Postgres to bring list all of table fields for particular Employee row?

Taking a reference from link: Postgres to fetch the list having comma separated values, I want to write a query which somhow brings Employee email Table fields as a list for a particular Empployee. This is needed for Spring Batch to Simply match it from the Resultset and create a POJO/Model class like List emails for Employee class?
Can this be possible ?
select c.*, ce.*, string_agg(ce.email, ',') as emails
from root.employee c
full outer join root.employee_email ce
on c.employee_id = ce.employee_id
group by
c.employee_id, ce.employee_email_id
order by
c.employee_id
limit 1000
offset 0;
Your problem is a common one in the batch processing realm and with Spring Batch it is called "Driving Query Based ItemReaders", you can find more about that in here.
Basically you retrieve the Contacts in your reader, and in your processor you add the list of Emails to them.
#Bean(destroyMethod = "")
public JdbcCursorItemReader<Employee> employeeReader(DataSource dataSource) {
JdbcCursorItemReader<Employee> ItemReader = new JdbcCursorItemReader<>();
ItemReader.setDataSource(dataSource);
ItemReader.setSql("SELECT * FROM employee.employee C ");
ItemReader.setRowMapper(new EmployeeRowMapper());
return ItemReader;
}
#Bean
public ItemProcessor<Employee, Employee> settlementHeaderProcessor(JdbcTemplate jdbcTemplate){
return item -> {
root.EMPLOYEE_EMAIL CE WHERE ce.employee_id = ? ",
new Object[]{item.getId()},
new RowMapper<String>() {
#Override
public String mapRow(ResultSet resultSet, int i) throws SQLException {
return resultSet.getString("EMAIL");
}
});
item.setEmails(emails);
return item;
};
}
PS : this could have some performance issues if you have lots of contacts, because for each contact Item you will hit the database to retrieve Emails.
There is another optimized way, by creating a custom reader that will return a List of Contacts (For example 1000 by 1000), and a processor that will enrich them with their emails. This way you will hit the database again for each 1000 Contact Item.
In your reader your retrieve a list of unique Employees page per page (Say your page is 1000 long).
And in your processor for the 1000 employees you retrieve all their emails in one query.
Then for each employee you set the emails retrieved in the last query.
An example might like the following:
public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Integer> {
}
#Getter
class EmployeeVO {
private Long employeeId;
private String email;
EmployeeVO(Long employeeId, String email) {
this.employeeId= employeeId;
this.email = email;
}
}
public class EmployeeListReader implements ItemReader<List<Employee>> {
private final static int PAGE_SIZE = 1000;
private final EmployeeRepository employeeRepository;
private int page = 0;
public EmployeeListReader(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
public List<Employee> read() throws Exception {
Page<Employee> employees = employeeRepository.findAll(PageRequest.of(page, PAGE_SIZE));
page++;
return employees.getContent();
}
}
#Bean
EmployeeListReader reader(){
return new EmployeeListReader(this.employeeRepository);
}
#Bean
public ItemProcessor<List<Employee>, List<Employee>> settlementHeaderProcessor(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
return item -> {
List<Long> employeesIds = item.stream().map(Employee::getId).collect(Collectors.toList());
SqlParameterSource parameters = new MapSqlParameterSource("ids", employeesIds);
List<ContactVO> emails = namedParameterJdbcTemplate
.query("SELECT CE.employeeId, CE.EMAIL FROM employee_EMAIL CE WHERE ce.contact_id IN (:ids) ",
parameters,
new RowMapper<ContactVO>() {
#Override
public ContactVO mapRow(ResultSet resultSet, int i) throws SQLException {
return new ContactVO(
resultSet.getLong("EMPLOYEE_ID"),
resultSet.getString("EMAIL"));
}
});
Map<Long, List<ContactVO>> emailsByContactId = emails.stream().collect(Collectors.groupingBy(ContactVO::getContactId));
List<Employee> newEmployeesWithEmails = Collections.unmodifiableList(item);
newEmployeesWithEmails.forEach(employee -> {
employee.setEmails(emailsByContactId.get(employee.getId()).stream().map(ContactVO::getEmail).collect(Collectors.toList()));
});
return newEmployeesWithEmails;
};
}
Hope this helps

JPA first level cache not clreared after completion of transaction

I am using JPA 2.1(with EclipseLink implementation), to get a record from Database.
By default it first level cache is enabled, it caches the record in PersistenceContext. If I try to get same record I will get it from first level cache, so no query will be fired on database second time.
Once transaction is over the first level cache will be cleared, and If I try to get same entry one more time, query has to be fired as the cache is cleared and it should come from database but it is not.
At least the query should be fired on database if I close the current entity manager,re-open it, and try to get the record.
Even now second query is not going to database. Once I get the record from the database first time(at this time I can see the select query in console logs), after wards if I try to get one more time, its coming from cache memory(as I can not see the query one more time in console logs, I am pretending that it is coming from cache), no matter what I do(use new transaction or close and re-open entity manager) the first level cache ain't cleared.
The code which I am using is below:
EntityManagerFactory entityManagerFactory=
Persistence.createEntityManagerFactory("01EmployeeBasics");
EntityManager entityManager=entityManagerFactory.createEntityManager();
System.out.println("EM1 : "+entityManager);
entityManager.getTransaction().begin();
System.out.println("Tx1 : "+entityManager.getTransaction());
Employee employee=entityManager.find(Employee.class, 123);
entityManager.getTransaction().commit();
entityManager.close();
entityManager=entityManagerFactory.createEntityManager();
System.out.println("EM2 : "+entityManager);
entityManager.getTransaction().begin();
System.out.println("Tx2 : "+entityManager.getTransaction());
Employee employee2=entityManager.find(Employee.class, 123);
entityManager.getTransaction().commit();
entityManager.close();
entityManagerFactory.close();
Employee class is as below:
package in.co.way2learn;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
public class Employee {
#Id
private int id;
private String name;
private int salary;
public Employee() {
// TODO Auto-generated constructor stub
}
public Employee(int id, String name, int salary) {
super();
this.id = id;
this.name = name;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
System.out.println("Employee.getName()");
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
In database there is a record with id 123.
Now my question is why the first level cache is not cleared??
EclipseLink has a shared object (2nd level) cache which is enabled by default and which:
...exists for the duration of the persistence unit (EntityManagerFactory,
or server) and is shared by all EntityManagers and users of the
persistence unit.
If you disable this according to the instructions in the below then you should see the 2nd query firing.
https://wiki.eclipse.org/EclipseLink/Examples/JPA/Caching

Spring boot REST application

I am trying to make a RESTful application in Java using Spring boot by following the tutorial here. I want to modify it so that I can extract an identifier from the URL and use it to serve requests.
So http://localhost:8080/members/<memberId> should serve me a JSON object with information about the member whose ID is <memberId>. I don't know how to
Map all http://localhost:8080/members/* to a single controller.
Extract the from the URL.
Should the logic of extracting the memberId and using it be part of the controller or a separate class, as per the MVC architecture?
I am new to Spring/Spring-boot/MVC. It is quite confusing to get started with. So please bear with my newbie questions.
Map all http://localhost:8080/members/* to a single controller.
You can use a placeholder in a request mapping to so it'll handle multiple URLs. For example:
#RequestMapping("/members/{id}")
Extract the id from the URL
You can have the value of a placeholder injected into your controller method using the #PathVariable annotation with a value that matches the name of the placeholder, "id" in this case:
#RequestMapping("/members/{id}")
public Member getMember(#PathVariable("id") long id) {
// Look up and return the member with the matching id
}
Should the logic of extracting the memberId and using it be part of the controller or a separate class, as per the MVC architecture?
You should let Spring MVC extract the member id from the URL as shown above. As for using it, you'll probably pass the URL to some sort of repository or service class that offers a findById method.
As you can see in the code below, service for customer are in one controller to get one and to add new customer.
So, you will have 2 services:
http://localhost:8080/customer/
http://localhost:8080/customer/{id}
#RestController("customer")
public class SampleController {
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public Customer greetings(#PathVariable("id") Long id) {
Customer customer = new Customer();
customer.setName("Eddu");
customer.setLastname("Melendez");
return customer;
}
#RequestMapping(value = "/{id}", method = RequestMethod.POST)
public void add(#RequestBody Customer customer) {
}
class Customer implements Serializable {
private String name;
private String lastname;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getLastname() {
return lastname;
}
}
}

Disadvantages of interface objected programming

class Person{
private String name;
private int age;
private String gender;
//......
}
class Student extends Person{
private String id;
private String schoolBelongTo;
//......
}
public void showInfoOf(Person person){
System.out.println(person.getName());
//......
}
When using function "showInfoOf" ,if an object of Peron is used as the param,OK.However,if it is the type Student,I cannot get access to the field id and schoolBelongTo.
So I am confused ,how to ?
Actually, I want to know is this one of its(Interface oriented programming's or Supper class oriented programming's) disadvantages???
Two possible solutions:
You can programatically check the type in showInfoOf (Person), and use a cast to access & print the desired fields; or,
You can define a method on Person which will print/provide the desired info -- and either replace showPersonInfo() with that entirely, or call it into it. This is the more OO way.
Example:
abstract class Person {
private String name;
private int age;
private String gender;
public void printInfo() {
System.out.println( name);
}
}
class Student extends Person{
private String id;
private String schoolBelongTo;
#Override
public void printInfo() {
super.printInfo();
System.out.println( id);
System.out.println( schoolBelongTo);
}
}
public void showInfoOf (Person person){
person.printInfo();
}
In this example, all functionality has moved to Person.printInfo() and there is no real functionality remaining in showInfoOf (Person).
However in the real-world, you'd probably want move versatility in a Person.provideInfo() function -- perhaps returning a LinkedHashMap of fields & values (since unlabelled values on their own, are not great design).
The showInfoOf (Person) function could then handle formatting & printing the values to the specific requirement, leaving the Person.provideInfo() function general & multi-purpose.
in showInfoOf() you would have to check that person is of type Student, then cast it as a Student to get id or schoolBelongsTo

How to use list of pages from graph.facebook.com/me/accounts

https://graph.facebook.com/me/accounts?access_token=USERS_AUTH_TOKEN
returns a list of pages the user has admin status in (in JSON format).
I would like to list all the pages in a dropdownlist, and make the user choose which facebook page he wants to use (on my webapp), so I can obtain the specific access token for that facebook page.
My question is - whats the easiest and best way to do that. Ive never worked with JSON before, but I guess theres a pretty easy was to do this through the facebook-sdk.
Since you're using the C# SDK, just take the array of objects and convert them into a IList<IDictionary>() array using the pageId as the key and the value being the page name.
This is not fully compilable, but you get the idea:
private void IList<IDictionary<long,string>> ConvertToList(dynamic meAccounts)
{
foreach(var acc in meAccounts.data)
{
yield return new Dictionary((long)acc.id, (string)acc.name);
}
{
Okay figured out a way to do it. But I have no idea ifs the right way or the most optimal.
Would very much like inputs on it.
[DataContract]
internal class FacebookObj
{
[DataMember]
public List<FacebookAccount> data;
[DataMember]
public FacebookNext paging;
}
[DataContract]
internal class FacebookAccount
{
[DataMember]
public string name;
[DataMember]
public string category;
[DataMember]
public string id;
[DataMember]
public string access_token;
}
[DataContract]
internal class FacebookNext
{
[DataMember]
public string next;
}
public void ShowPages(string authToken) {
WebRequest webRequest = WebRequest.Create("https://graph.facebook.com/me/accounts?access_token=" + authToken);
WebResponse webResponse = webRequest.GetResponse();
Stream sr = webResponse.GetResponseStream();
if (sr != null)
{
jsonSer = new DataContractJsonSerializer(typeof(FacebookObj));
FacebookObj o = (FacebookObj)jsonSer.ReadObject(sr2);
foreach (FacebookAccount s in o.data)
{
//Do stuff
Response.Write(s.id + " - " + s.name + "<br />");
}
}
}