de.egore911.reader.servlets.OpmlImportServlet.java Source code

Java tutorial

Introduction

Here is the source code for de.egore911.reader.servlets.OpmlImportServlet.java

Source

/*
 *   Copyright 2013 Christoph Brill
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package de.egore911.reader.servlets;

import java.io.IOException;
import java.io.InputStream;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.users.User;
import com.google.common.base.Strings;

import de.egore911.reader.dao.CategoryDao;
import de.egore911.reader.dao.FeedDao;
import de.egore911.reader.dao.FeedUserDao;
import de.egore911.reader.model.Category;
import de.egore911.reader.model.Feed;
import de.egore911.reader.model.FeedUser;

/**
 * Handle GET and POST requests for OPML import.
 * 
 * @author Christoph Brill
 */
public class OpmlImportServlet extends AbstractHtmlServlet {

    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        User user = getUserOrRedirect(resp);
        if (user == null) {
            return;
        }

        prepareTree(req, user);

        req.getRequestDispatcher("/import.jsp").forward(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        User user = getUserOrRedirect(resp);
        if (user == null) {
            return;
        }

        boolean success = false;
        String reason = null;
        ServletFileUpload upload = new ServletFileUpload();
        CategoryDao categoryDao = new CategoryDao();
        FeedUserDao feedUserDao = new FeedUserDao();
        FeedDao feedDao = new FeedDao();
        try {
            FileItemIterator iter = upload.getItemIterator(req);
            // Parse the request
            while (iter.hasNext()) {
                FileItemStream item = iter.next();
                String name = item.getFieldName();
                if ("subscriptions".equals(name) && !item.isFormField()
                        && "text/xml".equals(item.getContentType())) {
                    try (InputStream stream = item.openStream()) {
                        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
                        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
                        Document document = documentBuilder.parse(stream);

                        document.getDocumentElement().normalize();

                        Element opml = document.getDocumentElement();
                        if (!"opml".equals(opml.getTagName())) {
                            throw new ServletException("Invalid XML");
                        }

                        NodeList nodes = opml.getChildNodes();
                        for (int i = 0; i < nodes.getLength(); i++) {
                            Node node = nodes.item(i);
                            if (node.getNodeType() == Node.ELEMENT_NODE) {
                                Element element = (Element) node;
                                if ("body".equals(element.getTagName())) {
                                    if (countFeeds(element.getChildNodes()) < 20) {
                                        importRecursive(categoryDao, feedUserDao, feedDao, user, Category.ROOT,
                                                element.getChildNodes());
                                        success = true;
                                    } else {
                                        reason = "to_many_feeds";
                                    }
                                }
                            }
                        }

                    } catch (ParserConfigurationException | SAXException e) {
                        throw new ServletException(e.getMessage(), e);
                    }
                }
            }
        } catch (FileUploadException e) {
            throw new ServletException(e.getMessage(), e);
        }

        if (success) {
            resp.sendRedirect("/reader");
        } else {
            String redirectTo = "/import?msg=import_failed";
            if (reason != null) {
                redirectTo += "&reason=" + reason;
            }
            resp.sendRedirect(redirectTo);
        }
    }

    private int countFeeds(NodeList nodes) throws ServletException {
        int result = 0;
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element element = (Element) node;
                if (!"outline".equals(element.getTagName())) {
                    throw new ServletException("Invalid XML");
                }
                String xmlUrl = element.getAttribute("xmlUrl");
                if (Strings.isNullOrEmpty(xmlUrl)) {
                    // It does not have a xmlUrl -> this is a category
                    result += countFeeds(element.getChildNodes());
                } else {
                    result++;
                }
            }
        }
        return result;
    }

    @SuppressWarnings("null")
    private void importRecursive(@Nonnull CategoryDao categoryDao, @Nonnull FeedUserDao feedUserDao,
            @Nonnull FeedDao feedDao, @Nonnull User user, @Nullable Key parent, NodeList nodes)
            throws ServletException {
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element element = (Element) node;
                if (!"outline".equals(element.getTagName())) {
                    throw new ServletException("Invalid XML");
                }
                String xmlUrl = element.getAttribute("xmlUrl");
                String title = element.getAttribute("title");
                if (Strings.isNullOrEmpty(xmlUrl)) {
                    // It does not have a xmlUrl -> this is a category
                    if (title == null) {
                        throw new ServletException("Invalid XML");
                    }
                    Category category = categoryDao.getByName(title, user, parent);
                    if (category == null) {
                        category = new Category(parent, title, user);
                        categoryDao.persist(category);
                    }
                    importRecursive(categoryDao, feedUserDao, feedDao, user, category.getId(),
                            element.getChildNodes());
                } else {
                    Feed feed = feedDao.getByUrl(xmlUrl);
                    if (feed == null) {
                        feed = new Feed(title, xmlUrl);
                        feedDao.persist(feed);
                        FeedUser feedUser = new FeedUser(feed.getId(), user, parent);
                        feedUserDao.persist(feedUser);
                    } else {
                        boolean found = false;
                        for (FeedUser feedUser : feedUserDao.getFeedUsers(feed.getId())) {
                            if (feedUser.getUser().equals(user)) {
                                found = true;
                                break;
                            }
                        }
                        if (!found) {
                            FeedUser feedUser = new FeedUser(feed.getId(), user, parent);
                            feedUserDao.persist(feedUser);
                        }
                    }
                }
            }
        }
    }

}