com.wibidata.shopping.servlet.HomePageServlet.java Source code

Java tutorial

Introduction

Here is the source code for com.wibidata.shopping.servlet.HomePageServlet.java

Source

/**
 * (c) Copyright 2013 WibiData, Inc.
 *
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * 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 com.wibidata.shopping.servlet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.NavigableMap;
import java.util.TreeMap;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.hadoop.hbase.HConstants;

import org.kiji.mapreduce.lib.avro.Node;
import org.kiji.schema.EntityId;
import org.kiji.schema.Kiji;
import org.kiji.schema.KijiDataRequest;
import org.kiji.schema.KijiDataRequestBuilder;
import org.kiji.schema.KijiDataRequestException;
import org.kiji.schema.KijiRowData;
import org.kiji.schema.KijiRowScanner;
import org.kiji.schema.KijiTable;
import org.kiji.schema.KijiTableReader;
import org.kiji.schema.KijiTableReader.KijiScannerOptions;
import org.kiji.schema.util.ResourceUtils;
import org.kiji.scoring.FreshKijiTableReaderBuilder;

import com.wibidata.shopping.KijiContextListener;
import com.wibidata.shopping.avro.FavoriteWord;
import com.wibidata.shopping.avro.FavoriteWords;
import com.wibidata.shopping.avro.ProductRating;
import com.wibidata.shopping.avro.ProductRecommendation;
import com.wibidata.shopping.avro.ProductRecommendations;
import com.wibidata.shopping.model.Category;
import com.wibidata.shopping.model.Product;

/**
 * The home page servlet.
 */
public class HomePageServlet extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

        request.setCharacterEncoding("UTF-8");

        final Kiji kiji = (Kiji) getServletContext().getAttribute(KijiContextListener.KIJI_ATTRIBUTE);
        final KijiTable categoryTable = kiji.openTable("kiji_shopping_category");

        // Read the products by category.
        KijiTableReader reader = categoryTable.openTableReader();
        KijiRowScanner scanner = null;
        List<Category> categories = new ArrayList<Category>();
        try {
            KijiDataRequestBuilder drBuilder = KijiDataRequest.builder();
            drBuilder.newColumnsDef().add("related", "product");
            final KijiDataRequest dataRequest = drBuilder.build();

            final KijiScannerOptions scanOptions = new KijiScannerOptions()
                    .setStartRow(categoryTable.getEntityId("category:"))
                    .setStopRow(categoryTable.getEntityId("category;"));

            scanner = reader.getScanner(dataRequest, scanOptions);
            for (KijiRowData row : scanner) {
                if (row.containsColumn("related", "product")) {
                    Category category = Category.fromProducts((Node) row.getMostRecentValue("related", "product"));
                    categories.add(category);
                }
            }
        } catch (KijiDataRequestException e) {
            throw new IOException(e);
        } finally {
            ResourceUtils.closeOrLog(scanner);
            ResourceUtils.closeOrLog(reader);
            ResourceUtils.releaseOrLog(categoryTable);
        }
        request.setAttribute("categories", categories);

        // If the user is logged in, read their recent ratings, favorite
        // words, and recommendations.
        if (null != request.getSession().getAttribute("login")) {
            final String login = request.getSession().getAttribute("login").toString();
            final KijiTable userTable = kiji.openTable("kiji_shopping_user");
            final KijiTable productTable = kiji.openTable("kiji_shopping_product");
            try {
                List<ProductRating> ratings = getRecentRatings(userTable, login);
                if (null != ratings) {
                    request.setAttribute("recentRatings", ratings);
                }
                List<FavoriteWord> favoriteWords = getFavoriteWords(userTable, login);
                if (null != favoriteWords) {
                    request.setAttribute("favoriteWords", favoriteWords);
                }
                List<Product> productRecommendations = getProductRecommendations(userTable, productTable, login);
                if (null != productRecommendations) {
                    request.setAttribute("productRecommendations", productRecommendations);
                }
            } finally {
                ResourceUtils.releaseOrLog(productTable);
                ResourceUtils.releaseOrLog(userTable);
            }
        }

        request.getRequestDispatcher("/WEB-INF/view/HomePage.jsp").forward(request, response);
    }

    private List<ProductRating> getRecentRatings(KijiTable userTable, String login) throws IOException {
        KijiTableReader reader = userTable.openTableReader();
        try {
            final long now = System.currentTimeMillis();
            final long lastWeek = now - DateUtils.MILLIS_PER_DAY * 7L;

            EntityId entityId = userTable.getEntityId(login);
            KijiDataRequestBuilder drBuilder = KijiDataRequest.builder();
            drBuilder.newColumnsDef().addFamily("rating");
            drBuilder.withTimeRange(lastWeek, HConstants.LATEST_TIMESTAMP);
            KijiDataRequest dataRequest = drBuilder.build();

            KijiRowData row = reader.get(entityId, dataRequest);
            if (row.containsColumn("rating")) {
                NavigableMap<String, NavigableMap<Long, ProductRating>> ratingsMap = row.getValues("rating");
                NavigableMap<Long, ProductRating> sortedRatings = new TreeMap<Long, ProductRating>();
                for (NavigableMap<Long, ProductRating> value : ratingsMap.values()) {
                    for (NavigableMap.Entry<Long, ProductRating> entry : value.entrySet()) {
                        sortedRatings.put(entry.getKey(), entry.getValue());
                    }
                }
                return new ArrayList<ProductRating>(sortedRatings.descendingMap().values());
            }
            return null;
        } catch (KijiDataRequestException e) {
            throw new IOException(e);
        } finally {
            IOUtils.closeQuietly(reader);
        }
    }

    /**
     * Reads the dish recommendations from the user table.
     *
     * @param userTable The user table.
     * @param productTable The product table.
     * @param login The user's login username.
     * @return A list of the user's product recommendations (may be null).
     */
    private List<Product> getProductRecommendations(KijiTable userTable, KijiTable productTable, String login)
            throws IOException {
        KijiTableReader reader = FreshKijiTableReaderBuilder.create().withTable(userTable).withTimeout(1000)
                .build();
        try {
            EntityId entityId = userTable.getEntityId(login);
            KijiDataRequestBuilder drBuilder = KijiDataRequest.builder();
            drBuilder.newColumnsDef().add("personalization", "product_recommendations");
            KijiDataRequest dataRequest = drBuilder.build();
            KijiRowData row = reader.get(entityId, dataRequest);
            if (row.containsColumn("personalization", "product_recommendations")) {
                List<Product> productRecommendations = getProducts(productTable, row
                        .<ProductRecommendations>getMostRecentValue("personalization", "product_recommendations"));
                return productRecommendations;
            }
            return null;
        } catch (KijiDataRequestException e) {
            throw new IOException(e);
        } finally {
            IOUtils.closeQuietly(reader);
        }
    }

    /**
     * Turns the avro ProductRecommendations type into a POJO for display.
     *
     * @param productRecommendations The avro data.
     * @return A POJO representing the list of dishes.
     */
    private List<Product> getProducts(KijiTable productTable, ProductRecommendations productRecommendations)
            throws IOException {
        List<Product> productList = new ArrayList<Product>();
        List<EntityId> productIds = new ArrayList<EntityId>();
        for (ProductRecommendation productRecommendation : productRecommendations.getRecommendations()) {
            productIds.add(productTable.getEntityId(productRecommendation.getId().toString()));
        }

        // Get the product details for display.
        KijiTableReader reader = productTable.openTableReader();
        try {
            KijiDataRequestBuilder drBuilder = KijiDataRequest.builder();
            drBuilder.newColumnsDef().add("info", "id").add("info", "name").add("info", "price")
                    .add("info", "description_short").add("info", "thumbnail");
            KijiDataRequest dataRequest = drBuilder.build();

            List<KijiRowData> rows = reader.bulkGet(productIds, dataRequest);
            for (KijiRowData row : rows) {
                Product product = new Product();
                product.setId(row.getMostRecentValue("info", "id").toString());
                if (row.containsColumn("info", "name")) {
                    product.setName(row.getMostRecentValue("info", "name").toString());
                }
                if (row.containsColumn("info", "description_short")) {
                    product.setDescription(row.getMostRecentValue("info", "description_short").toString());
                }
                if (row.containsColumn("info", "thumbnail")) {
                    product.setThumbnail(row.getMostRecentValue("info", "thumbnail").toString());
                }
                productList.add(product);
                if (productList.size() >= 4) {
                    // Show at most 4 recommendations on the page.
                    break;
                }
            }
        } catch (KijiDataRequestException e) {
            throw new IOException(e);
        } finally {
            IOUtils.closeQuietly(reader);
        }

        return productList;
    }

    /**
     * Reads the favorite ingredients from the user table.
     *
     * @param userTable The user table.
     * @param login The user's login username.
     * @return A list of the user's favorite ingredients (may be null).
     */
    private List<FavoriteWord> getFavoriteWords(KijiTable userTable, String login) throws IOException {
        KijiTableReader reader = FreshKijiTableReaderBuilder.create().withTable(userTable).withTimeout(1000)
                .build();

        try {
            EntityId entityId = userTable.getEntityId(login);
            KijiDataRequestBuilder drBuilder = KijiDataRequest.builder();
            drBuilder.newColumnsDef().add("personalization", "favorite_words");
            KijiDataRequest dataRequest = drBuilder.build();

            KijiRowData row = reader.get(entityId, dataRequest);
            if (row.containsColumn("personalization", "favorite_words")) {
                FavoriteWords favoriteWords = row.getMostRecentValue("personalization", "favorite_words");
                return favoriteWords.getWords();
            }
            return null;
        } catch (KijiDataRequestException e) {
            throw new IOException(e);
        } finally {
            IOUtils.closeQuietly(reader);
        }
    }
}