com.msopentech.odatajclient.engine.data.ODataEntitySetIterator.java Source code

Java tutorial

Introduction

Here is the source code for com.msopentech.odatajclient.engine.data.ODataEntitySetIterator.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
 *
 *   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.msopentech.odatajclient.engine.data;

import com.msopentech.odatajclient.engine.client.ODataClient;
import com.msopentech.odatajclient.engine.data.impl.v3.AtomEntry;
import com.msopentech.odatajclient.engine.data.impl.v3.JSONEntry;
import com.msopentech.odatajclient.engine.format.ODataPubFormat;
import com.msopentech.odatajclient.engine.utils.ODataConstants;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * OData entity set iterator class.
 */
public class ODataEntitySetIterator implements Iterator<ODataEntity> {

    /**
     * Logger.
     */
    private static final Logger LOG = LoggerFactory.getLogger(ODataEntitySetIterator.class);

    private static final long serialVersionUID = 9039605899821494025L;

    private final ODataClient odataClient;

    private final InputStream stream;

    private final ODataPubFormat format;

    private Entry cached;

    private ODataEntitySet entitySet;

    private final ByteArrayOutputStream osFeed;

    private final String namespaces;

    private boolean available = true;

    /**
     * Constructor.
     *
     * @param odataClient client instance getting this request
     * @param stream source stream.
     * @param format OData format.
     */
    public ODataEntitySetIterator(final ODataClient odataClient, final InputStream stream,
            final ODataPubFormat format) {

        this.odataClient = odataClient;
        this.stream = stream;
        this.format = format;
        this.osFeed = new ByteArrayOutputStream();

        if (format == ODataPubFormat.ATOM) {
            namespaces = getAllElementAttributes(stream, "feed", osFeed);
        } else {
            namespaces = null;
            try {
                if (consume(stream, "\"value\":", osFeed, true) >= 0) {
                    int c = 0;
                    while (c != '[' && (c = stream.read()) >= 0) {
                        osFeed.write(c);
                    }
                }
            } catch (IOException e) {
                LOG.error("Error parsing feed", e);
                throw new IllegalStateException(e);
            }
        }
    }

    /**
     * {@inheritDoc }
     */
    @Override
    public boolean hasNext() {
        if (available && cached == null) {
            if (format == ODataPubFormat.ATOM) {
                cached = nextAtomEntryFromFeed(stream, osFeed, namespaces);
            } else {
                cached = nextJsonEntryFromFeed(stream, osFeed);
            }

            if (cached == null) {
                available = false;
                entitySet = odataClient.getReader().readEntitySet(new ByteArrayInputStream(osFeed.toByteArray()),
                        format);
                close();
            }
        }

        return available;
    }

    /**
     * {@inheritDoc }
     */
    @Override
    public ODataEntity next() {
        if (hasNext()) {
            final ODataEntity res = odataClient.getBinder().getODataEntity(cached);
            cached = null;
            return res;
        }

        throw new NoSuchElementException("No entity found");
    }

    /**
     * Unsupported operation.
     */
    @Override
    public void remove() {
        throw new UnsupportedOperationException("Operation not supported");
    }

    /**
     * Closes the current iterator.
     */
    public void close() {
        IOUtils.closeQuietly(stream);
        IOUtils.closeQuietly(osFeed);
    }

    /**
     * Gets the next link if exists.
     *
     * @return next link if exists; null otherwise.
     */
    public URI getNext() {
        if (entitySet == null) {
            throw new IllegalStateException(
                    "Iteration must be completed in order to retrieve the link for next page");
        }
        return entitySet.getNext();
    }

    /**
     * Finalize object closing all managed resources.
     *
     * @throws Throwable
     */
    @Override
    protected void finalize() throws Throwable {
        close();
        super.finalize();
    }

    private JSONEntry nextJsonEntryFromFeed(final InputStream input, final OutputStream osFeed) {
        final ByteArrayOutputStream entry = new ByteArrayOutputStream();

        JSONEntry entity = null;
        try {
            int c = 0;

            boolean foundNewOne = false;

            do {
                c = input.read();
                if (c == '{') {
                    entry.write(c);
                    c = -1;
                    foundNewOne = true;
                }
                if (c == ']') {
                    osFeed.write(c);
                    c = -1;
                }
            } while (c >= 0);

            if (foundNewOne) {
                int count = 1;
                c = 0;

                while (count > 0 && c >= 0) {
                    c = input.read();
                    if (c == '{') {
                        count++;
                    } else if (c == '}') {
                        count--;
                    }
                    entry.write(c);
                }

                if (c >= 0) {
                    entity = odataClient.getDeserializer().toEntry(new ByteArrayInputStream(entry.toByteArray()),
                            JSONEntry.class);
                }
            } else {
                while ((c = input.read()) >= 0) {
                    osFeed.write(c);
                }
            }
        } catch (Exception e) {
            LOG.error("Error retrieving entities from EntitySet", e);
        }

        return entity;
    }

    /**
     * De-Serializes a stream into an OData entity set.
     *
     * @param input stream to de-serialize.
     * @param format de-serialize as AtomFeed or JSONFeed
     * @return de-serialized entity set.
     */
    private AtomEntry nextAtomEntryFromFeed(final InputStream input, final OutputStream osFeed,
            final String namespaces) {
        final ByteArrayOutputStream entry = new ByteArrayOutputStream();

        AtomEntry entity = null;

        try {
            if (consume(input, "<entry>", osFeed, false) >= 0) {
                entry.write("<entry ".getBytes(ODataConstants.UTF8));
                entry.write(namespaces.getBytes(ODataConstants.UTF8));
                entry.write(">".getBytes(ODataConstants.UTF8));

                if (consume(input, "</entry>", entry, true) >= 0) {
                    entity = odataClient.getDeserializer().toEntry(new ByteArrayInputStream(entry.toByteArray()),
                            AtomEntry.class);
                }
            }
        } catch (Exception e) {
            LOG.error("Error retrieving entities from EntitySet", e);
        }

        return entity;
    }

    private String getAllElementAttributes(final InputStream input, final String name, final OutputStream os) {
        final ByteArrayOutputStream attrs = new ByteArrayOutputStream();

        String res;

        try {
            byte[] attrsDeclaration = null;

            final String key = "<" + name + " ";
            if (consume(input, key, os, true) >= 0 && consume(input, ">", attrs, false) >= 0) {
                attrsDeclaration = attrs.toByteArray();
                os.write(attrsDeclaration);
                os.write('>');
            }

            res = attrsDeclaration == null ? StringUtils.EMPTY
                    : new String(attrsDeclaration, ODataConstants.UTF8).trim();
        } catch (Exception e) {
            LOG.error("Error retrieving entities from EntitySet", e);
            res = StringUtils.EMPTY;
        }

        return res.endsWith("/") ? res.substring(0, res.length() - 1) : res;
    }

    private int consume(final InputStream input, final String end, final OutputStream os,
            final boolean includeEndKey) throws IOException {

        final char[] endKey = end.toCharArray();
        final char[] endLowerKey = end.toLowerCase().toCharArray();
        final char[] endUpperKey = end.toUpperCase().toCharArray();

        int pos = 0;
        int c = 0;
        while (pos < endKey.length && (c = input.read()) >= 0) {
            if (c == endLowerKey[pos] || c == endUpperKey[pos]) {
                pos++;
                if (includeEndKey && os != null) {
                    os.write(c);
                }
            } else if (pos > 0) {
                if (!includeEndKey && os != null) {
                    for (int i = 0; i < pos; i++) {
                        os.write(endKey[i]);
                    }
                }
                if (os != null) {
                    os.write(c);
                }
                pos = 0;
            } else {
                if (os != null) {
                    os.write(c);
                }
            }
        }

        return c;
    }
}