Conformed to Google Checkstyle.

This commit is contained in:
neviyn 2018-09-27 09:24:50 +01:00
parent 2950095e50
commit 3d048723cd
16 changed files with 277 additions and 107 deletions

View File

@ -24,8 +24,8 @@ import uk.co.neviyn.observations.resources.TutorResource;
public class ObservationsApplication extends Application<ObservationsConfiguration> {
private final HibernateBundle<ObservationsConfiguration> hibernate = new HibernateBundle<ObservationsConfiguration>(
Observation.class, Tutor.class, Site.class) {
private final HibernateBundle<ObservationsConfiguration> hibernate =
new HibernateBundle<ObservationsConfiguration>(Observation.class, Tutor.class, Site.class) {
@Override
public DataSourceFactory getDataSourceFactory(ObservationsConfiguration configuration) {
return configuration.getDataSourceFactory();
@ -47,15 +47,17 @@ public class ObservationsApplication extends Application<ObservationsConfigurati
public void run(ObservationsConfiguration observationsConfiguration, Environment environment) {
final JerseyEnvironment jersey = environment.jersey();
jersey.register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<User>()
.setAuthenticator(new SimpleAuthenticator(observationsConfiguration.getAdminPassword())).setRealm("SECURITY")
.buildAuthFilter()));
.setAuthenticator(new SimpleAuthenticator(
observationsConfiguration.getAdminPassword())
).setRealm("SECURITY").buildAuthFilter()));
jersey.register(new AuthValueFactoryProvider.Binder<>(User.class));
TutorDao tutorDao = new TutorDao(hibernate.getSessionFactory());
SiteDao siteDao = new SiteDao(hibernate.getSessionFactory());
ObservationDao observationDao = new ObservationDao(hibernate.getSessionFactory());
final TutorResource tutorResource = new TutorResource(tutorDao, siteDao);
jersey.register(tutorResource);
final ObservationResource observationResource = new ObservationResource(observationDao, tutorDao, siteDao);
final ObservationResource observationResource =
new ObservationResource(observationDao, tutorDao, siteDao);
jersey.register(observationResource);
final SiteResource siteResource = new SiteResource(siteDao);
jersey.register(siteResource);

View File

@ -1,7 +1,10 @@
package uk.co.neviyn.observations.api;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.joda.time.DateTime;
@Data
@ -11,7 +14,19 @@ public class AverageStats {
@NonNull
@JsonProperty
private double monitoring, control, conservatism, teamwork, knowledge;
private double monitoring;
@NonNull
@JsonProperty
private double control;
@NonNull
@JsonProperty
private double conservatism;
@NonNull
@JsonProperty
private double teamwork;
@NonNull
@JsonProperty
private double knowledge;
@NonNull
@JsonProperty

View File

@ -21,13 +21,17 @@ public class AverageStatsChartJs {
@JsonProperty
private List<Dataset> datasets = new ArrayList<>();
public AverageStatsChartJs(List<AverageStats> inputData){
List<Double> monitoring = new ArrayList<>(),
control = new ArrayList<>(),
conservatism = new ArrayList<>(),
teamwork = new ArrayList<>(),
knowledge = new ArrayList<>();
for(AverageStats averageStats: inputData){
/**
* A list of AverageStats converted to a format compatible with Chart.js.
* @param inputData List of average stats.
*/
public AverageStatsChartJs(List<AverageStats> inputData) {
List<Double> monitoring = new ArrayList<>();
List<Double> control = new ArrayList<>();
List<Double> conservatism = new ArrayList<>();
List<Double> teamwork = new ArrayList<>();
List<Double> knowledge = new ArrayList<>();
for (AverageStats averageStats: inputData) {
labels.add(averageStats.getDate().toString("yyyy-MM-dd"));
monitoring.add(averageStats.getMonitoring());
control.add(averageStats.getControl());
@ -62,7 +66,7 @@ public class AverageStatsChartJs {
@JsonProperty
private final boolean fill = false;
Dataset(String label, String color, List<Double> data){
Dataset(String label, String color, List<Double> data) {
this.label = label;
this.backgroundColor = color;
this.borderColor = color;

View File

@ -1,10 +1,14 @@
package uk.co.neviyn.observations.api;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import uk.co.neviyn.observations.core.ObservationEntry;
import java.util.List;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import uk.co.neviyn.observations.core.ObservationEntry;
@Data
@NoArgsConstructor
@ -22,11 +26,29 @@ public class NewObservation {
@NonNull
@JsonProperty
private String observed, type, whom;
private String observed;
@NonNull
@JsonProperty
private String type;
@NonNull
@JsonProperty
private String whom;
@NonNull
@JsonProperty
private float monitoring, control, conservatism, teamwork, knowledge;
private float monitoring;
@NonNull
@JsonProperty
private float control;
@NonNull
@JsonProperty
private float conservatism;
@NonNull
@JsonProperty
private float teamwork;
@NonNull
@JsonProperty
private float knowledge;
@NonNull
@JsonProperty

View File

@ -3,18 +3,17 @@ package uk.co.neviyn.observations.auth;
import io.dropwizard.auth.AuthenticationException;
import io.dropwizard.auth.Authenticator;
import io.dropwizard.auth.basic.BasicCredentials;
import java.util.Optional;
import lombok.AllArgsConstructor;
import uk.co.neviyn.observations.core.User;
import java.util.Optional;
@AllArgsConstructor
public class SimpleAuthenticator implements Authenticator<BasicCredentials, User> {
private final String adminPassword;
@Override
public Optional<User> authenticate(BasicCredentials credentials) throws AuthenticationException {
public Optional<User> authenticate(BasicCredentials credentials) {
if (adminPassword.equals(credentials.getPassword())) {
return Optional.of(new User(credentials.getUsername()));
}

View File

@ -2,13 +2,25 @@ package uk.co.neviyn.observations.core;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import org.joda.time.DateTime;
import javax.persistence.*;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.joda.time.DateTime;
@Entity
@Table(name = "OBSERVATION")
@ -25,7 +37,7 @@ public class Observation implements Serializable {
private long id;
@ManyToOne
@JoinColumn(name="site_id", nullable=false)
@JoinColumn(name = "site_id", nullable = false)
@JsonIgnore
@EqualsAndHashCode.Exclude
private Site site;
@ -49,7 +61,19 @@ public class Observation implements Serializable {
@NonNull
@JsonProperty
private float monitoring, control, conservatism, teamwork, knowledge;
private float monitoring;
@NonNull
@JsonProperty
private float control;
@NonNull
@JsonProperty
private float conservatism;
@NonNull
@JsonProperty
private float teamwork;
@NonNull
@JsonProperty
private float knowledge;
@NonNull
@JsonProperty

View File

@ -1,10 +1,12 @@
package uk.co.neviyn.observations.core;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import javax.persistence.Embeddable;
import java.io.Serializable;
import javax.persistence.Embeddable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
@Data
@NoArgsConstructor

View File

@ -2,11 +2,20 @@ package uk.co.neviyn.observations.core;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
@Entity
@Table(name = "SITE")
@ -26,7 +35,7 @@ public class Site implements Serializable {
@JsonProperty
private String name;
@OneToMany(mappedBy="site")
@OneToMany(mappedBy = "site")
@JsonIgnore
@EqualsAndHashCode.Exclude
private Set<Tutor> tutors;

View File

@ -2,11 +2,23 @@ package uk.co.neviyn.observations.core;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
@Entity
@Table(name = "TUTOR")
@ -27,7 +39,7 @@ public class Tutor implements Serializable {
private String name;
@ManyToOne
@JoinColumn(name="site_id", nullable=false)
@JoinColumn(name = "site_id", nullable = false)
@JsonIgnore
@EqualsAndHashCode.Exclude
private Site site;

View File

@ -1,11 +1,10 @@
package uk.co.neviyn.observations.core;
import java.security.Principal;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.security.Principal;
@Data
@AllArgsConstructor
@NoArgsConstructor

View File

@ -1,6 +1,12 @@
package uk.co.neviyn.observations.dao;
import io.dropwizard.hibernate.AbstractDAO;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.joda.time.DateTime;
@ -9,48 +15,55 @@ import uk.co.neviyn.observations.core.Observation;
import uk.co.neviyn.observations.core.Site;
import uk.co.neviyn.observations.core.Tutor;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
public class ObservationDao extends AbstractDAO<Observation> {
public ObservationDao(SessionFactory sessionFactory) {
super(sessionFactory);
}
public Observation get(long id){
public Observation get(long id) {
return super.get(id);
}
public Observation persist(Observation observation){
public Observation persist(Observation observation) {
return super.persist(observation);
}
public List<Observation> listAll(){
public List<Observation> listAll() {
return currentSession().createQuery("from Observation", Observation.class).list();
}
/**
* Generate the average observation stats with data constraints.
* @param site Restrict to a site.
* @param tutor Restrict to a tutor.
* @param startDate Restrict to after a certain date.
* @param endDate Restrict to before a certain date.
* @param whom Restrict to a particular person/group who was observed.
* @return Average observation scores per day.
*/
// TODO: Add tutor filter
public List<AverageStats> averageStats(Site site, Tutor tutor, DateTime startDate, DateTime endDate, String whom){
public List<AverageStats> averageStats(Site site, Tutor tutor, DateTime startDate,
DateTime endDate, String whom) {
CriteriaBuilder builder = currentSession().getCriteriaBuilder();
CriteriaQuery<AverageStats> criteriaQuery = builder.createQuery(AverageStats.class);
Root<Observation> root = criteriaQuery.from(Observation.class);
criteriaQuery.multiselect(builder.avg(root.get("monitoring")), builder.avg(root.get("control")),
builder.avg(root.get("conservatism")), builder.avg(root.get("teamwork")), builder.avg(root.get("knowledge")),
root.get("date"));
builder.avg(root.get("conservatism")), builder.avg(root.get("teamwork")),
builder.avg(root.get("knowledge")), root.get("date"));
criteriaQuery.groupBy(root.get("date"));
List<Predicate> predicates = new ArrayList<>();
if(site != null)
if (site != null) {
predicates.add(builder.equal(root.get("site"), site));
if(startDate != null)
}
if (startDate != null) {
predicates.add(builder.greaterThanOrEqualTo(root.get("date"), startDate));
if(endDate != null)
}
if (endDate != null) {
predicates.add(builder.lessThanOrEqualTo(root.get("date"), endDate));
if(whom != null)
}
if (whom != null) {
predicates.add(builder.equal(root.get("whom"), whom));
}
criteriaQuery.having(predicates.toArray(new Predicate[0]));
Query<AverageStats> query = currentSession().createQuery(criteriaQuery);
System.out.println(query.getQueryString());

View File

@ -1,25 +1,24 @@
package uk.co.neviyn.observations.dao;
import io.dropwizard.hibernate.AbstractDAO;
import java.util.List;
import org.hibernate.SessionFactory;
import uk.co.neviyn.observations.core.Site;
import java.util.List;
public class SiteDao extends AbstractDAO<Site> {
public SiteDao(SessionFactory sessionFactory) {
super(sessionFactory);
}
public List<Site> listAll(){
public List<Site> listAll() {
return currentSession().createQuery("from Site", Site.class).list();
}
public Site get(long id){
public Site get(long id) {
return super.get(id);
}
public Site persist(Site site){
public Site persist(Site site) {
return super.persist(site);
}
}

View File

@ -1,25 +1,24 @@
package uk.co.neviyn.observations.dao;
import io.dropwizard.hibernate.AbstractDAO;
import java.util.List;
import org.hibernate.SessionFactory;
import uk.co.neviyn.observations.core.Tutor;
import java.util.List;
public class TutorDao extends AbstractDAO<Tutor> {
public TutorDao(SessionFactory sessionFactory) {
super(sessionFactory);
}
public Tutor get(long id){
public Tutor get(long id) {
return super.get(id);
}
public List<Tutor> listAll(){
public List<Tutor> listAll() {
return currentSession().createQuery("from Tutor", Tutor.class).list();
}
public Tutor persist(Tutor tutor){
public Tutor persist(Tutor tutor) {
return super.persist(tutor);
}
}

View File

@ -1,6 +1,16 @@
package uk.co.neviyn.observations.resources;
import io.dropwizard.hibernate.UnitOfWork;
import java.util.HashSet;
import java.util.Set;
import javax.validation.constraints.NotNull;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
@ -15,12 +25,6 @@ import uk.co.neviyn.observations.dao.ObservationDao;
import uk.co.neviyn.observations.dao.SiteDao;
import uk.co.neviyn.observations.dao.TutorDao;
import javax.validation.constraints.NotNull;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.HashSet;
import java.util.Set;
@RequiredArgsConstructor
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@ -32,6 +36,11 @@ public class ObservationResource {
private final TutorDao tutorDao;
private final SiteDao siteDao;
/**
* Create a new Observation.
* @param newObservation New observation data.
* @return ID of newly created observation.
*/
@POST
@UnitOfWork
public long add(@NotNull NewObservation newObservation) {
@ -42,11 +51,12 @@ public class ObservationResource {
tutors.add(tutorDao.get(l));
}
final Site site = siteDao.get(newObservation.getSiteId());
Observation observation = Observation.builder().site(site).tutors(tutors).observed(newObservation.getObserved())
.type(TrainingType.valueOf(newObservation.getType())).monitoring(newObservation.getMonitoring())
.control(newObservation.getControl()).conservatism(newObservation.getConservatism())
.teamwork(newObservation.getTeamwork()).knowledge(newObservation.getKnowledge())
.observations(newObservation.getRawData()).date(submissionDate).whom(newObservation.getWhom()).build();
Observation observation = Observation.builder().site(site).tutors(tutors)
.observed(newObservation.getObserved()).type(TrainingType.valueOf(newObservation.getType()))
.monitoring(newObservation.getMonitoring()).control(newObservation.getControl())
.conservatism(newObservation.getConservatism()).teamwork(newObservation.getTeamwork())
.knowledge(newObservation.getKnowledge()).observations(newObservation.getRawData())
.date(submissionDate).whom(newObservation.getWhom()).build();
for (Tutor t : tutors) {
t.getObservations().add(observation);
}
@ -55,28 +65,45 @@ public class ObservationResource {
return observation.getId();
}
/**
* Get a Chart.js compatible llist of average observation scores grouped by day.
* @param siteId Only observations for site.
* @param tutorId Only observations for tutor.
* @param startDate Only observations after startDate.
* @param endDate Only observations before endDate.
* @param whom Only observations of whom.
* @return Chart.js stats object.
*/
@Path("/average")
@GET
@UnitOfWork
public AverageStatsChartJs averageObservationScores(@QueryParam("site") Integer siteId, @QueryParam("tutor") Integer tutorId,
@QueryParam("startDate") String startDate,
@QueryParam("endDate") String endDate, @QueryParam("whom") String whom) {
public AverageStatsChartJs averageObservationScores(@QueryParam("site") Integer siteId,
@QueryParam("tutor") Integer tutorId, @QueryParam("startDate") String startDate,
@QueryParam("endDate") String endDate, @QueryParam("whom") String whom) {
Site site = null;
Tutor tutor = null;
DateTime start = null;
DateTime end = null;
try{
try {
site = siteDao.get(siteId);
} catch (Exception ignored){}
try{
} catch (Exception e) {
log.warn("Couldn't get site with ID " + siteId);
}
try {
tutor = tutorDao.get(tutorId);
} catch (Exception ignored){}
try{
} catch (Exception e) {
log.warn("Couldn't get tutor with ID " + tutorId);
}
try {
start = DateTime.parse(startDate);
} catch (Exception ignored){}
try{
} catch (Exception e) {
log.warn("Couldn't get a valid date from " + startDate);
}
try {
end = DateTime.parse(endDate);
} catch (Exception ignored) {}
} catch (Exception e) {
log.warn("Couldn't get a valid date from " + endDate);
}
return new AverageStatsChartJs(dao.averageStats(site, tutor, start, end, whom));
}
}

View File

@ -2,6 +2,14 @@ package uk.co.neviyn.observations.resources;
import io.dropwizard.auth.Auth;
import io.dropwizard.hibernate.UnitOfWork;
import java.util.List;
import java.util.stream.Collectors;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import uk.co.neviyn.observations.api.SelectOption;
@ -9,11 +17,6 @@ import uk.co.neviyn.observations.core.Site;
import uk.co.neviyn.observations.core.User;
import uk.co.neviyn.observations.dao.SiteDao;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.List;
import java.util.stream.Collectors;
@RequiredArgsConstructor
@Produces(MediaType.APPLICATION_JSON)
@Path("/site")
@ -22,6 +25,12 @@ public class SiteResource {
private final SiteDao dao;
/**
* Add a new Site.
* @param user Authorization account.
* @param name Name of Site to add.
* @return Newly created site object.
*/
@POST
@UnitOfWork
public Site add(@Auth User user, String name) {
@ -30,17 +39,30 @@ public class SiteResource {
return site;
}
/**
* List all known Sites.
* @return List of all Sites.
*/
@Path("/all")
@GET
@UnitOfWork
public List<SelectOption<Long>> allSites() {
return dao.listAll().stream().map(x -> new SelectOption<>(x.getName(), x.getId())).collect(Collectors.toList());
return dao.listAll().stream().map(x ->
new SelectOption<>(x.getName(), x.getId())).collect(Collectors.toList()
);
}
/**
* A List of all the Tutors registered to Site.
* @param id ID of site.
* @return List of Tutors, compatible with a HTML select object.
*/
@Path("/{id}/tutors")
@GET
@UnitOfWork
public List<SelectOption<Long>> getSiteTutors(@PathParam("id") long id) {
return dao.get(id).getTutors().stream().map(x -> new SelectOption<>(x.getName(), x.getId())).collect(Collectors.toList());
return dao.get(id).getTutors().stream().map(x ->
new SelectOption<>(x.getName(), x.getId())).collect(Collectors.toList()
);
}
}

View File

@ -3,6 +3,16 @@ package uk.co.neviyn.observations.resources;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.dropwizard.auth.Auth;
import io.dropwizard.hibernate.UnitOfWork;
import java.util.List;
import java.util.Set;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.NonNull;
@ -15,12 +25,6 @@ import uk.co.neviyn.observations.core.User;
import uk.co.neviyn.observations.dao.SiteDao;
import uk.co.neviyn.observations.dao.TutorDao;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
import java.util.Set;
@RequiredArgsConstructor
@Produces(MediaType.APPLICATION_JSON)
@Path("/tutor")
@ -30,30 +34,48 @@ public class TutorResource {
private final TutorDao dao;
private final SiteDao siteDao;
/**
* Create a new Tutor.
* @param user Authorization account.
* @param newTutor Details of new Tutor.
* @return Newly created Tutor object.
*/
@POST
@UnitOfWork
public Tutor add(@Auth User user, NewTutor newTutor) {
final Site site = siteDao.get(newTutor.siteId);
final Tutor tutor = Tutor.builder().name(newTutor.name).site(site).build();
site.getTutors().add(tutor);
log.info("Created tutor '" + tutor.getName() + "' with id " + tutor.getId() + " at site " + site.getId());
log.info("Created tutor '" + tutor.getName() + "' with id "
+ tutor.getId() + " at site " + site.getId());
return dao.persist(tutor);
}
/**
* Get a List of all Tutors.
* @return List of all Tutors.
*/
@Path("/all")
@GET
@UnitOfWork
public List<Tutor> allTutors() {
List<Tutor> tutors = dao.listAll();
if (tutors != null && !tutors.isEmpty())
if (tutors != null && !tutors.isEmpty()) {
return tutors;
}
throw new WebApplicationException("No tutors found!", Response.Status.NOT_FOUND);
}
/**
* Get a list of all observations by a tutor.
* @param id Tutor ID.
* @return List of tutors' observations.
*/
@Path("/{id}/observations")
@GET
@UnitOfWork
public Set<Observation> getSiteTutors(@PathParam("id") long id) {
public Set<Observation> getTutorObservation(@PathParam("id") long id) {
return dao.get(id).getObservations();
}