/*
* Data Hub Service (DHuS) - For Space data distribution.
* Copyright (C) 2013,2014,2015 GAEL Systems
*
* This file is part of DHuS software sources.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.gael.dhus.olingo.v1;
import fr.gael.dhus.olingo.v1.ExpectedException.InvalidKeyException;
import fr.gael.dhus.olingo.v1.entity.AbstractEntity;
import fr.gael.dhus.olingo.v1.entityset.AbstractEntitySet;
import java.util.Iterator;
import java.util.List;
import org.apache.olingo.odata2.api.edm.EdmEntitySet;
import org.apache.olingo.odata2.api.exception.ODataException;
import org.apache.olingo.odata2.api.uri.KeyPredicate;
import org.apache.olingo.odata2.api.uri.NavigationSegment;
/**
* This class is a utility class to navigate through the datastore. This class
* is used by OData Processors implementations. It uses the deta defined in
* uriInfo. All KeyPredicates are singles, because every Key is mono-valued in
* the Schema. Olingo's uriInfo data structure depicts the uri convention from
* the OData v2 specification. Uri Convention example:
*
* <pre>
* odata/v1/Category(1)/Products
* \______/\___________________/
* ROOT RESOURCE PATH
*
* Resource Path:
* Category(1)/Category(34)/Product(5)/Price/$value
* \_________/\______________________/\___________/
* Collection Navigation Resource
* </pre>
*
* See the <a href=
* "http://www.odata.org/documentation/odata-version-2-0/uri-conventions
* #ResourcePath">Uri conventions</a>.
*/
public final class Navigator
{
/** Do not allow creation of instances. */
private Navigator() {}
/**
* Reads the navigation segments and recursively digs deeper in the data. Can
* return a Map<Key, Product|Collection|Node|Attribute> for EntitySets, a
* Product, Collection, Node, Attribute for Entities, a Int, Long, String,
* Date, Float, Double, ... for Properties.
*
* @param <E> return type.
*
* @param collection the first segment (as defined in the OData v2 spec).
* @param collec_kp the KeyPredicate for the collection param.
* @param nav_segments A list of NavigationSegment.
* @param return_type the type of returned object (may be null).
*
* @return a non-null instance of the returnType.
*
* @throws IllegalArgumentException if one or more arg is null.
* @throws ODataException if not able to return an instance.
*/
@SuppressWarnings("unchecked")
public static <E> E navigate(EdmEntitySet collection, KeyPredicate collec_kp,
List<NavigationSegment> nav_segments, Class<? extends E> return_type) throws ODataException
{
Object result;
AbstractEntitySet entity_set = Model.getEntitySet(collection.getName());
if (collec_kp != null) // Start is an Entity
{
AbstractEntity entity = entity_set.getEntity(collec_kp);
if (entity == null)
{
throw new InvalidKeyException(collec_kp.getLiteral(), entity_set.getName());
}
result = entity;
Iterator<NavigationSegment> it = nav_segments.iterator();
while (it.hasNext())
{
result = entity.navigate(it.next());
if (result instanceof AbstractEntity)
{
entity = AbstractEntity.class.cast(result);
}
else if (it.hasNext())
{
throw new ExpectedException("Unexpected nav segment " + it.next().toString());
}
}
}
else // Start is an EntitySet (no further navigation required)
{
result = entity_set.getEntities();
}
// Returns the result casted into a returnType object
if (result == null)
{
throw new ExpectedException("Navigation failed (result is null)");
}
try
{
if (return_type != null)
{
return return_type.cast(result);
}
return (E) result;
}
catch (ClassCastException e)
{
throw new ODataException(e);
}
}
}