org.apache.sling.hapi.client.impl.microdata.MicrodataDocument.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.sling.hapi.client.impl.microdata.MicrodataDocument.java

Source

/*******************************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * 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 org.apache.sling.hapi.client.impl.microdata;

import org.apache.http.NameValuePair;
import org.apache.sling.hapi.client.*;
import org.apache.sling.hapi.client.forms.internal.FormValues;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;

public class MicrodataDocument implements Document {
    private org.jsoup.nodes.Document jsoupDocument;
    private HtmlClient client;

    public MicrodataDocument(String html, HtmlClient client, String baseUrl) {
        this.jsoupDocument = Jsoup.parse(html, baseUrl);
        this.client = client;
    }

    @Override
    public Items link(String rel) throws ClientException {
        Item me = toItem(jsoupDocument);
        return me.link(rel);
    }

    @Override
    public Items form(String rel) throws ClientException {
        Item me = toItem(jsoupDocument);
        return me.form(rel);
    }

    @Override
    public Items item(String rel) {
        List<Item> items = new ArrayList<Item>();

        for (Item i : items()) {
            if (((ItemImpl) i).el.hasClass(rel)) {
                items.add(i);
            }
        }

        return new ItemsImpl(items);
    }

    @Override
    public Items items() {
        return new ItemsImpl(selectItems(jsoupDocument, new ArrayList<Item>()));
    }

    @Override
    public String toString() {
        return this.jsoupDocument.toString();
    }

    private String toClass(String name) {
        return "." + name;
    }

    private List<Item> toItems(Elements el) {
        List<Item> items = new ArrayList<Item>();

        for (Element e : el) {
            items.add(toItem(e));
        }

        return items;
    }

    private Item toItem(Element el) {
        return new ItemImpl(el, this);
    }

    private List<Item> selectItems(Element e, List<Item> items) {
        if (e.hasAttr("itemscope") && !e.hasAttr("itemprop")) {
            items.add(new ItemImpl(e, this));
            return items;
        }

        for (Element c : e.children()) {
            selectItems(c, items);
        }

        return items;
    }

    private class ItemImpl implements Item {

        private Element el;
        private MicrodataDocument document;
        private ItemImpl followed;

        public ItemImpl(Element element, MicrodataDocument document) {
            if (element == null)
                throw new NullPointerException("element is mandatory");
            this.el = element;
            this.document = document;
        }

        @Override
        public Items prop(String name) throws ClientException {
            return new ItemsImpl(selectProps(getProxy().el, name, new ArrayList<Item>()));
        }

        @Override
        public Set<String> props() throws ClientException {
            return selectAllPropNames(getProxy().el, new HashSet<String>());
        }

        @Override
        public Items link(String rel) throws ClientException {
            String selector = "link[rel=" + rel + "], a[rel=" + rel + "], link" + toClass(rel) + ", a"
                    + toClass(rel);
            return new ItemsImpl(toItems(getProxy().el.select(selector)));
        }

        @Override
        public Items link() throws ClientException {
            String selector = "link, a";
            return new ItemsImpl(toItems(getProxy().el.select(selector)));
        }

        @Override
        public Items form(String rel) throws ClientException {
            String selector = "form[data-rel=" + rel + "], form" + toClass(rel);
            return new ItemsImpl(toItems(getProxy().el.select(selector)));
        }

        @Override
        public Items form() throws ClientException {
            String selector = "form";
            return new ItemsImpl(toItems(getProxy().el.select(selector)));
        }

        /* Private methods */

        private List<Item> selectProps(Element e, String name, List<Item> items) {
            for (Element c : e.children()) {
                if (c.hasAttr("itemprop")) {
                    if (c.attr("itemprop").equals(name)) {
                        items.add(new ItemImpl(c, document));
                    }

                    if (c.hasAttr("itemscope")) {
                        continue;
                    }
                }

                selectProps(c, name, items);
            }

            return items;
        }

        private Set<String> selectAllPropNames(Element e, Set<String> items) {
            for (Element c : e.children()) {
                if (c.hasAttr("itemprop")) {
                    items.add(c.attr("itemprop"));
                }

                if (c.hasAttr("itemscope")) {
                    continue;
                }

                selectAllPropNames(c, items);
            }
            return items;
        }

        private ItemImpl getProxy() throws ClientException {
            if (el.tagName().equalsIgnoreCase("a") && el.hasAttr("href")) {
                if (followed == null) {
                    followed = follow(el, document);
                }
                return followed;
            }

            return this;
        }

        private ItemImpl follow(Element el, MicrodataDocument doc) throws ClientException {
            if (el.hasAttr("itemscope")) {
                return new ItemImpl(el, doc);
            }

            if (el.tagName().equalsIgnoreCase("a") && el.hasAttr("href")) {
                String href = el.attr("href");

                if (href.startsWith("#")) {
                    Element first = el.ownerDocument().select(href).first();
                    return first == null ? null : follow(first, doc);
                }

                String absHref = el.attr("abs:href");
                MicrodataDocument d = (MicrodataDocument) doc.client.get(absHref);

                try {
                    URI uri = new URI(absHref);

                    String fragment = uri.getRawFragment();
                    if (fragment != null) {
                        Element e = d.jsoupDocument.getElementById(fragment);
                        return e == null ? null : follow(e, d);
                    }
                } catch (URISyntaxException ex) {
                    throw new ClientException("Error parsing URI: " + absHref, ex);
                }

                ItemsImpl items = (ItemsImpl) d.items();

                if (items.length() == 1) {
                    return (ItemImpl) items.at(0);
                }

                throw new ClientException("Unable determine item: " + absHref);
            }

            return new ItemImpl(el, doc);
        }

        @Override
        public String text() throws ClientException {
            // resolve element
            Element el = getProxy().el;

            // if it's a meta, get the value of the content attr
            if (el.tagName().equalsIgnoreCase("meta") && el.hasAttr("content")) {
                return el.attr("content");
            }

            // else, get the text value using jsoup
            return getProxy().el.text();
        }

        @Override
        public boolean bool() throws ClientException {
            return Boolean.parseBoolean(text());
        }

        @Override
        public int number() throws ClientException {
            return Integer.parseInt(text());
        }

        @Override
        public String href() {
            return el.attr("href");
        }

        @Override
        public String src() {
            return el.attr("src");
        }

        @Override
        public Document follow() throws ClientException {
            if ((el.tagName().equalsIgnoreCase("a") || el.tagName().equalsIgnoreCase("link"))
                    && el.hasAttr("href")) {
                String href = el.attr("href");

                if (href.startsWith("#")) {
                    return document;
                }

                return document.client.enter(el.attr("abs:href"));
            }

            throw new ClientException("Unable to follow: " + el.toString());
        }

        @Override
        public Document submit(Iterable<NameValuePair> values) throws ClientException {
            if (el.tagName().equalsIgnoreCase("form")) {
                String action = el.attr("abs:action");
                if (action.length() == 0) {
                    action = el.baseUri();
                }

                String method = el.attr("method");

                if (method.length() == 0 || method.equalsIgnoreCase("get")) {
                    FormValues query = new FormValues(el, values);
                    String url = action + (action.contains("?") ? "?" : "&") + query.toString();
                    return document.client.enter(url);
                }

                if (method.equalsIgnoreCase("post")) {
                    String enctype = el.attr("enctype");

                    FormValues v = new FormValues(el, values);
                    if (enctype.length() == 0 || enctype.equalsIgnoreCase("application/x-www-form-urlencoded")) {
                        return document.client.post(action, v.toUrlEncodedEntity());
                    } else if (enctype.equalsIgnoreCase("multipart/form-data")) {
                        return document.client.post(action, v.toMultipartEntity());
                    }

                    throw new ClientException("Unsupported form enctype: " + enctype);
                }

                throw new ClientException("Unsupported form method: " + method);
            }

            throw new ClientException("The item is not a form");
        }

    }

    /**
     * Items impl for microdata
     */
    private class ItemsImpl implements Items {
        private List<Item> items;

        public ItemsImpl(List<Item> items) {
            this.items = items;
        }

        @Override
        public Iterator<Item> iterator() {
            return items.iterator();
        }

        @Override
        public Item at(int index) {
            return items.get(index);
        }

        @Override
        public int length() {
            return items.size();
        }

        @Override
        public Items prop(String name) throws ClientException {
            return items.get(0).prop(name);
        }

        @Override
        public Set<String> props() throws ClientException {
            return items.get(0).props();
        }

        @Override
        public Items link(String rel) throws ClientException {
            return items.get(0).link(rel);
        }

        @Override
        public Items link() throws ClientException {
            return items.get(0).link();
        }

        @Override
        public Items form(String rel) throws ClientException {
            return items.get(0).form(rel);
        }

        @Override
        public Items form() throws ClientException {
            return items.get(0).form();
        }

        @Override
        public String text() throws ClientException {
            return items.get(0).text();
        }

        @Override
        public boolean bool() throws ClientException {
            return items.get(0).bool();
        }

        @Override
        public int number() throws ClientException {
            return items.get(0).number();
        }

        @Override
        public String href() {
            return items.get(0).href();
        }

        @Override
        public String src() {
            return items.get(0).src();
        }

        @Override
        public Document follow() throws ClientException {
            return items.get(0).follow();
        }

        @Override
        public Document submit(Iterable<NameValuePair> values) throws ClientException {
            return items.get(0).submit(values);
        }
    }

}