/*
* Copyright © 2015 Cask Data, Inc.
*
* 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 co.cask.cdap.examples.profiles;
import co.cask.cdap.api.annotation.UseDataSet;
import co.cask.cdap.api.common.Bytes;
import co.cask.cdap.api.dataset.table.Delete;
import co.cask.cdap.api.dataset.table.Get;
import co.cask.cdap.api.dataset.table.Put;
import co.cask.cdap.api.dataset.table.Row;
import co.cask.cdap.api.dataset.table.Scanner;
import co.cask.cdap.api.dataset.table.Table;
import co.cask.cdap.api.service.AbstractService;
import co.cask.cdap.api.service.http.AbstractHttpServiceHandler;
import co.cask.cdap.api.service.http.HttpServiceRequest;
import co.cask.cdap.api.service.http.HttpServiceResponder;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import org.jboss.netty.buffer.ChannelBufferInputStream;
import org.jboss.netty.buffer.ChannelBuffers;
import java.io.InputStreamReader;
import java.util.List;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
/**
* A service for creating and modifying user profiles.
*/
public class UserProfileService extends AbstractService {
private static final Gson GSON = new Gson();
@Override
protected void configure() {
setName("UserProfileService");
setDescription("A service for creating and modifying user profiles");
addHandler(new UserProfileServiceHandler());
}
/**
* Handler to create, update, and retrieve user profiles.
*/
public class UserProfileServiceHandler extends AbstractHttpServiceHandler {
@UseDataSet("profiles")
private Table profiles;
@GET
@Path("profiles")
public void getProfiles(HttpServiceRequest request, HttpServiceResponder responder,
@QueryParam("users") String users,
@QueryParam("limit") @DefaultValue("10") int limit) {
List<Profile> profilesList = Lists.newArrayList();
// if the users query param is given, get the users given using a multi-get
if (users != null && !users.isEmpty()) {
// expecting the users param to be a comma separated list of users
String[] usersArr = users.split("\\s*,\\s*");
// create a list of Gets, one for each user
List<Get> gets = Lists.newArrayListWithCapacity(usersArr.length);
for (String user : usersArr) {
gets.add(new Get(Bytes.toBytes(user)));
}
// add up to limit number of users.
int profilesAdded = 0;
for (Row row : profiles.get(gets)) {
// row is empty if it could not be found.
if (row.isEmpty()) {
continue;
}
if (profilesAdded >= limit) {
break;
}
profilesList.add(toProfile(row));
profilesAdded++;
}
} else {
// otherwise, scan the entire table
Scanner scanner = profiles.scan(null, null);
try {
Row row;
int profilesAdded = 0;
while (profilesAdded < limit && (row = scanner.next()) != null) {
profilesList.add(toProfile(row));
profilesAdded++;
}
} finally {
scanner.close();
}
}
responder.sendJson(200, profilesList);
}
@GET
@Path("profiles/{user-id}")
public void getProfile(HttpServiceRequest request, HttpServiceResponder responder,
@PathParam("user-id") String userId) {
Row row = profiles.get(new Get(userId));
if (row.isEmpty()) {
responder.sendError(404, "No such user id.");
return;
}
responder.sendJson(200, toProfile(row));
}
@PUT
@Path("profiles/{user-id}")
public void createProfile(HttpServiceRequest request, HttpServiceResponder responder,
@PathParam("user-id") String userId) {
Row row = profiles.get(new Get(userId));
if (!row.isEmpty()) {
responder.sendError(409, "User already exists.");
return;
}
Profile profile = GSON.fromJson(new InputStreamReader(
new ChannelBufferInputStream(
ChannelBuffers.wrappedBuffer(request.getContent()))),
Profile.class);
if (profile.getId() == null || profile.getName() == null || profile.getEmail() == null) {
responder.sendError(400, "Profile must contain id, name, and email.");
return;
}
if (!userId.equals(profile.getId())) {
responder.sendError(400, "User id of profile must match user id in path.");
return;
}
if (profile.getLastLogin() != null || profile.getLastActivity() != null) {
responder.sendError(400, "Profile must not contain lastLogin or lastActivity.");
return;
}
Put put = new Put(userId);
put.add("id", userId);
put.add("name", profile.getName());
put.add("email", profile.getEmail());
profiles.put(put);
responder.sendStatus(201); // Created
}
@DELETE
@Path("profiles/{user-id}")
public void deleteProfile(HttpServiceRequest request, HttpServiceResponder responder,
@PathParam("user-id") String userId) {
Row row = profiles.get(new Get(userId));
if (row.isEmpty()) {
responder.sendError(404, "No such user id.");
return;
}
Delete delete = new Delete(userId);
profiles.delete(delete);
responder.sendStatus(200);
}
@PUT
@Path("profiles/{user-id}/email")
public void updateEmail(HttpServiceRequest request, HttpServiceResponder responder,
@PathParam("user-id") String userId) {
String address = Charsets.UTF_8.decode(request.getContent()).toString();
if (!address.contains("@")) {
responder.sendError(400, "Invalid email address.");
return;
}
Row row = profiles.get(new Get(userId));
if (row.isEmpty()) {
responder.sendError(404, "No such user id.");
return;
}
Put put = new Put(userId, "email", address);
profiles.put(put);
responder.sendStatus(200);
}
@PUT
@Path("profiles/{user-id}/lastLogin")
public void updateLastLogin(HttpServiceRequest request, HttpServiceResponder responder,
@PathParam("user-id") String userId) {
String body = Charsets.UTF_8.decode(request.getContent()).toString();
long time;
try {
time = Long.parseLong(body);
} catch (NumberFormatException e) {
responder.sendError(400, "Invalid time value.");
return;
}
Row row = profiles.get(new Get(userId));
if (row.isEmpty()) {
responder.sendError(404, "No such user id.");
return;
}
Put put = new Put(userId, "login", time);
profiles.put(put);
responder.sendStatus(200);
}
private Profile toProfile(Row row) {
String userId = Bytes.toString(row.getRow());
String name = row.getString("name");
String email = row.getString("email");
Long lastLogin = row.getLong("login");
Long lastActive = row.getLong("active");
return new Profile(userId, name, email, lastLogin, lastActive);
}
}
}