Package name.pehl.karaka.server.activity.boundary

Source Code of name.pehl.karaka.server.activity.boundary.ActivitiesResource

package name.pehl.karaka.server.activity.boundary;

import com.google.appengine.api.search.Results;
import com.google.appengine.api.search.ScoredDocument;
import name.pehl.karaka.server.activity.control.ActivitiesConverter;
import name.pehl.karaka.server.activity.control.ActivityConverter;
import name.pehl.karaka.server.activity.control.ActivityIndexSearch;
import name.pehl.karaka.server.activity.control.ActivityRepository;
import name.pehl.karaka.server.activity.entity.Activity;
import name.pehl.karaka.server.activity.entity.SameActivity;
import name.pehl.karaka.server.settings.control.CurrentSettings;
import name.pehl.karaka.server.settings.entity.Settings;
import name.pehl.karaka.shared.model.Activities;
import name.pehl.karaka.shared.model.Duration;
import name.pehl.karaka.shared.model.Durations;
import name.pehl.karaka.shared.model.Year;
import name.pehl.karaka.shared.model.Years;
import org.jboss.resteasy.annotations.cache.Cache;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.LinkHeader;
import org.jboss.resteasy.spi.NotFoundException;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.MutableDateTime;
import org.joda.time.format.ISODateTimeFormat;

import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
import static javax.ws.rs.core.Response.Status.*;
import static name.pehl.karaka.shared.model.HasLinks.*;
import static name.pehl.karaka.shared.model.Status.STOPPED;
import static name.pehl.karaka.shared.model.TimeUnit.*;
import static org.joda.time.Months.months;
import static org.joda.time.Weeks.weeks;

/**
* Supported methods:
* <p/>
* <p>Read methods:</p>
* <ul>
* <li>GET /activities/{year}/{month}: Find activities by year and month</li>
* <li>GET /activities/{year}/{month}/duration: Get the duration in minutes of the specified activities</li>
* <li>GET /activities/relative/{month}: Find activities by month relative to the current month</li>
* <li>GET /activities/relative/{month}/duration: Get the duration in minutes of the specified activities</li>
* <li>GET /activities/currentMonth: Find activities of the current month</li>
* <li>GET /activities/currentMonth/duration: Get the duration in minutes of the specified activities</li>
* <li>GET /activities/{year}/cw{week}: Find activities by year and week</li>
* <li>GET /activities/{year}/cw{week}/duration: Get the duration in minutes of the specified activities</li>
* <li>GET /activities/relative/cw{week}: Find activities by  week relative to the current week</li>
* <li>GET /activities/relative/cw{week}/duration: Get the duration in minutes of the specified activities</li>
* <li>GET /activities/currentWeek: Find activities</li>
* <li>GET /activities/currentWeek/duration: Get the duration in minutes of the specified activities</li>
* <li>GET /activities/{year}/{month}/{day}: Find activities</li>
* <li>GET /activities/{year}/{month}/{day}/duration: Get the duration in minutes of the specified activities</li>
* <li>GET /activities/today: Find activities</li>
* <li>GET /activities/today/duration: Get the duration in minutes of the specified activities</li>
* <li>GWT /activities/{yyyymmdd}/{yyyymmdd}: Get the activities in the specified range (from and to are inclusive)</li>
* <li>GWT /activities/{yyyymmdd}/yyyymmdd}/duration: Get the duration in minutes of the specified activities</li>
* <li>GET /activities/running: Find the running activity</li>
* <li>GET /activities/latest: Find the latest activity</li>
* <li>GET /activities/?q=&lt;name&gt;: Fid the activities with the specified name</li>
* <li>GET /activities/current/durations: Get the durations of the current month, week and day</li>
* <li>GET /activities/years: Returns the years, months and weeks in which activities are stored</li>
* </ul>
* <p>CUD methods:</p>
* <ul>
* <li>POST /activities: Start a new activity. The data for the new activity must be provided in the request body.
* The new activity will be stored as the running activity. If there's another running activity that activity will be
* stopped first.<br/>
* The method returns 201 together with the created / modified activities in a collection (even if there was only one
* activity created).</li>
* <li>PUT /activities/{id}: Update an existing activity. The data for the activity must be provided in the request
* body. The end time of the activity is taken from the JSON input and the duration in minutes is calculated. There's
* one exception to this rule: If
* <ul>
* <li>the activity is stopped</li>
* <li>the init time is present</li>
* <li>the end time is not present and</li>
* <li>the duration in minutes is specified</li>
* </ul>
* then the end time is calculated. Please note that changes to the status of an activity are ignored by this method!
* The only way to change the status of an activity is to call the relvant method / url pair.<br/>
* The method returns 200 together with the updated activity.</li>
* <li>PUT /activities/{id}/copy/{period}: Copy an existing activity as a new activity and adds the specified period.
* The period must follow the format described at <a href="http://en.wikipedia.org/wiki/ISO_8601#Durations">ISO8601</a>.
* The status of the original activity is not touched.<br/>
* The method returns 201 together with the copied activity.</li>
* <li>PUT /activities/{id}/start: Start an existing activity. Depending on the activities start date the activity is
* resumed (start date == today) or started as a new activity (start date != today). If there's another running
* activity that activity will be stopped first.<br/>
* The method returns 200 together with all modified activities in a collection (even if there was only one activity
* modified). If the activity was already started nothing will happen and 304 is returned.</li>
* <li>PUT /activities/{id}/tick: Tick an existing activity i.e. sets the end time to the current time and saves the
* activity. If the activity is not yet started, it will be started first. If there's another running activity that
* activity will be stopped first.<br/>
* The method returns 200 together with all modified activities in a collection (even if there was only one activity
* modified).</li>
* <li>PUT /activities/{id}/stop: Stop an existing activity.<br/>
* The method returns 200 together with the updated activity. If the activity is already stopped nothing will happen
* and 304 is returned.</li>
* <li>DELETE /activities/{id}: Delete an existing activity and return 204.</li>
* </ul>
*
* @author $Author: harald.pehl $
* @version $Date: 2011-05-16 12:54:26 +0200 (Mo, 16. Mai 2011) $ $Revision: 110
*          $
* @todo implement ETag
*/
@Path("/activities")
@Cache(maxAge = 36000)
@Produces(APPLICATION_JSON)
public class ActivitiesResource
{
    @Context UriInfo uriInfo;
    @Inject @CurrentSettings Instance<Settings> settings;
    @Inject ActivityRepository repository;
    @Inject ActivityIndexSearch indexSearch;
    @Inject ActivitiesConverter activitiesConverter;
    @Inject ActivityConverter activityConverter;


    // ------------------------------------------------- years / months / weeks

    @GET
    @Path("/years")
    public Response years()
    {
        List<Activity> activities = repository.list();
        if (activities.isEmpty())
        {
            throw new NotFoundException("No activities found");
        }
        Map<Integer, Year> lookup = new HashMap<Integer, Year>();
        for (Activity activity : activities)
        {
            int y = activity.getStart().getYear();
            int m = activity.getStart().getMonth();
            int w = activity.getStart().getWeek();
            Year year = lookup.get(y);
            if (year == null)
            {
                year = new Year(y);
                lookup.put(y, year);
            }
            year.addMonth(m);
            year.addWeek(w);
        }
        Years years = new Years(new TreeSet<Year>(lookup.values()));

        String url = uriInfo.getAbsolutePath().toASCIIString();
        LinkHeader linkHeader = new LinkHeader().addLink(null, SELF, url, null);
        return Response.ok(years).header("Link", linkHeader.toString()).build();
    }


    // --------------------------------------------------------------- by month

    @GET
    @Path("/{year:\\d{4}}/{month:\\d{1,2}}")
    public Response activitiesForYearMonth(@PathParam("year") int year, @PathParam("month") int month)
    {
        DateMidnight yearMonth = new DateMidnight(year, month, 1, settings.get().getTimeZone());
        Activities activities = activitiesConverter.toModel(yearMonth, MONTH,
                repository.findByYearMonth(yearMonth.year().get(), yearMonth.monthOfYear().get()));
        return addLinksForYearMonth(activities, yearMonth);
    }

    @GET
    @Produces(TEXT_PLAIN)
    @Path("/{year:\\d{4}}/{month:\\d{1,2}}/duration")
    public Duration minutesForYearMonth(@PathParam("year") int year, @PathParam("month") int month)
    {
        DateMidnight date = new DateMidnight(year, month, 1, settings.get().getTimeZone());
        return minutes(repository.findByYearMonth(date.year().get(), date.monthOfYear().get()));
    }

    @GET
    @Path("/relative/{month:[+-]?\\d+}")
    public Response activitiesForRelativeMonth(@PathParam("month") int month)
    {
        DateMidnight absolute = absoluteMonth(month);
        Activities activities = activitiesConverter.toModel(absolute, MONTH,
                repository.findByYearMonth(absolute.year().get(), absolute.monthOfYear().get()));
        return addLinksForYearMonth(activities, absolute);
    }

    @GET
    @Produces(TEXT_PLAIN)
    @Path("/relative/{month:[+-]?\\d+}/duration")
    public Duration minutesForRelativeMonth(@PathParam("month") int month)
    {
        DateMidnight date = absoluteMonth(month);
        return minutes(repository.findByYearMonth(date.year().get(), date.monthOfYear().get()));
    }

    @GET
    @Path("/currentMonth")
    public Response activitiesForCurrentMonth()
    {
        DateMidnight now = now(settings.get().getTimeZone());
        Activities activities = activitiesConverter.toModel(now, MONTH,
                repository.findByYearMonth(now.year().get(), now.monthOfYear().get()));
        return addLinksForYearMonth(activities, now);
    }

    @GET
    @Produces(TEXT_PLAIN)
    @Path("/currentMonth/duration")
    public Duration minutesForCurrentMonth()
    {
        DateMidnight date = now(settings.get().getTimeZone());
        return minutes(repository.findByYearMonth(date.year().get(), date.monthOfYear().get()));
    }

    private DateMidnight absoluteMonth(int month)
    {
        DateMidnight now = now(settings.get().getTimeZone());
        return now.plus(months(month));
    }

    private Response addLinksForYearMonth(Activities activities, DateMidnight yearMonth)
    {
        LinkHeader linkHeader = new LinkHeader();
        String self = uriInfo.getAbsolutePath().toASCIIString();
        linkHeader.addLink(null, SELF, self, null);

        DateMidnight prevMonth = yearMonth.minusMonths(1);
        DateMidnight nextMonth = yearMonth.plusMonths(1);
        boolean hasPrev = repository.hasActivitiesByYearMonth(prevMonth.year().get(), prevMonth.monthOfYear().get());
        boolean hasNext = repository.hasActivitiesByYearMonth(nextMonth.year().get(), nextMonth.monthOfYear().get());
        if (hasPrev)
        {
            String prev = uriInfo.getBaseUriBuilder().path("activities")
                    .segment(String.valueOf(prevMonth.year().get()), String.valueOf(prevMonth.monthOfYear().get()))
                    .build().toASCIIString();
            linkHeader.addLink(null, PREV, prev, null);
        }
        if (hasNext)
        {
            String next = uriInfo.getBaseUriBuilder().path("activities")
                    .segment(String.valueOf(nextMonth.year().get()), String.valueOf(nextMonth.monthOfYear().get()))
                    .build().toASCIIString();
            linkHeader.addLink(null, NEXT, next, null);
        }

        Response.ResponseBuilder response;
        if (!activities.isEmpty())
        {
            response = Response.ok(activities);
        }
        else
        {
            response = Response.status(NOT_FOUND).entity(
                    String.format("No activities found for %d/%d", yearMonth.monthOfYear().get(),
                            yearMonth.year().get()));
        }
        response.header("Link", linkHeader.toString());
        return response.build();
    }


    // ------------------------------------------------------- by calendar week

    @GET
    @Path("/{year:\\d{4}}/cw{week:\\d{1,2}}")
    public Response activitiesForYearWeek(@PathParam("year") int year, @PathParam("week") int week)
    {
        DateMidnight yearWeek = new MutableDateTime(settings.get().getTimeZone()).year().set(year).weekOfWeekyear()
                .set(week)
                .toDateTime().toDateMidnight();
        Activities activities = activitiesConverter.toModel(yearWeek, WEEK,
                repository.findByYearWeek(yearWeek.year().get(), yearWeek.weekOfWeekyear().get()));
        return addLinksForYearWeek(activities, yearWeek);
    }

    @GET
    @Produces(TEXT_PLAIN)
    @Path("/{year:\\d{4}}/cw{week:\\d{1,2}}/duration")
    public Duration minutesForYearWeek(@PathParam("year") int year, @PathParam("week") int week)
    {
        DateMidnight yearWeek = new MutableDateTime(settings.get().getTimeZone()).year().set(year).weekOfWeekyear()
                .set(week)
                .toDateTime().toDateMidnight();
        return minutes(repository.findByYearWeek(yearWeek.year().get(), yearWeek.weekOfWeekyear().get()));
    }

    @GET
    @Path("/relative/cw{week:[+-]?\\d+}")
    public Response activitiesForRelativeWeek(@PathParam("week") int week)
    {
        DateMidnight absolute = absoluteWeek(week);
        Activities activities = activitiesConverter.toModel(absolute, WEEK,
                repository.findByYearWeek(absolute.year().get(), absolute.weekOfWeekyear().get()));
        return addLinksForYearWeek(activities, absolute);
    }

    @GET
    @Produces(TEXT_PLAIN)
    @Path("/relative/cw{week:[+-]?\\d+}/duration")
    public Duration minutesForRelativeWeek(@PathParam("week") int week)
    {
        DateMidnight date = absoluteWeek(week);
        return minutes(repository.findByYearWeek(date.year().get(), date.weekOfWeekyear().get()));
    }

    @GET
    @Path("/currentWeek")
    public Response activitiesForCurrentWeek()
    {
        DateMidnight now = now(settings.get().getTimeZone());
        Activities activities = activitiesConverter.toModel(now, WEEK,
                repository.findByYearWeek(now.year().get(), now.weekOfWeekyear().get()));
        return addLinksForYearWeek(activities, now);
    }

    @GET
    @Produces(TEXT_PLAIN)
    @Path("/currentWeek/duration")
    public Duration minutesForCurrentWeek()
    {
        DateMidnight date = now(settings.get().getTimeZone());
        return minutes(repository.findByYearWeek(date.year().get(), date.weekOfWeekyear().get()));
    }

    private DateMidnight absoluteWeek(int week)
    {
        DateMidnight now = now(settings.get().getTimeZone());
        return now.plus(weeks(week));
    }

    private Response addLinksForYearWeek(Activities activities, DateMidnight yearWeek)
    {
        LinkHeader linkHeader = new LinkHeader();
        String self = uriInfo.getAbsolutePath().toASCIIString();
        linkHeader.addLink(null, SELF, self, null);

        DateMidnight prevWeek = yearWeek.minusWeeks(1);
        DateMidnight nextWeek = yearWeek.plusWeeks(1);
        boolean hasPrev = repository.hasActivitiesByYearWeek(prevWeek.year().get(), prevWeek.weekOfWeekyear().get());
        boolean hasNext = repository.hasActivitiesByYearWeek(nextWeek.year().get(), nextWeek.weekOfWeekyear().get());
        if (hasPrev)
        {
            String prev = uriInfo
                    .getBaseUriBuilder()
                    .path("activities")
                    .segment(String.valueOf(prevWeek.year().get()),
                            "cw" + String.valueOf(prevWeek.weekOfWeekyear().get())).build().toASCIIString();
            linkHeader.addLink(null, PREV, prev, null);
        }
        if (hasNext)
        {
            String next = uriInfo
                    .getBaseUriBuilder()
                    .path("activities")
                    .segment(String.valueOf(nextWeek.year().get()),
                            "cw" + String.valueOf(nextWeek.weekOfWeekyear().get())).build().toASCIIString();
            linkHeader.addLink(null, NEXT, next, null);
        }

        Response.ResponseBuilder response;
        if (!activities.isEmpty())
        {
            response = Response.ok(activities);
        }
        else
        {
            response = Response.status(NOT_FOUND).entity(
                    String.format("No activities found for CW %d/%d", yearWeek.weekOfWeekyear().get(),
                            yearWeek.year().get()));
        }
        response.header("Link", linkHeader.toString());
        return response.build();
    }


    // ----------------------------------------------------------------- by day

    @GET
    @Path("/{year:\\d{4}}/{month:\\d{1,2}}/{day:\\d{1,2}}")
    public Response activitiesForYearMonthDay(@PathParam("year") int year, @PathParam("month") int month,
            @PathParam("day") int day)
    {
        DateMidnight yearMonthDay = new DateMidnight(year, month, day, settings.get().getTimeZone());
        Activities activities = activitiesConverter.toModel(yearMonthDay, DAY,
                repository.findByYearMonthDay(yearMonthDay.year().get(), yearMonthDay.monthOfYear().get(), yearMonthDay
                        .dayOfMonth().get()));
        return addLinksForYearMonthDay(activities, yearMonthDay);
    }

    @GET
    @Produces(TEXT_PLAIN)
    @Path("/{year:\\d{4}}/{month:\\d{1,2}}/{day:\\d{1,2}}/duration")
    public Duration minutesForYearMonthDay(@PathParam("year") int year, @PathParam("month") int month,
            @PathParam("day") int day)
    {
        DateMidnight date = new DateMidnight(year, month, day, settings.get().getTimeZone());
        return minutes(repository.findByYearMonthDay(date.year().get(), date.monthOfYear().get(), date
                .dayOfMonth().get()));
    }

    @GET
    @Path("/today")
    public Response activitiesForToday()
    {
        DateMidnight now = now(settings.get().getTimeZone());
        Activities activities = activitiesConverter.toModel(now, DAY,
                repository.findByYearMonthDay(now.year().get(), now.monthOfYear().get(), now
                        .dayOfMonth().get()));
        return addLinksForYearMonthDay(activities, now);
    }

    @GET
    @Produces(TEXT_PLAIN)
    @Path("/today/duration")
    public Duration minutesForToday()
    {
        DateMidnight date = now(settings.get().getTimeZone());
        return minutes(repository.findByYearMonthDay(date.year().get(), date.monthOfYear().get(), date
                .dayOfMonth().get()));
    }

    private Response addLinksForYearMonthDay(Activities activities, DateMidnight yearMonthDay)
    {
        LinkHeader linkHeader = new LinkHeader();
        String self = uriInfo.getAbsolutePath().toASCIIString();
        linkHeader.addLink(null, SELF, self, null);

        DateMidnight prevDay = yearMonthDay.minusDays(1);
        DateMidnight nextDay = yearMonthDay.plusDays(1);
        boolean hasPrev = repository.hasActivitiesByYearMonthDay(prevDay.year().get(), prevDay.monthOfYear().get(),
                prevDay.dayOfMonth().get());
        boolean hasNext = repository.hasActivitiesByYearMonthDay(nextDay.year().get(), nextDay.monthOfYear().get(),
                nextDay.dayOfMonth().get());
        if (hasPrev)
        {
            String prev = uriInfo
                    .getBaseUriBuilder()
                    .path("activities")
                    .segment(String.valueOf(prevDay.year().get()), String.valueOf(prevDay.monthOfYear().get()),
                            String.valueOf(prevDay.dayOfMonth().get())).build().toASCIIString();
            linkHeader.addLink(null, PREV, prev, null);
        }
        if (hasNext)
        {
            String next = uriInfo
                    .getBaseUriBuilder()
                    .path("activities")
                    .segment(String.valueOf(nextDay.year().get()), String.valueOf(nextDay.monthOfYear().get()),
                            String.valueOf(nextDay.dayOfMonth().get())).build().toASCIIString();
            linkHeader.addLink(null, NEXT, next, null);
        }

        Response.ResponseBuilder response;
        if (!activities.isEmpty())
        {
            response = Response.ok(activities);
        }
        else
        {
            response = Response.status(NOT_FOUND).entity(String
                    .format("No activities found for %d/%d/%d", yearMonthDay.dayOfMonth().get(),
                            yearMonthDay.monthOfYear().get(), yearMonthDay.year().get()));
        }
        response.header("Link", linkHeader.toString());
        return response.build();
    }


    // ----------------------------------------------------------------- by range

    @GET
    @Path("/{from:\\d{8}}/{to:\\d{8}}")
    public Response activitiesInRange(@PathParam("from") String from, @PathParam("to") String to)
    {
        DateTime start = null;
        try
        {
            start = ISODateTimeFormat.basicDate().parseDateTime(from);
        }
        catch (IllegalArgumentException e)
        {
            return Response.status(BAD_REQUEST).entity(String.format("Invalid start date: %s", start)).build();
        }
        DateTime end = null;
        try
        {
            end = ISODateTimeFormat.basicDate().parseDateTime(to);
        }
        catch (IllegalArgumentException e)
        {
            return Response.status(BAD_REQUEST).entity(String.format("Invalid end date: %s", end)).build();
        }
        List<Activity> range = repository.findByRange(start, end);
        if (!range.isEmpty())
        {
            // TODO Custom TimeUnit 'RANGE'?
            Activities activities = activitiesConverter.toModel(start.toDateMidnight(), DAY, range);
            return Response.ok(activities).build();
        }
        return Response.status(NOT_FOUND).entity(String.format("No activities found in range [%s,%s]", from, to)).build();
    }


    // ------------------------------------------------ find activities by name

    @GET
    @NoCache
    public List<name.pehl.karaka.shared.model.Activity> findByName(@QueryParam("q") String query)
    {
        Map<SameActivity, name.pehl.karaka.shared.model.Activity> activities = new HashMap<SameActivity, name.pehl.karaka.shared.model.Activity>();
        Results<ScoredDocument> results = indexSearch.search(query);
        for (ScoredDocument scoredDocument : results)
        {
            Long id = Long.valueOf(scoredDocument.getId());
            Activity activity = repository.get(id);
            if (activity != null)
            {
                activities.put(new SameActivity(activity), activityConverter.toModel(activity));
            }
        }
        return new ArrayList<name.pehl.karaka.shared.model.Activity>(activities.values());
    }


    // --------------------------------- minutes of current month, week and day

    @GET
    @Path("/current/durations")
    public Response minutesForCurrentMonthWeekAndDay()
    {
        DateMidnight now = now(settings.get().getTimeZone());
        int year = now.year().get();
        int month = now.monthOfYear().get();
        int week = now.weekOfWeekyear().get();
        int day = now.dayOfMonth().get();
        Duration currentMonth = minutes(repository.findByYearMonth(year, month));
        Duration currentWeek = minutes(repository.findByYearWeek(year, week));
        Duration today = minutes(repository.findByYearMonthDay(year, month, day));
        Durations durations = new Durations(currentMonth, currentWeek, today);

        String url = uriInfo.getAbsolutePath().toASCIIString();
        LinkHeader linkHeader = new LinkHeader().addLink(null, SELF, url, null);
        return Response.ok(durations).header("Link", linkHeader.toString()).build();
    }


    // -------------------------------------------------------------- by status

    @GET
    @Path("/running")
    public name.pehl.karaka.shared.model.Activity runningActivity()
    {
        Activity activity = repository.findRunningActivity();
        if (activity == null)
        {
            throw new NotFoundException("No running activity");
        }
        return activityConverter.toModel(activity);
    }

    @GET
    @Path("/latest")
    public name.pehl.karaka.shared.model.Activity latestActivity()
    {
        Activity activity = repository.findLatestActivity();
        if (activity == null)
        {
            throw new NotFoundException("No latest activity");
        }
        return activityConverter.toModel(activity);
    }


    // ------------------------------------------------------------ CUD methods

    @POST
    public Response createNewActivity(name.pehl.karaka.shared.model.Activity clientActivity)
    {
        Activity serverActivity = activityConverter.fromModel(clientActivity);
        Activity savedActivity = repository.save(serverActivity);
        name.pehl.karaka.shared.model.Activity newClientActivity = activityConverter.toModel(savedActivity);
        return Response.status(CREATED).entity(newClientActivity).build();
    }

    @PUT
    @Path("/{id}")
    public Response updateActivity(@PathParam("id") String id,
            name.pehl.karaka.shared.model.Activity clientActivity)
    {
        try
        {
            Activity serverActivity = repository.get(id);
            activityConverter.merge(clientActivity, serverActivity);
            Activity savedActivity = repository.save(serverActivity);
            name.pehl.karaka.shared.model.Activity updatedClientActivity = activityConverter.toModel(savedActivity);
            return Response.ok(updatedClientActivity).build();
        }
        catch (com.googlecode.objectify.NotFoundException e)
        {
            return Response.status(NOT_FOUND).build();
        }
    }

    @PUT
    @Path("/{id}/copy/{period}")
    public Response copyActivity(@PathParam("id") String id, @PathParam("period") String period)
    {
        try
        {
            Activity activity = repository.get(id);
            Activity copy = activity.copy(period);
            Activity savedActivity = repository.save(copy);
            name.pehl.karaka.shared.model.Activity clientCopy = activityConverter.toModel(savedActivity);
            return Response.status(CREATED).entity(clientCopy).build();
        }
        catch (com.googlecode.objectify.NotFoundException e)
        {
            return Response.status(NOT_FOUND).build();
        }
        catch (IllegalArgumentException e)
        {
            return Response.status(BAD_REQUEST).entity(
                    "Illegal format for period \"" + period + "\". See http://en.wikipedia.org/wiki/ISO_8601#Durations for a valid format")
                    .build();
        }
    }

    @PUT
    @Path("/start")
    public Response startNewActivity(name.pehl.karaka.shared.model.Activity clientActivity)
    {
        // TODO Is it an error if the client activity already exists on the server?
        Activity newServerActivity = activityConverter.fromModel(clientActivity);
        Activity savedActivity = repository.save(newServerActivity);
        Iterable<Activity> modifiedActivities = repository.start(savedActivity);
        Set<name.pehl.karaka.shared.model.Activity> clientActivities = new HashSet<name.pehl.karaka.shared.model.Activity>();
        for (Activity modifiedActivity : modifiedActivities)
        {
            clientActivities.add(activityConverter.toModel(modifiedActivity));
        }
        return Response.status(CREATED).entity(clientActivities).build();
    }

    @PUT
    @Path("/{id}/start")
    public Response startActivity(@PathParam("id") String id)
    {
        try
        {
            Activity activity = repository.get(id);
            Iterable<Activity> modifiedActivities = repository.start(activity);
            Set<name.pehl.karaka.shared.model.Activity> clientActivities = new HashSet<name.pehl.karaka.shared.model.Activity>();
            for (Activity modifiedActivity : modifiedActivities)
            {
                clientActivities.add(activityConverter.toModel(modifiedActivity));
            }
            return Response.ok(clientActivities).build();
        }
        catch (com.googlecode.objectify.NotFoundException e)
        {
            return Response.status(NOT_FOUND).build();
        }
    }

    @PUT
    @Path("/{id}/tick")
    public Response tickActivity(@PathParam("id") String id)
    {
        try
        {
            Activity activity = repository.get(id);
            Iterable<Activity> modifiedActivities = repository.tick(activity);
            Set<name.pehl.karaka.shared.model.Activity> clientActivities = new HashSet<name.pehl.karaka.shared.model.Activity>();
            for (Activity modifiedActivity : modifiedActivities)
            {
                clientActivities.add(activityConverter.toModel(modifiedActivity));
            }
            return Response.ok(clientActivities).build();
        }
        catch (com.googlecode.objectify.NotFoundException e)
        {
            return Response.status(NOT_FOUND).build();
        }
    }

    @PUT
    @Path("/{id}/stop")
    public Response stopActivity(@PathParam("id") String id)
    {
        try
        {
            Activity activity = repository.get(id);
            if (activity.getStatus() == STOPPED)
            {
                return Response.status(NOT_MODIFIED).build();
            }
            else
            {
                activity.stop();
                Activity savedActivity = repository.save(activity);
                name.pehl.karaka.shared.model.Activity clientActivity = activityConverter.toModel(savedActivity);
                return Response.ok(clientActivity).build();
            }
        }
        catch (com.googlecode.objectify.NotFoundException e)
        {
            return Response.status(NOT_FOUND).build();
        }
    }

    @DELETE
    @Path("/{id}")
    public Response deleteActivity(@PathParam("id") String id)
    {
        try
        {
            Activity activity = repository.get(id);
            repository.delete(activity);
            return Response.noContent().build();
        }
        catch (com.googlecode.objectify.NotFoundException e)
        {
            return Response.status(NOT_FOUND).build();
        }
    }


    // --------------------------------------------------------- helper methods

    private DateMidnight now(DateTimeZone timeZone)
    {
        return new DateMidnight(timeZone);
    }

    private Duration minutes(List<Activity> activities)
    {
        long minutes = 0;
        for (Activity activity : activities)
        {
            minutes += activity.getDuration();
        }
        return new Duration(minutes);
    }
}
TOP

Related Classes of name.pehl.karaka.server.activity.boundary.ActivitiesResource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.