org.apache.olingo.client.api.domain.ClientEntitySetIterator.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.olingo.client.api.domain.ClientEntitySetIterator.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 org.apache.olingo.client.api.domain;

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.olingo.client.api.ODataClient;
import org.apache.olingo.client.api.data.ResWrap;
import org.apache.olingo.client.api.serialization.ODataDeserializerException;
import org.apache.olingo.commons.api.Constants;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.format.ContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * OData entity set iterator class.
 * <br/>
 * <b>Please don't forget to call the <tt>close()>/</tt> method when not needed any more.</b>
 *
 * @param <E> concrete ODataEntity implementation
 * @param <T> concrete ODataEntitySet implementation
 */
public class ClientEntitySetIterator<T extends ClientEntitySet, E extends ClientEntity> implements Iterator<E> {

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

    protected final ODataClient odataClient;

    protected ResWrap<Entity> cached;

    private final InputStream stream;

    private final ContentType contentType;

    private T entitySet;

    private final ByteArrayOutputStream osEntitySet;

    private final String namespaces;

    private boolean available = true;

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

        this.odataClient = odataClient;
        this.stream = stream;
        this.contentType = contentType;
        this.osEntitySet = new ByteArrayOutputStream();

        if (contentType.isCompatible(ContentType.APPLICATION_ATOM_SVC)
                || contentType.isCompatible(ContentType.APPLICATION_ATOM_XML)) {
            namespaces = getAllElementAttributes(stream, "feed", osEntitySet);
        } else {
            namespaces = null;
            try {
                if (consume(stream, "\"value\":", osEntitySet, true) >= 0) {
                    int c = 0;
                    while (c != '[' && (c = stream.read()) >= 0) {
                        osEntitySet.write(c);
                    }
                }
            } catch (IOException e) {
                LOG.error("Error parsing entity set", e);
                throw new IllegalStateException(e);
            }
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean hasNext() {
        if (available && cached == null) {
            if (contentType.isCompatible(ContentType.APPLICATION_ATOM_SVC)
                    || contentType.isCompatible(ContentType.APPLICATION_ATOM_XML)) {
                cached = nextAtomEntityFromEntitySet(stream, osEntitySet, namespaces);
            } else {
                cached = nextJSONEntityFromEntitySet(stream, osEntitySet);
            }

            if (cached == null) {
                available = false;
                try {
                    entitySet = (T) odataClient.getReader()
                            .readEntitySet(new ByteArrayInputStream(osEntitySet.toByteArray()), contentType);
                } catch (final ODataDeserializerException e) {
                    available = false;
                }
                close();
            }
        }

        return available;
    }

    @Override
    public E next() {
        if (hasNext()) {
            @SuppressWarnings("unchecked")
            final E res = (E) 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(osEntitySet);
    }

    /**
     * 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();
    }

    private ResWrap<Entity> nextJSONEntityFromEntitySet(final InputStream input, final OutputStream osEntitySet) {
        final ByteArrayOutputStream entity = new ByteArrayOutputStream();

        ResWrap<Entity> jsonEntity = null;
        try {
            int c;

            boolean foundNewOne = false;

            do {
                c = input.read();
                if (c == '{') {
                    entity.write(c);
                    c = -1;
                    foundNewOne = true;
                }
                if (c == ']') {
                    osEntitySet.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--;
                    }
                    entity.write(c);
                }

                if (c >= 0) {
                    jsonEntity = odataClient.getDeserializer(ContentType.JSON)
                            .toEntity(new ByteArrayInputStream(entity.toByteArray()));
                }
            } else {
                while ((c = input.read()) >= 0) {
                    osEntitySet.write(c);
                }
            }
        } catch (Exception e) {
            LOG.error("Error retrieving entities from EntitySet", e);
        }

        return jsonEntity;
    }

    private ResWrap<Entity> nextAtomEntityFromEntitySet(final InputStream input, final OutputStream osEntitySet,
            final String namespaces) {

        final ByteArrayOutputStream entity = new ByteArrayOutputStream();

        ResWrap<Entity> atomEntity = null;

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

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

        return atomEntity;
    }

    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 ? "" : new String(attrsDeclaration, Constants.UTF8).trim();
        } catch (Exception e) {
            LOG.error("Error retrieving entities from EntitySet", e);
            res = "";
        }

        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;
    }
}