You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by il...@apache.org on 2014/03/24 10:42:35 UTC

[46/50] [abbrv] [OLINGO-205, OLINGO-200] provided atom v4 deserialization for entity type/set + entity set request

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/9aefb959/fit/src/main/java/org/apache/olingo/fit/utils/JSONUtilities.java
----------------------------------------------------------------------
diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/JSONUtilities.java b/fit/src/main/java/org/apache/olingo/fit/utils/JSONUtilities.java
deleted file mode 100644
index 79d2d8f..0000000
--- a/fit/src/main/java/org/apache/olingo/fit/utils/JSONUtilities.java
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * 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.fit.utils;
-
-import static org.apache.olingo.fit.utils.Constants.*;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.JsonNodeFactory;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.fasterxml.jackson.databind.node.TextNode;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.util.AbstractMap.SimpleEntry;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javax.ws.rs.NotFoundException;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
-
-public class JSONUtilities extends AbstractUtilities {
-
-  public JSONUtilities(final ODataVersion version) throws Exception {
-    super(version);
-  }
-
-  @Override
-  protected Accept getDefaultFormat() {
-    return Accept.JSON_FULLMETA;
-  }
-
-  @Override
-  protected InputStream addLinks(
-          final String entitySetName, final String entitykey, final InputStream is, final Set<String> links)
-          throws Exception {
-    final ObjectMapper mapper = new ObjectMapper();
-    final ObjectNode srcNode = (ObjectNode) mapper.readTree(is);
-    IOUtils.closeQuietly(is);
-
-    for (String link : links) {
-      srcNode.set(link + JSON_NAVIGATION_SUFFIX,
-              new TextNode(Commons.getLinksURI(version, entitySetName, entitykey, link)));
-    }
-
-    return IOUtils.toInputStream(srcNode.toString());
-  }
-
-  @Override
-  protected Set<String> retrieveAllLinkNames(InputStream is) throws Exception {
-    final ObjectMapper mapper = new ObjectMapper();
-    final ObjectNode srcNode = (ObjectNode) mapper.readTree(is);
-    IOUtils.closeQuietly(is);
-
-    final Set<String> links = new HashSet<String>();
-
-    final Iterator<String> fieldIter = srcNode.fieldNames();
-
-    while (fieldIter.hasNext()) {
-      final String field = fieldIter.next();
-
-      if (field.endsWith(JSON_NAVIGATION_BIND_SUFFIX)
-              || field.endsWith(JSON_NAVIGATION_SUFFIX)
-              || field.endsWith(JSON_MEDIA_SUFFIX)
-              || field.endsWith(JSON_EDITLINK_NAME)) {
-        if (field.indexOf('@') > 0) {
-          links.add(field.substring(0, field.indexOf('@')));
-        } else {
-          links.add(field);
-        }
-      }
-    }
-
-    return links;
-  }
-
-  /**
-   * {@inheritDoc }
-   */
-  @Override
-  protected NavigationLinks retrieveNavigationInfo(
-          final String entitySetName, final InputStream is)
-          throws Exception {
-    final ObjectMapper mapper = new ObjectMapper();
-    final ObjectNode srcNode = (ObjectNode) mapper.readTree(is);
-    IOUtils.closeQuietly(is);
-
-    final NavigationLinks links = new NavigationLinks();
-
-    final Iterator<Map.Entry<String, JsonNode>> fieldIter = srcNode.fields();
-
-    while (fieldIter.hasNext()) {
-      final Map.Entry<String, JsonNode> field = fieldIter.next();
-      if (field.getKey().endsWith(JSON_NAVIGATION_BIND_SUFFIX)) {
-        final String title = field.getKey().substring(0, field.getKey().indexOf('@'));
-        final List<String> hrefs = new ArrayList<String>();
-        if (field.getValue().isArray()) {
-          for (JsonNode href : ((ArrayNode) field.getValue())) {
-            final String uri = href.asText();
-            hrefs.add(uri.substring(uri.lastIndexOf('/') + 1));
-          }
-        } else {
-          final String uri = field.getValue().asText();
-          hrefs.add(uri.substring(uri.lastIndexOf('/') + 1));
-        }
-
-        links.addLinks(title, hrefs);
-      } else if (Commons.linkInfo.get(version).exists(entitySetName, field.getKey())) {
-        links.addInlines(field.getKey(), IOUtils.toInputStream(field.getValue().toString()));
-      }
-    }
-
-    return links;
-  }
-
-  /**
-   * {@inheritDoc }
-   */
-  @Override
-  protected InputStream normalizeLinks(
-          final String entitySetName, final String entityKey, final InputStream is, final NavigationLinks links)
-          throws Exception {
-    final ObjectMapper mapper = new ObjectMapper();
-    final ObjectNode srcNode = (ObjectNode) mapper.readTree(is);
-
-    if (links != null) {
-      for (String linkTitle : links.getLinkNames()) {
-        // normalize link
-        srcNode.remove(linkTitle + JSON_NAVIGATION_BIND_SUFFIX);
-        srcNode.set(
-                linkTitle + JSON_NAVIGATION_SUFFIX,
-                new TextNode(String.format("%s(%s)/%s", entitySetName, entityKey, linkTitle)));
-      }
-
-      for (String linkTitle : links.getInlineNames()) {
-        // normalize link if exist; declare a new one if missing
-        srcNode.remove(linkTitle + JSON_NAVIGATION_BIND_SUFFIX);
-        srcNode.set(
-                linkTitle + JSON_NAVIGATION_SUFFIX,
-                new TextNode(String.format("%s(%s)/%s", entitySetName, entityKey, linkTitle)));
-
-        // remove inline
-        srcNode.remove(linkTitle);
-
-        // remove from links
-        links.removeLink(linkTitle);
-      }
-    }
-
-    srcNode.set(
-            JSON_EDITLINK_NAME,
-            new TextNode(Constants.DEFAULT_SERVICE_URL + entitySetName + "(" + entityKey + ")"));
-
-    return IOUtils.toInputStream(srcNode.toString());
-  }
-
-  @Override
-  public InputStream getPropertyValue(final InputStream src, final List<String> path)
-          throws Exception {
-    final ObjectMapper mapper = new ObjectMapper();
-    final JsonNode srcNode = mapper.readTree(src);
-    JsonNode node = getProperty(srcNode, path);
-    return IOUtils.toInputStream(node.asText());
-  }
-
-  @Override
-  public InputStream getProperty(
-          final String entitySetName, final String entityId, final List<String> path, final String edmType)
-          throws Exception {
-
-    final InputStream src =
-            fsManager.readFile(Commons.getEntityBasePath(entitySetName, entityId) + ENTITY, Accept.JSON_FULLMETA);
-
-    final ObjectMapper mapper = new ObjectMapper();
-    final JsonNode srcNode = mapper.readTree(src);
-
-    final ObjectNode propertyNode = new ObjectNode(JsonNodeFactory.instance);
-
-    if (StringUtils.isNotBlank(edmType)) {
-      propertyNode.put(JSON_ODATAMETADATA_NAME, ODATA_METADATA_PREFIX + edmType);
-    }
-
-    JsonNode jsonNode = getProperty(srcNode, path);
-
-    if (jsonNode.isArray()) {
-      propertyNode.put("value", (ArrayNode) jsonNode);
-    } else if (jsonNode.isObject()) {
-      propertyNode.putAll((ObjectNode) jsonNode);
-    } else {
-      propertyNode.put("value", jsonNode.asText());
-    }
-
-    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    mapper.writeValue(bos, propertyNode);
-
-    final InputStream res = new ByteArrayInputStream(bos.toByteArray());
-    IOUtils.closeQuietly(bos);
-
-    return res;
-  }
-
-  private JsonNode getProperty(final JsonNode node, final List<String> path)
-          throws NotFoundException {
-
-    JsonNode propertyNode = node;
-    for (int i = 0; i < path.size(); i++) {
-      propertyNode = propertyNode.get(path.get(i));
-      if (propertyNode == null) {
-        throw new NotFoundException();
-      }
-    }
-
-    return propertyNode;
-  }
-
-  public InputStream addJsonInlinecount(
-          final InputStream src, final int count, final Accept accept)
-          throws Exception {
-    final ObjectMapper mapper = new ObjectMapper();
-    final JsonNode srcNode = mapper.readTree(src);
-
-    ((ObjectNode) srcNode).put(ODATA_COUNT_NAME, count);
-
-    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    mapper.writeValue(bos, srcNode);
-
-    final InputStream res = new ByteArrayInputStream(bos.toByteArray());
-    IOUtils.closeQuietly(bos);
-
-    return res;
-  }
-
-  public InputStream wrapJsonEntities(final InputStream entities) throws Exception {
-    final ObjectMapper mapper = new ObjectMapper();
-    final JsonNode node = mapper.readTree(entities);
-
-    final ObjectNode res;
-
-    final JsonNode value = node.get(JSON_VALUE_NAME);
-
-    if (value.isArray()) {
-      res = mapper.createObjectNode();
-      res.set("value", value);
-      final JsonNode next = node.get(JSON_NEXTLINK_NAME);
-      if (next != null) {
-        res.set(JSON_NEXTLINK_NAME, next);
-      }
-    } else {
-      res = (ObjectNode) value;
-    }
-
-    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    mapper.writeValue(bos, res);
-
-    final InputStream is = new ByteArrayInputStream(bos.toByteArray());
-    IOUtils.closeQuietly(bos);
-
-    return is;
-  }
-
-  @Override
-  public InputStream selectEntity(final InputStream src, final String[] propertyNames) throws Exception {
-    final ObjectMapper mapper = new ObjectMapper();
-    final ObjectNode srcNode = (ObjectNode) mapper.readTree(src);
-
-    final Set<String> retain = new HashSet<String>();
-    retain.add(JSON_ID_NAME);
-    retain.add(JSON_TYPE_NAME);
-    retain.add(JSON_EDITLINK_NAME);
-    retain.add(JSON_NEXTLINK_NAME);
-    retain.add(JSON_ODATAMETADATA_NAME);
-    retain.add(JSON_VALUE_NAME);
-
-    for (String name : propertyNames) {
-      retain.add(name);
-      retain.add(name + JSON_NAVIGATION_SUFFIX);
-      retain.add(name + JSON_MEDIA_SUFFIX);
-      retain.add(name + JSON_TYPE_SUFFIX);
-    }
-
-    srcNode.retain(retain);
-
-    return IOUtils.toInputStream(srcNode.toString());
-  }
-
-  @Override
-  public InputStream readEntities(
-          final List<String> links, final String linkName, final String next, final boolean forceFeed)
-          throws Exception {
-
-    if (links.isEmpty()) {
-      throw new NotFoundException();
-    }
-
-    final ObjectMapper mapper = new ObjectMapper();
-    final ObjectNode node = mapper.createObjectNode();
-
-    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-
-    if (forceFeed || links.size() > 1) {
-      bos.write("[".getBytes());
-    }
-
-    for (String link : links) {
-      try {
-        final Map.Entry<String, String> uri = Commons.parseEntityURI(link);
-        final Map.Entry<String, InputStream> entity =
-                readEntity(uri.getKey(), uri.getValue(), Accept.JSON_FULLMETA);
-
-        if (bos.size() > 1) {
-          bos.write(",".getBytes());
-        }
-
-        IOUtils.copy(entity.getValue(), bos);
-      } catch (Exception e) {
-        // log and ignore link
-        LOG.warn("Error parsing uri {}", link, e);
-      }
-    }
-
-    if (forceFeed || links.size() > 1) {
-      bos.write("]".getBytes());
-    }
-
-    node.set(JSON_VALUE_NAME, mapper.readTree(new ByteArrayInputStream(bos.toByteArray())));
-
-    if (StringUtils.isNotBlank(next)) {
-      node.set(JSON_NEXTLINK_NAME, new TextNode(next));
-    }
-
-    return IOUtils.toInputStream(node.toString());
-  }
-
-  @Override
-  protected InputStream replaceLink(
-          final InputStream toBeChanged, final String linkName, final InputStream replacement)
-          throws Exception {
-    final ObjectMapper mapper = new ObjectMapper();
-
-    final ObjectNode toBeChangedNode = (ObjectNode) mapper.readTree(toBeChanged);
-    final ObjectNode replacementNode = (ObjectNode) mapper.readTree(replacement);
-
-    if (toBeChangedNode.get(linkName + JSON_NAVIGATION_SUFFIX) == null) {
-      throw new NotFoundException();
-    }
-
-    toBeChangedNode.set(linkName, replacementNode.get(JSON_VALUE_NAME));
-
-    final JsonNode next = replacementNode.get(linkName + JSON_NEXTLINK_NAME);
-    if (next != null) {
-      toBeChangedNode.set(linkName + JSON_NEXTLINK_SUFFIX, next);
-    }
-
-    return IOUtils.toInputStream(toBeChangedNode.toString());
-  }
-
-  @Override
-  protected Map<String, InputStream> getChanges(final InputStream src) throws Exception {
-    final Map<String, InputStream> res = new HashMap<String, InputStream>();
-
-    final ObjectMapper mapper = new ObjectMapper();
-    final JsonNode srcObject = mapper.readTree(src);
-
-    final Iterator<Map.Entry<String, JsonNode>> fields = srcObject.fields();
-    while (fields.hasNext()) {
-      final Map.Entry<String, JsonNode> field = fields.next();
-      res.put(field.getKey(), IOUtils.toInputStream(field.getValue().toString()));
-    }
-
-    return res;
-  }
-
-  @Override
-  protected InputStream setChanges(
-          final InputStream toBeChanged, final Map<String, InputStream> properties) throws Exception {
-
-    final ObjectMapper mapper = new ObjectMapper();
-    final ObjectNode toBeChangedObject = (ObjectNode) mapper.readTree(toBeChanged);
-
-    for (Map.Entry<String, InputStream> property : properties.entrySet()) {
-      final JsonNode propertyNode = mapper.readTree(property.getValue());
-      toBeChangedObject.set(property.getKey(), propertyNode);
-    }
-
-    return IOUtils.toInputStream(toBeChangedObject.toString());
-  }
-
-  @Override
-  public Map.Entry<String, List<String>> extractLinkURIs(
-          final String entitySetName, final String entityId, final String linkName)
-          throws Exception {
-    final LinkInfo links = readLinks(entitySetName, entityId, linkName, Accept.JSON_FULLMETA);
-    return extractLinkURIs(links.getLinks());
-  }
-
-  @Override
-  public Map.Entry<String, List<String>> extractLinkURIs(final InputStream is)
-          throws Exception {
-    final ObjectMapper mapper = new ObjectMapper();
-    final ObjectNode srcNode = (ObjectNode) mapper.readTree(is);
-    IOUtils.closeQuietly(is);
-
-    final List<String> links = new ArrayList<String>();
-
-    JsonNode uris = srcNode.get("value");
-    if (uris == null) {
-      final JsonNode url = srcNode.get("url");
-      if (url != null) {
-        links.add(url.textValue());
-      }
-    } else {
-      final Iterator<JsonNode> iter = ((ArrayNode) uris).iterator();
-      while (iter.hasNext()) {
-        links.add(iter.next().get("url").textValue());
-      }
-    }
-
-    final JsonNode next = srcNode.get(JSON_NEXTLINK_NAME);
-
-    return new SimpleEntry<String, List<String>>(next == null ? null : next.asText(), links);
-  }
-
-  @Override
-  public InputStream addEditLink(
-          final InputStream content, final String title, final String href) throws Exception {
-    final ObjectMapper mapper = new ObjectMapper();
-    final ObjectNode srcNode = (ObjectNode) mapper.readTree(content);
-    IOUtils.closeQuietly(content);
-
-    srcNode.set(JSON_EDITLINK_NAME, new TextNode(href));
-    return IOUtils.toInputStream(srcNode.toString());
-  }
-
-  @Override
-  public InputStream replaceProperty(
-          final InputStream src, final InputStream replacement, final List<String> path, final boolean justValue)
-          throws Exception {
-    final ObjectMapper mapper = new ObjectMapper();
-    final ObjectNode srcNode = (ObjectNode) mapper.readTree(src);
-    IOUtils.closeQuietly(src);
-
-    final JsonNode replacementNode;
-    if (justValue) {
-      replacementNode = new TextNode(IOUtils.toString(replacement));
-    } else {
-      replacementNode = (ObjectNode) mapper.readTree(replacement);
-    }
-    IOUtils.closeQuietly(replacement);
-
-    JsonNode node = srcNode;
-    for (int i = 0; i < path.size() - 1; i++) {
-      node = node.get(path.get(i));
-      if (node == null) {
-        throw new NotFoundException();
-      }
-    }
-
-    ((ObjectNode) node).set(path.get(path.size() - 1), replacementNode);
-
-    return IOUtils.toInputStream(srcNode.toString());
-  }
-
-  @Override
-  public InputStream deleteProperty(final InputStream src, final List<String> path) throws Exception {
-    final ObjectMapper mapper = new ObjectMapper();
-    final ObjectNode srcNode = (ObjectNode) mapper.readTree(src);
-    IOUtils.closeQuietly(src);
-
-    JsonNode node = srcNode;
-    for (int i = 0; i < path.size() - 1; i++) {
-      node = node.get(path.get(i));
-      if (node == null) {
-        throw new NotFoundException();
-      }
-    }
-
-    ((ObjectNode) node).set(path.get(path.size() - 1), null);
-
-    return IOUtils.toInputStream(srcNode.toString());
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/9aefb959/fit/src/main/java/org/apache/olingo/fit/utils/XMLUtilities.java
----------------------------------------------------------------------
diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/XMLUtilities.java b/fit/src/main/java/org/apache/olingo/fit/utils/XMLUtilities.java
deleted file mode 100644
index 0009eea..0000000
--- a/fit/src/main/java/org/apache/olingo/fit/utils/XMLUtilities.java
+++ /dev/null
@@ -1,1388 +0,0 @@
-/*
- * 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.fit.utils;
-
-import static org.apache.olingo.fit.utils.Constants.*;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.StringWriter;
-import java.util.AbstractMap;
-import java.util.AbstractMap.SimpleEntry;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javax.ws.rs.NotFoundException;
-import javax.xml.namespace.QName;
-import javax.xml.stream.XMLEventFactory;
-import javax.xml.stream.XMLEventReader;
-import javax.xml.stream.XMLEventWriter;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLOutputFactory;
-import javax.xml.stream.XMLStreamConstants;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.events.Attribute;
-import javax.xml.stream.events.StartElement;
-import javax.xml.stream.events.XMLEvent;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileSystemException;
-
-public class XMLUtilities extends AbstractUtilities {
-
-  protected static XMLInputFactory ifactory = null;
-
-  protected static XMLOutputFactory ofactory = null;
-
-  public XMLUtilities(final ODataVersion version) throws Exception {
-    super(version);
-  }
-
-  public void retrieveLinkInfoFromMetadata() throws Exception {
-
-    final MetadataLinkInfo metadataLinkInfo = new MetadataLinkInfo();
-    Commons.linkInfo.put(version, metadataLinkInfo);
-
-    final InputStream metadata = fsManager.readFile(Constants.METADATA, Accept.XML);
-    final XMLEventReader reader = getEventReader(metadata);
-
-    int initialDepth = 0;
-    try {
-      while (true) {
-        Map.Entry<Integer, XmlElement> entityType =
-                extractElement(reader, null, Collections.<String>singletonList("EntityType"),
-                null, false, initialDepth, 4, 4);
-        initialDepth = entityType.getKey();
-
-        final String entitySetName =
-                entityType.getValue().getStart().getAttributeByName(new QName("Name")).getValue();
-
-        final XMLEventReader entityReader = getEventReader(entityType.getValue().toStream());
-        int size = 0;
-
-        try {
-          while (true) {
-            final XmlElement navProperty =
-                    extractElement(entityReader, null, Collections.<String>singletonList("NavigationProperty"),
-                    null, false, 0, -1, -1).getValue();
-
-            final String linkName = navProperty.getStart().getAttributeByName(new QName("Name")).getValue();
-            final Map.Entry<String, Boolean> target = getTargetInfo(navProperty.getStart(), linkName);
-
-            metadataLinkInfo.addLink(
-                    entitySetName,
-                    linkName,
-                    target.getKey(),
-                    target.getValue());
-
-            size++;
-          }
-        } catch (Exception e) {
-        } finally {
-          entityReader.close();
-        }
-
-        if (size == 0) {
-          metadataLinkInfo.addEntitySet(entitySetName);
-        }
-      }
-    } catch (Exception e) {
-    } finally {
-      reader.close();
-    }
-  }
-
-  private Map.Entry<String, Boolean> getTargetInfo(final StartElement element, final String linkName)
-          throws Exception {
-    final InputStream metadata = fsManager.readFile(Constants.METADATA, Accept.XML);
-    XMLEventReader reader = getEventReader(metadata);
-
-    final String associationName = element.getAttributeByName(new QName("Relationship")).getValue();
-
-    final Map.Entry<Integer, XmlElement> association = extractElement(
-            reader, null, Collections.<String>singletonList("Association"),
-            Collections.<Map.Entry<String, String>>singleton(new SimpleEntry<String, String>(
-            "Name", associationName.substring(associationName.lastIndexOf(".") + 1))), false,
-            0, 4, 4);
-
-    reader.close();
-    IOUtils.closeQuietly(metadata);
-
-    final InputStream associationContent = association.getValue().toStream();
-    reader = getEventReader(associationContent);
-
-    final Map.Entry<Integer, XmlElement> associationEnd = extractElement(
-            reader, null, Collections.<String>singletonList("End"),
-            Collections.<Map.Entry<String, String>>singleton(new SimpleEntry<String, String>("Role", linkName)),
-            false, 0, -1, -1);
-
-    reader.close();
-    IOUtils.closeQuietly(associationContent);
-
-    final String target = associationEnd.getValue().getStart().getAttributeByName(new QName("Type")).getValue();
-    final boolean feed = associationEnd.getValue().getStart().getAttributeByName(
-            new QName("Multiplicity")).getValue().equals("*");
-
-    return new SimpleEntry<String, Boolean>(target, feed);
-  }
-
-  @Override
-  protected Accept getDefaultFormat() {
-    return Accept.ATOM;
-  }
-
-  protected XMLEventReader getEventReader(final InputStream is) throws XMLStreamException {
-    if (ifactory == null) {
-      ifactory = XMLInputFactory.newInstance();
-    }
-    ifactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, false);
-    return ifactory.createXMLEventReader(is);
-  }
-
-  protected static XMLEventWriter getEventWriter(final OutputStream os) throws XMLStreamException {
-    if (ofactory == null) {
-      ofactory = XMLOutputFactory.newInstance();
-    }
-
-    return ofactory.createXMLEventWriter(os);
-  }
-
-  private void writeEvent(final XMLEvent event, final XMLEventWriter writer) {
-    if (writer != null) {
-      try {
-        writer.add(event);
-      } catch (XMLStreamException e) {
-        LOG.error("Error writing event {}", event, e);
-      }
-    }
-  }
-
-  private void skipElement(
-          final StartElement start,
-          final XMLEventReader reader,
-          final XMLEventWriter writer,
-          final boolean excludeStart)
-          throws Exception {
-
-    if (!excludeStart) {
-      writeEvent(start, writer);
-    }
-
-    int depth = 1;
-    boolean found = false;
-
-    while (reader.hasNext() && !found) {
-      final XMLEvent event = reader.nextEvent();
-
-      writeEvent(event, writer);
-
-      if (event.getEventType() == XMLStreamConstants.START_ELEMENT) {
-        depth++;
-      } else if (event.getEventType() == XMLStreamConstants.END_ELEMENT) {
-        depth--;
-        found = depth == 0 && start.getName().equals(event.asEndElement().getName());
-      }
-    }
-  }
-
-  /**
-   * {@inheritDoc }
-   */
-  @Override
-  protected InputStream addLinks(
-          final String entitySetName, final String entitykey, final InputStream is, final Set<String> links)
-          throws Exception {
-
-    // -----------------------------------------
-    // 0. Build reader and writer
-    // -----------------------------------------
-    final XMLEventReader reader = getEventReader(is);
-    final XMLEventFactory eventFactory = XMLEventFactory.newInstance();
-
-    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    final XMLEventWriter writer = getEventWriter(bos);
-    // -----------------------------------------
-    final Map.Entry<Integer, XmlElement> entry =
-            extractElement(reader, writer, Collections.singletonList("entry"), 0, 1, 1);
-
-    writer.add(entry.getValue().getStart());
-
-    // add for links
-    for (String link : links) {
-      final Set<Attribute> attributes = new HashSet<Attribute>();
-      attributes.add(eventFactory.createAttribute(new QName("title"), link));
-      attributes.add(eventFactory.createAttribute(new QName("href"),
-              Commons.getLinksURI(version, entitySetName, entitykey, link)));
-      attributes.add(eventFactory.createAttribute(new QName("rel"), Constants.ATOM_LINK_REL + link));
-      attributes.add(eventFactory.createAttribute(new QName("type"),
-              Commons.linkInfo.get(version).isFeed(entitySetName, link) ? Constants.ATOM_LINK_FEED
-              : Constants.ATOM_LINK_ENTRY));
-
-      writer.add(eventFactory.createStartElement(new QName(LINK), attributes.iterator(), null));
-      writer.add(eventFactory.createEndElement(new QName(LINK), null));
-    }
-
-    writer.add(entry.getValue().getContentReader());
-    writer.add(entry.getValue().getEnd());
-    writer.add(reader);
-    IOUtils.closeQuietly(is);
-
-    writer.flush();
-    writer.close();
-    reader.close();
-
-    return new ByteArrayInputStream(bos.toByteArray());
-  }
-
-  /**
-   * {@inheritDoc }
-   */
-  @Override
-  protected Set<String> retrieveAllLinkNames(final InputStream is) throws Exception {
-    final Set<String> links = new HashSet<String>();
-
-    final XMLEventReader reader = getEventReader(is);
-
-    try {
-
-      int startDepth = 0;
-
-      while (true) {
-        final Map.Entry<Integer, XmlElement> linkInfo =
-                extractElement(reader, null, Collections.<String>singletonList(LINK), startDepth, 2, 2);
-
-        startDepth = linkInfo.getKey();
-
-        links.add(linkInfo.getValue().getStart().getAttributeByName(new QName("title")).getValue());
-      }
-    } catch (Exception ignore) {
-      // ignore
-    } finally {
-      reader.close();
-      IOUtils.closeQuietly(is);
-    }
-
-    return links;
-  }
-
-  /**
-   * {@inheritDoc }
-   */
-  @Override
-  protected NavigationLinks retrieveNavigationInfo(
-          final String entitySetName, final InputStream is)
-          throws Exception {
-
-    final NavigationLinks links = new NavigationLinks();
-
-    final XMLEventReader reader = getEventReader(is);
-
-    try {
-      final List<Map.Entry<String, String>> filter = new ArrayList<Map.Entry<String, String>>();
-      filter.add(new AbstractMap.SimpleEntry<String, String>("type", "application/atom+xml;type=entry"));
-      filter.add(new AbstractMap.SimpleEntry<String, String>("type", "application/atom+xml;type=feed"));
-
-      int startDepth = 0;
-
-      while (true) {
-        // a. search for link with type attribute equals to "application/atom+xml;type=entry/feed"
-        final Map.Entry<Integer, XmlElement> linkInfo = extractElement(
-                reader, null, Collections.<String>singletonList(LINK), filter, true, startDepth, 2, 2);
-        final XmlElement link = linkInfo.getValue();
-        startDepth = linkInfo.getKey();
-
-        final String title = link.getStart().getAttributeByName(new QName("title")).getValue();
-
-        final Attribute hrefAttr = link.getStart().getAttributeByName(new QName("href"));
-        final String href = hrefAttr == null ? null : hrefAttr.getValue();
-
-        try {
-          final XmlElement inlineElement =
-                  extractElement(link.getContentReader(), null, Collections.<String>singletonList(INLINE), 0, -1, -1).
-                  getValue();
-          final XMLEventReader inlineReader = inlineElement.getContentReader();
-
-          try {
-            while (true) {
-              final XmlElement entry =
-                      extractElement(inlineReader, null, Collections.<String>singletonList("entry"), 0, -1, -1).
-                      getValue();
-              links.addInlines(title, entry.toStream());
-            }
-          } catch (Exception e) {
-            // Reached the end of document
-          }
-
-          inlineReader.close();
-        } catch (Exception ignore) {
-          // inline element not found (inlines are not mondatory).
-          if (StringUtils.isNotBlank(href) && entityUriPattern.matcher(href).matches()) {
-            links.addLinks(title, href.substring(href.lastIndexOf('/') + 1));
-          }
-        }
-      }
-    } catch (Exception ignore) {
-      // ignore
-    } finally {
-      reader.close();
-    }
-
-    return links;
-  }
-
-  /**
-   * {@inheritDoc }
-   */
-  @Override
-  protected InputStream normalizeLinks(
-          final String entitySetName, final String entityKey, final InputStream is, final NavigationLinks links)
-          throws Exception {
-
-    // -----------------------------------------
-    // 0. Build reader and writer
-    // -----------------------------------------
-    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    IOUtils.copy(is, bos);
-    is.close();
-
-    final ByteArrayOutputStream tmpBos = new ByteArrayOutputStream();
-    final XMLEventWriter writer = getEventWriter(tmpBos);
-
-    final XMLEventReader reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
-    // -----------------------------------------
-
-    // -----------------------------------------
-    // 1. Normalize links
-    // -----------------------------------------
-    final Set<String> added = new HashSet<String>();
-
-    try {
-      final List<Map.Entry<String, String>> filter = new ArrayList<Map.Entry<String, String>>();
-      filter.add(new AbstractMap.SimpleEntry<String, String>("type", "application/atom+xml;type=entry"));
-      filter.add(new AbstractMap.SimpleEntry<String, String>("type", "application/atom+xml;type=feed"));
-
-      Map.Entry<Integer, XmlElement> linkInfo = null;
-
-      while (true) {
-        // a. search for link with type attribute equals to "application/atom+xml;type=entry/feed"
-        linkInfo = extractElement(
-                reader, writer, Collections.<String>singletonList(LINK), filter, true,
-                linkInfo == null ? 0 : linkInfo.getKey(), 2, 2);
-        final XmlElement link = linkInfo.getValue();
-
-        final String title = link.getStart().getAttributeByName(new QName("title")).getValue();
-
-        if (!added.contains(title)) {
-          added.add(title);
-
-          final String normalizedLink = String.format(
-                  "<link href=\"%s(%s)/%s\" rel=\"%s\" title=\"%s\" type=\"%s\"/>",
-                  entitySetName,
-                  entityKey,
-                  title,
-                  link.getStart().getAttributeByName(new QName("rel")).getValue(),
-                  title,
-                  link.getStart().getAttributeByName(new QName("type")).getValue());
-
-          addAtomElement(IOUtils.toInputStream(normalizedLink), writer);
-        }
-      }
-    } catch (Exception ignore) {
-      // ignore
-    } finally {
-      writer.close();
-      reader.close();
-    }
-    // -----------------------------------------
-
-    // -----------------------------------------
-    // 2. Add edit link if missing
-    // -----------------------------------------
-    final InputStream content = addEditLink(
-            new ByteArrayInputStream(tmpBos.toByteArray()),
-            entitySetName,
-            Constants.DEFAULT_SERVICE_URL + entitySetName + "(" + entityKey + ")");
-    // -----------------------------------------
-
-    // -----------------------------------------
-    // 3. Add content element if missing
-    // -----------------------------------------
-    return addAtomContent(
-            content,
-            entitySetName,
-            Constants.DEFAULT_SERVICE_URL + entitySetName + "(" + entityKey + ")");
-    // -----------------------------------------
-
-  }
-
-  public XmlElement getXmlElement(
-          final StartElement start,
-          final XMLEventReader reader)
-          throws Exception {
-
-    final XmlElement res = new XmlElement();
-    res.setStart(start);
-
-    StringWriter content = new StringWriter();
-
-    int depth = 1;
-
-    while (reader.hasNext() && depth > 0) {
-      final XMLEvent event = reader.nextEvent();
-
-      if (event.getEventType() == XMLStreamConstants.START_ELEMENT) {
-        depth++;
-      } else if (event.getEventType() == XMLStreamConstants.END_ELEMENT) {
-        depth--;
-      }
-
-      if (depth == 0) {
-        res.setEnd(event.asEndElement());
-      } else {
-        event.writeAsEncodedUnicode(content);
-      }
-    }
-
-    content.flush();
-    content.close();
-
-    res.setContent(new ByteArrayInputStream(content.toString().getBytes()));
-
-    return res;
-  }
-
-  private void addAtomElement(
-          final InputStream content,
-          final XMLEventWriter writer)
-          throws Exception {
-    final XMLEventReader reader = getEventReader(content);
-
-    final XMLEventFactory eventFactory = XMLEventFactory.newInstance();
-    XMLEvent newLine = eventFactory.createSpace("\n");
-
-    try {
-      writer.add(newLine);
-
-      while (reader.hasNext()) {
-        final XMLEvent event = reader.nextEvent();
-
-        if (event.getEventType() != XMLStreamConstants.START_DOCUMENT
-                && event.getEventType() != XMLStreamConstants.END_DOCUMENT
-                && event.getEventType() != XMLStreamConstants.COMMENT) {
-          writer.add(event);
-        }
-      }
-      writer.add(newLine);
-    } finally {
-      reader.close();
-      IOUtils.closeQuietly(content);
-    }
-  }
-
-  @Override
-  public InputStream addEditLink(
-          final InputStream content, final String title, final String href)
-          throws Exception {
-
-    final ByteArrayOutputStream copy = new ByteArrayOutputStream();
-    IOUtils.copy(content, copy);
-
-    IOUtils.closeQuietly(content);
-
-    XMLEventReader reader = getEventReader(new ByteArrayInputStream(copy.toByteArray()));
-
-    ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    XMLEventWriter writer = getEventWriter(bos);
-
-    final String editLinkElement = String.format("<link rel=\"edit\" title=\"%s\" href=\"%s\" />", title, href);
-
-    try {
-      // check edit link existence
-      extractElement(reader, writer, Collections.<String>singletonList(LINK),
-              Collections.<Map.Entry<String, String>>singletonList(
-              new AbstractMap.SimpleEntry<String, String>("rel", "edit")), false, 0, -1, -1);
-
-      addAtomElement(IOUtils.toInputStream(editLinkElement), writer);
-      writer.add(reader);
-
-    } catch (Exception e) {
-      reader.close();
-      reader = getEventReader(new ByteArrayInputStream(copy.toByteArray()));
-
-      bos = new ByteArrayOutputStream();
-      writer = getEventWriter(bos);
-
-      final XmlElement entryElement =
-              extractElement(reader, writer, Collections.<String>singletonList("entry"), 0, 1, 1).getValue();
-
-      writer.add(entryElement.getStart());
-
-      addAtomElement(IOUtils.toInputStream(editLinkElement), writer);
-
-      writer.add(entryElement.getContentReader());
-      writer.add(entryElement.getEnd());
-
-      writer.add(reader);
-
-      writer.flush();
-      writer.close();
-    } finally {
-      reader.close();
-    }
-
-    return new ByteArrayInputStream(bos.toByteArray());
-  }
-
-  public InputStream addAtomContent(
-          final InputStream content, final String title, final String href)
-          throws Exception {
-
-    final ByteArrayOutputStream copy = new ByteArrayOutputStream();
-    IOUtils.copy(content, copy);
-
-    IOUtils.closeQuietly(content);
-
-    XMLEventReader reader = getEventReader(new ByteArrayInputStream(copy.toByteArray()));
-
-    ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    XMLEventWriter writer = getEventWriter(bos);
-
-    try {
-      // check edit link existence
-      XmlElement contentElement =
-              extractElement(reader, writer, Collections.<String>singletonList("content"), 0, 2, 2).getValue();
-      writer.add(contentElement.getStart());
-      writer.add(contentElement.getContentReader());
-      writer.add(contentElement.getEnd());
-      writer.add(reader);
-    } catch (Exception e) {
-      reader.close();
-      reader = getEventReader(new ByteArrayInputStream(copy.toByteArray()));
-
-      bos = new ByteArrayOutputStream();
-      writer = getEventWriter(bos);
-
-      if (isMediaContent(title)) {
-        final XmlElement entryElement =
-                extractElement(reader, writer, Collections.<String>singletonList("entry"), 0, 1, 1).getValue();
-
-        writer.add(entryElement.getStart());
-        writer.add(entryElement.getContentReader());
-
-        addAtomElement(
-                IOUtils.toInputStream(String.format("<content type=\"*/*\" src=\"%s/$value\" />", href)),
-                writer);
-
-        writer.add(entryElement.getEnd());
-      } else {
-        try {
-          final XmlElement entryElement =
-                  extractElement(reader, writer, Collections.<String>singletonList(PROPERTIES), 0, 2, 3).getValue();
-
-          addAtomElement(
-                  IOUtils.toInputStream("<content type=\"application/xml\">"),
-                  writer);
-
-          writer.add(entryElement.getStart());
-          writer.add(entryElement.getContentReader());
-          writer.add(entryElement.getEnd());
-
-          addAtomElement(
-                  IOUtils.toInputStream("</content>"),
-                  writer);
-        } catch (Exception nf) {
-          reader.close();
-          reader = getEventReader(new ByteArrayInputStream(copy.toByteArray()));
-
-          bos = new ByteArrayOutputStream();
-          writer = getEventWriter(bos);
-
-          final XmlElement entryElement =
-                  extractElement(reader, writer, Collections.<String>singletonList("entry"), 0, 1, 1).getValue();
-          writer.add(entryElement.getStart());
-          writer.add(entryElement.getContentReader());
-
-          addAtomElement(
-                  IOUtils.toInputStream("<content type=\"application/xml\"/>"),
-                  writer);
-
-          writer.add(entryElement.getEnd());
-        }
-      }
-
-      writer.add(reader);
-
-      writer.flush();
-      writer.close();
-    } finally {
-      reader.close();
-    }
-
-    return new ByteArrayInputStream(bos.toByteArray());
-  }
-
-  public int countAllElements(final String entitySetName) throws Exception {
-    final String basePath = entitySetName + File.separatorChar;
-    int count = countFeedElements(fsManager.readFile(basePath + FEED, Accept.XML), "entry");
-
-    final String skipTokenDirPath = fsManager.getAbsolutePath(basePath + SKIP_TOKEN, null);
-
-
-    try {
-      final FileObject skipToken = fsManager.resolve(skipTokenDirPath);
-      final FileObject[] files = fsManager.findByExtension(skipToken, Accept.XML.getExtension().substring(1));
-
-      for (FileObject file : files) {
-        count += countFeedElements(fsManager.readFile(
-                basePath + SKIP_TOKEN + File.separatorChar + file.getName().getBaseName(), null), "entry");
-      }
-    } catch (FileSystemException fse) {
-      LOG.debug("Resource path '{}' not found", skipTokenDirPath);
-    }
-
-
-    return count;
-  }
-
-  private int countFeedElements(final InputStream is, final String elementName) throws XMLStreamException {
-    final XMLEventReader reader = getEventReader(is);
-
-    int count = 0;
-
-    while (reader.hasNext()) {
-      final XMLEvent event = reader.nextEvent();
-
-      if (event.getEventType() == XMLStreamConstants.START_ELEMENT
-              && elementName.equals(event.asStartElement().getName().getLocalPart())) {
-        count++;
-      }
-    }
-
-    reader.close();
-    return count;
-  }
-
-  public Map.Entry<Integer, XmlElement> extractElement(
-          final XMLEventReader reader, final XMLEventWriter writer, final List<String> path,
-          final int startPathPos, final int minPathPos, final int maxPathPos)
-          throws Exception {
-    return extractElement(reader, writer, path, null, false, startPathPos, minPathPos, maxPathPos);
-  }
-
-  public Map.Entry<Integer, XmlElement> extractElement(
-          final XMLEventReader reader, final XMLEventWriter writer, final List<String> path,
-          final Collection<Map.Entry<String, String>> filter,
-          final boolean filterInOr,
-          final int startPathPos, final int minPathPos, final int maxPathPos)
-          throws Exception {
-
-    StartElement start = null;
-    int searchFor = 0;
-    int depth = startPathPos;
-
-    // Current inspected element
-    String current = null;
-
-    // set defaults
-    final List<String> pathElementNames = path == null ? Collections.<String>emptyList() : path;
-    final Collection<Map.Entry<String, String>> filterAttrs =
-            filter == null ? Collections.<Map.Entry<String, String>>emptySet() : filter;
-
-    while (reader.hasNext() && start == null) {
-      final XMLEvent event = reader.nextEvent();
-
-      if (event.getEventType() == XMLStreamConstants.START_ELEMENT) {
-        depth++;
-
-        if (current != null || ((minPathPos < 0 || minPathPos <= depth) && (maxPathPos < 0 || depth <= maxPathPos))) {
-          if (pathElementNames.isEmpty()
-                  || pathElementNames.get(searchFor).trim().equals(event.asStartElement().getName().getLocalPart())) {
-
-            if (searchFor < pathElementNames.size() - 1) {
-              // path exploring not completed
-              writeEvent(event, writer);
-              current = pathElementNames.get(searchFor).trim();
-              searchFor++;
-            } else {
-
-              // path exploring completed ... evaluate filter about path element name attribute
-              boolean match = filterAttrs.isEmpty() || !filterInOr;
-
-              for (Map.Entry<String, String> filterAttr : filterAttrs) {
-                final Attribute attr = event.asStartElement().getAttributeByName(new QName(filterAttr.getKey().trim()));
-
-                if (attr == null || !filterAttr.getValue().trim().equals(attr.getValue())) {
-                  match = filterInOr ? match : false;
-                } else {
-                  match = filterInOr ? true : match;
-                }
-              }
-
-              if (match) {
-                // found searched element
-                start = event.asStartElement();
-              } else {
-                skipElement(event.asStartElement(), reader, writer, false);
-                depth--;
-              }
-            }
-          } else if (current == null) {
-            writeEvent(event, writer);
-          } else {
-            // skip element
-            skipElement(event.asStartElement(), reader, writer, false);
-            depth--;
-          }
-        } else {
-          writeEvent(event, writer);
-        }
-
-      } else if (event.getEventType() == XMLStreamConstants.END_ELEMENT) {
-        depth--;
-
-        writeEvent(event, writer);
-
-        if (event.asEndElement().getName().getLocalPart().equals(current)) {
-          // back step ....
-          searchFor--;
-          current = searchFor > 0 ? pathElementNames.get(searchFor - 1).trim() : null;
-        }
-      } else {
-        writeEvent(event, writer);
-      }
-    }
-
-    if (start == null) {
-      throw new NotFoundException();
-    }
-
-    return new SimpleEntry<Integer, XmlElement>(Integer.valueOf(depth - 1), getXmlElement(start, reader));
-  }
-
-  public InputStream addAtomInlinecount(
-          final InputStream feed, final int count, final Accept accept)
-          throws Exception {
-    final XMLEventReader reader = getEventReader(feed);
-
-    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    final XMLEventWriter writer = getEventWriter(bos);
-
-    try {
-
-      final XmlElement feedElement =
-              extractElement(reader, writer, Collections.<String>singletonList("feed"), 0, 1, 1).getValue();
-
-      writer.add(feedElement.getStart());
-      addAtomElement(IOUtils.toInputStream(String.format("<m:count>%d</m:count>", count)), writer);
-      writer.add(feedElement.getContentReader());
-      writer.add(feedElement.getEnd());
-
-      while (reader.hasNext()) {
-        writer.add(reader.nextEvent());
-      }
-
-    } finally {
-      writer.flush();
-      writer.close();
-      reader.close();
-      IOUtils.closeQuietly(feed);
-    }
-
-    return new ByteArrayInputStream(bos.toByteArray());
-  }
-
-  @Override
-  public InputStream getPropertyValue(final InputStream is, final List<String> path)
-          throws Exception {
-
-    final List<String> pathElements = new ArrayList<String>();
-
-    for (String element : path) {
-      pathElements.add(ATOM_PROPERTY_PREFIX + element);
-    }
-
-    final XMLEventReader reader = getEventReader(is);
-    final Map.Entry<Integer, XmlElement> property = extractElement(reader, null, pathElements, 0, 3, 4);
-
-    reader.close();
-    IOUtils.closeQuietly(is);
-
-    return property.getValue().getContent();
-  }
-
-  @Override
-  public InputStream selectEntity(final InputStream entity, final String[] propertyNames) throws Exception {
-    final XMLEventReader reader = getEventReader(entity);
-
-    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    final XMLEventWriter writer = getEventWriter(bos);
-
-    final List<String> found = new ArrayList<String>(Arrays.asList(propertyNames));
-
-    boolean inProperties = false;
-    boolean writeCurrent = true;
-    Boolean writeNext = null;
-    String currentName = null;
-
-    final List<String> fieldToBeSaved = new ArrayList<String>(Arrays.asList(propertyNames));
-
-    while (reader.hasNext()) {
-      final XMLEvent event = reader.nextEvent();
-      if (event.getEventType() == XMLStreamConstants.START_ELEMENT
-              && LINK.equals(event.asStartElement().getName().getLocalPart())
-              && !fieldToBeSaved.contains(
-              event.asStartElement().getAttributeByName(new QName("title")).getValue())
-              && !"edit".equals(event.asStartElement().getAttributeByName(new QName("rel")).getValue())) {
-        writeCurrent = false;
-      } else if (event.getEventType() == XMLStreamConstants.END_ELEMENT
-              && LINK.equals(event.asEndElement().getName().getLocalPart())) {
-        writeNext = true;
-      } else if (event.getEventType() == XMLStreamConstants.START_ELEMENT
-              && (PROPERTIES).equals(event.asStartElement().getName().getLocalPart())) {
-        writeCurrent = true;
-        writeNext = false;
-        inProperties = true;
-      } else if (event.getEventType() == XMLStreamConstants.END_ELEMENT
-              && (PROPERTIES).equals(event.asEndElement().getName().getLocalPart())) {
-        writeCurrent = true;
-      } else if (inProperties) {
-        if (event.getEventType() == XMLStreamConstants.START_ELEMENT) {
-          final String elementName = event.asStartElement().getName().getLocalPart();
-
-          for (String propertyName : propertyNames) {
-            if ((ATOM_PROPERTY_PREFIX + propertyName.trim()).equals(elementName)) {
-              writeCurrent = true;
-              found.remove(propertyName);
-              currentName = propertyName;
-            }
-          }
-
-        } else if (event.getEventType() == XMLStreamConstants.END_ELEMENT
-                && StringUtils.isNotBlank(currentName)
-                && (ATOM_PROPERTY_PREFIX + currentName.trim()).equals(
-                event.asEndElement().getName().getLocalPart())) {
-          writeNext = false;
-          currentName = null;
-        }
-
-      }
-
-      if (writeCurrent) {
-        writer.add(event);
-      }
-
-      if (writeNext != null) {
-        writeCurrent = writeNext;
-        writeNext = null;
-      }
-    }
-
-    writer.flush();
-    writer.close();
-    reader.close();
-    IOUtils.closeQuietly(entity);
-
-    // Do not raise any exception in order to support FC properties as well
-    // if (!found.isEmpty()) {
-    //     throw new Exception(String.format("Could not find a properties '%s'", found));
-    // }
-
-    return new ByteArrayInputStream(bos.toByteArray());
-  }
-
-  @Override
-  public InputStream readEntities(
-          final List<String> links, final String linkName, final String next, final boolean forceFeed)
-          throws Exception {
-
-    if (links.isEmpty()) {
-      throw new NotFoundException();
-    }
-
-    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-
-    if (forceFeed || links.size() > 1) {
-      // build a feed
-      bos.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>".getBytes());
-
-      bos.write(("<feed xml:base=\"" + DEFAULT_SERVICE_URL + "\" "
-              + "xmlns=\"http://www.w3.org/2005/Atom\" "
-              + "xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" "
-              + "xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\">")
-              .getBytes());
-
-      bos.write(("<id>" + DEFAULT_SERVICE_URL + "entityset(entityid)/" + linkName + "</id>").getBytes());
-
-      bos.write(("<title type=\"text\">" + linkName + "</title>").getBytes());
-      bos.write("<updated>2014-03-03T13:40:49Z</updated>".getBytes());
-      bos.write(("<link rel=\"self\" title=\"" + linkName + "\" href=\"" + linkName + "\" />").getBytes());
-    }
-
-    for (String link : links) {
-      try {
-        final Map.Entry<String, String> uri = Commons.parseEntityURI(link);
-
-        final XmlElement entry =
-                extractElement(
-                getEventReader(readEntity(uri.getKey(), uri.getValue(), Accept.ATOM).getValue()),
-                null,
-                Collections.<String>singletonList("entry"),
-                0, 1, 1).getValue();
-
-        IOUtils.copy(entry.toStream(), bos);
-      } catch (Exception e) {
-        // log and ignore link
-        LOG.warn("Error parsing uri {}", link, e);
-      }
-    }
-
-    if (forceFeed || links.size() > 1) {
-
-      if (StringUtils.isNotBlank(next)) {
-        bos.write(String.format("<link rel=\"next\" href=\"%s\" />", next).getBytes());
-      }
-
-      bos.write("</feed>".getBytes());
-    }
-
-    return new ByteArrayInputStream(bos.toByteArray());
-  }
-
-  @Override
-  public Map<String, InputStream> getChanges(final InputStream src) throws Exception {
-    final Map<String, InputStream> res = new HashMap<String, InputStream>();
-
-    ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    IOUtils.copy(src, bos);
-    IOUtils.closeQuietly(src);
-
-    // retrieve properties ...
-    XMLEventReader reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
-
-    final Map.Entry<Integer, XmlElement> propertyElement =
-            extractElement(reader, null, Collections.<String>singletonList(PROPERTIES), 0, 2, 3);
-    reader.close();
-
-    reader = propertyElement.getValue().getContentReader();
-
-    try {
-      while (true) {
-        final XmlElement property = extractElement(reader, null, null, 0, -1, -1).getValue();
-        res.put(property.getStart().getName().getLocalPart(), property.toStream());
-      }
-    } catch (Exception ignore) {
-      // end
-    }
-
-    reader.close();
-
-    // retrieve links ...
-    reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
-
-    try {
-      int pos = 0;
-      while (true) {
-        final Map.Entry<Integer, XmlElement> linkElement =
-                extractElement(reader, null, Collections.<String>singletonList(LINK), pos, 2, 2);
-
-        res.put("[LINK]" + linkElement.getValue().getStart().getAttributeByName(new QName("title")).getValue(),
-                linkElement.getValue().toStream());
-
-        pos = linkElement.getKey();
-      }
-    } catch (Exception ignore) {
-      // end
-    }
-
-    return res;
-  }
-
-  @Override
-  public InputStream setChanges(
-          final InputStream toBeChanged,
-          final Map<String, InputStream> properties)
-          throws Exception {
-    XMLEventReader reader = getEventReader(toBeChanged);
-
-    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    XMLEventWriter writer = getEventWriter(bos);
-
-    // ---------------------------------
-    // add property changes
-    // ---------------------------------
-    Map.Entry<Integer, XmlElement> propertyElement =
-            extractElement(reader, writer, Collections.<String>singletonList(PROPERTIES), 0, 2, 3);
-
-    writer.flush();
-
-    ByteArrayOutputStream pbos = new ByteArrayOutputStream();
-    OutputStreamWriter pwriter = new OutputStreamWriter(pbos);
-
-    final XMLEventReader propertyReader = propertyElement.getValue().getContentReader();
-
-    try {
-      while (true) {
-        final XmlElement property = extractElement(propertyReader, null, null, 0, -1, -1).getValue();
-        final String name = property.getStart().getName().getLocalPart();
-
-        if (properties.containsKey(name)) {
-          // replace
-          final InputStream replacement = properties.get(name);
-          properties.remove(property.getStart().getName().getLocalPart());
-          pwriter.append(IOUtils.toString(replacement));
-          IOUtils.closeQuietly(replacement);
-        } else {
-          pwriter.append(IOUtils.toString(property.toStream()));
-        }
-      }
-    } catch (Exception ignore) {
-      // end
-    }
-
-    for (Map.Entry<String, InputStream> remains : properties.entrySet()) {
-      if (!remains.getKey().startsWith("[LINK]")) {
-        pwriter.append(IOUtils.toString(remains.getValue()));
-        IOUtils.closeQuietly(remains.getValue());
-      }
-    }
-
-    pwriter.flush();
-    pwriter.close();
-
-    writer.add(propertyElement.getValue().getStart());
-    writer.add(new XMLEventReaderWrapper(new ByteArrayInputStream(pbos.toByteArray())));
-    writer.add(propertyElement.getValue().getEnd());
-
-    IOUtils.closeQuietly(pbos);
-
-    writer.add(reader);
-    reader.close();
-    writer.flush();
-    writer.close();
-    // ---------------------------------
-
-    // ---------------------------------
-    // add navigationm changes
-    // ---------------------------------
-
-    // remove existent links
-    for (Map.Entry<String, InputStream> remains : properties.entrySet()) {
-
-      if (remains.getKey().startsWith("[LINK]")) {
-        reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
-
-        bos.reset();
-        writer = getEventWriter(bos);
-
-        try {
-          final String linkName = remains.getKey().substring(remains.getKey().indexOf("]") + 1);
-
-          extractElement(reader, writer, Collections.<String>singletonList(LINK),
-                  Collections.<Map.Entry<String, String>>singleton(new SimpleEntry<String, String>("title", linkName)),
-                  false, 0, 2, 2);
-
-          writer.add(reader);
-
-        } catch (Exception ignore) {
-          // ignore
-        }
-
-        writer.flush();
-        writer.close();
-      }
-    }
-
-    reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
-
-    bos.reset();
-    writer = getEventWriter(bos);
-
-    propertyElement = extractElement(reader, writer, Collections.<String>singletonList(CONTENT), 0, 2, 2);
-    writer.flush();
-
-    pbos.reset();
-    pwriter = new OutputStreamWriter(pbos);
-
-    for (Map.Entry<String, InputStream> remains : properties.entrySet()) {
-      if (remains.getKey().startsWith("[LINK]")) {
-        pwriter.append(IOUtils.toString(remains.getValue()));
-        IOUtils.closeQuietly(remains.getValue());
-      }
-    }
-
-    pwriter.flush();
-    pwriter.close();
-
-    writer.add(new XMLEventReaderWrapper(new ByteArrayInputStream(pbos.toByteArray())));
-    IOUtils.closeQuietly(pbos);
-
-    writer.add(propertyElement.getValue().getStart());
-    writer.add(propertyElement.getValue().getContentReader());
-    writer.add(propertyElement.getValue().getEnd());
-
-    writer.add(reader);
-    reader.close();
-    writer.flush();
-    writer.close();
-    // ---------------------------------
-
-    return new ByteArrayInputStream(bos.toByteArray());
-  }
-
-  @Override
-  protected InputStream replaceLink(
-          final InputStream toBeChanged, final String linkName, final InputStream replacement)
-          throws Exception {
-    final XMLEventReader reader = getEventReader(toBeChanged);
-
-    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    final XMLEventWriter writer = getEventWriter(bos);
-
-    final XMLEventFactory eventFactory = XMLEventFactory.newInstance();
-    XMLEvent newLine = eventFactory.createSpace("\n");
-
-    try {
-      final XmlElement linkElement =
-              extractElement(reader, writer, Collections.<String>singletonList(LINK),
-              Collections.<Map.Entry<String, String>>singletonList(new SimpleEntry<String, String>("title", linkName)),
-              false, 0, -1, -1).getValue();
-      writer.add(linkElement.getStart());
-
-      // ------------------------------------------
-      // write inline ...
-      // ------------------------------------------
-      writer.add(newLine);
-      writer.add(eventFactory.createStartElement("m", null, "inline"));
-
-      addAtomElement(replacement, writer);
-
-      writer.add(eventFactory.createEndElement("m", null, "inline"));
-      writer.add(newLine);
-      // ------------------------------------------
-
-      writer.add(linkElement.getEnd());
-
-      writer.add(reader);
-      writer.flush();
-      writer.close();
-    } finally {
-      reader.close();
-      IOUtils.closeQuietly(toBeChanged);
-    }
-
-    return new ByteArrayInputStream(bos.toByteArray());
-  }
-
-  public String getEdmTypeFromAtom(final String entitySetName, final String entityId, final List<String> path)
-          throws Exception {
-    InputStream src = fsManager.readFile(Commons.getEntityBasePath(entitySetName, entityId) + ENTITY, Accept.XML);
-
-    final List<String> atomPathElements = new ArrayList<String>();
-
-    for (String element : path) {
-      atomPathElements.add(ATOM_PROPERTY_PREFIX + element);
-    }
-
-    final Map.Entry<Integer, XmlElement> prop = extractElement(getEventReader(src), null, atomPathElements, 0, 3, 4);
-    IOUtils.closeQuietly(src);
-
-    final Attribute type = prop.getValue().getStart().getAttributeByName(new QName(TYPE));
-
-    final String edmType;
-
-    if (type == null) {
-      edmType = Constants.ATOM_DEF_TYPE;
-    } else {
-      edmType = type.getValue();
-    }
-
-    return edmType;
-  }
-
-  @Override
-  public Map.Entry<String, List<String>> extractLinkURIs(
-          final String entitySetName, final String entityId, final String linkName)
-          throws Exception {
-    final LinkInfo links = readLinks(entitySetName, entityId, linkName, Accept.XML);
-    return extractLinkURIs(links.getLinks());
-  }
-
-  @Override
-  public Map.Entry<String, List<String>> extractLinkURIs(final InputStream is)
-          throws Exception {
-    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    IOUtils.copy(is, bos);
-    IOUtils.closeQuietly(is);
-
-    XMLEventReader reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
-    final List<String> links = new ArrayList<String>();
-    try {
-      while (true) {
-        links.add(IOUtils.toString(extractElement(reader, null, Collections.<String>singletonList("uri"), 0, -1, -1).
-                getValue().getContent()));
-      }
-    } catch (Exception ignore) {
-      // End document reached ...
-    }
-    reader.close();
-
-    String next;
-
-    reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
-    try {
-      next = IOUtils.toString(extractElement(reader, null, Collections.<String>singletonList("next"), 0, -1, -1).
-              getValue().getContent());
-    } catch (Exception ignore) {
-      // next link is not mandatory
-      next = null;
-    }
-    reader.close();
-
-    return new AbstractMap.SimpleEntry<String, List<String>>(next, links);
-  }
-
-  @Override
-  public InputStream getProperty(
-          final String entitySetName, final String entityId, final List<String> path, final String edmType)
-          throws Exception {
-    final List<String> pathElements = new ArrayList<String>();
-
-    for (String element : path) {
-      pathElements.add(ATOM_PROPERTY_PREFIX + element);
-    }
-
-    final InputStream src =
-            fsManager.readFile(Commons.getEntityBasePath(entitySetName, entityId) + ENTITY, Accept.XML);
-
-    final XMLEventReader reader = getEventReader(src);
-    final XmlElement property = extractElement(reader, null, pathElements, 0, 3, 4).getValue();
-
-    reader.close();
-    IOUtils.closeQuietly(src);
-
-    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    final XMLEventWriter writer = getEventWriter(bos);
-
-    final XMLEventFactory eventFactory = XMLEventFactory.newInstance();
-    writer.add(eventFactory.createStartDocument("UTF-8", "1.0"));
-    writer.add(property.getStart());
-
-    if (property.getStart().getAttributeByName(new QName(ATOM_DATASERVICE_NS)) == null) {
-      writer.add(eventFactory.createNamespace(ATOM_PROPERTY_PREFIX.substring(0, 1), DATASERVICES_NS));
-    }
-    if (property.getStart().getAttributeByName(new QName(ATOM_METADATA_NS)) == null) {
-      writer.add(eventFactory.createNamespace(ATOM_METADATA_PREFIX.substring(0, 1), METADATA_NS));
-    }
-
-    writer.add(property.getContentReader());
-    writer.add(property.getEnd());
-
-    writer.flush();
-    writer.close();
-
-    return new ByteArrayInputStream(bos.toByteArray());
-  }
-
-  @Override
-  public InputStream replaceProperty(
-          final InputStream src, final InputStream replacement, final List<String> path, final boolean justValue)
-          throws Exception {
-
-    final List<String> pathElements = new ArrayList<String>();
-
-    for (String element : path) {
-      pathElements.add(ATOM_PROPERTY_PREFIX + element);
-    }
-
-    final XMLEventReader reader = getEventReader(src);
-
-    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    final XMLEventWriter writer = getEventWriter(bos);
-
-    final Map.Entry<Integer, XmlElement> element = extractElement(reader, writer, pathElements, 0, 3, 4);
-
-    if (justValue) {
-      writer.add(element.getValue().getStart());
-    }
-
-    final XMLEventReader changesReader = new XMLEventReaderWrapper(replacement);
-
-    writer.add(changesReader);
-    changesReader.close();
-    IOUtils.closeQuietly(replacement);
-
-    if (justValue) {
-      writer.add(element.getValue().getEnd());
-    }
-
-    writer.add(reader);
-
-    reader.close();
-    IOUtils.closeQuietly(src);
-
-    writer.flush();
-    writer.close();
-
-    return new ByteArrayInputStream(bos.toByteArray());
-  }
-
-  @Override
-  public InputStream deleteProperty(final InputStream src, final List<String> path) throws Exception {
-
-    final List<String> pathElements = new ArrayList<String>();
-
-    for (String element : path) {
-      pathElements.add(ATOM_PROPERTY_PREFIX + element);
-    }
-
-    final XMLEventReader reader = getEventReader(src);
-
-    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    final XMLEventWriter writer = getEventWriter(bos);
-
-    final Map.Entry<Integer, XmlElement> element = extractElement(reader, writer, pathElements, 0, 3, 4);
-
-    final XMLEventReader changesReader = new XMLEventReaderWrapper(
-            IOUtils.toInputStream(String.format("<%s m:null=\"true\" />", path.get(path.size() - 1))));
-
-    writer.add(changesReader);
-    changesReader.close();
-
-    writer.add(reader);
-
-    reader.close();
-    IOUtils.closeQuietly(src);
-
-    writer.flush();
-    writer.close();
-
-    return new ByteArrayInputStream(bos.toByteArray());
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/9aefb959/fit/src/main/java/org/apache/olingo/fit/utils/v3/JSONUtilities.java
----------------------------------------------------------------------
diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/v3/JSONUtilities.java b/fit/src/main/java/org/apache/olingo/fit/utils/v3/JSONUtilities.java
new file mode 100644
index 0000000..0f2a3f2
--- /dev/null
+++ b/fit/src/main/java/org/apache/olingo/fit/utils/v3/JSONUtilities.java
@@ -0,0 +1,28 @@
+/*
+ * 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.fit.utils.v3;
+
+import org.apache.olingo.fit.utils.ODataVersion;
+
+public class JSONUtilities extends org.apache.olingo.fit.utils.AbstractJSONUtilities {
+
+  public JSONUtilities() throws Exception {
+    super(ODataVersion.v3);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/9aefb959/fit/src/main/java/org/apache/olingo/fit/utils/v3/XMLUtilities.java
----------------------------------------------------------------------
diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/v3/XMLUtilities.java b/fit/src/main/java/org/apache/olingo/fit/utils/v3/XMLUtilities.java
new file mode 100644
index 0000000..c1a58bf
--- /dev/null
+++ b/fit/src/main/java/org/apache/olingo/fit/utils/v3/XMLUtilities.java
@@ -0,0 +1,191 @@
+/*
+ * 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.fit.utils.v3;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.StartElement;
+import org.apache.commons.io.IOUtils;
+import org.apache.olingo.fit.utils.Accept;
+import org.apache.olingo.fit.utils.Commons;
+import org.apache.olingo.fit.utils.Constants;
+import org.apache.olingo.fit.utils.MetadataLinkInfo;
+import org.apache.olingo.fit.utils.ODataVersion;
+import org.apache.olingo.fit.utils.XmlElement;
+
+public class XMLUtilities extends org.apache.olingo.fit.utils.AbstractXMLUtilities {
+
+  public XMLUtilities() throws Exception {
+    super(ODataVersion.v3);
+  }
+
+  @Override
+  public void retrieveLinkInfoFromMetadata() throws Exception {
+
+    final MetadataLinkInfo metadataLinkInfo = new MetadataLinkInfo();
+    Commons.getLinkInfo().put(version, metadataLinkInfo);
+
+    final InputStream metadata = fsManager.readFile(Constants.METADATA, Accept.XML);
+    final XMLEventReader reader = getEventReader(metadata);
+
+    try {
+      while (true) {
+        final Map.Entry<Integer, XmlElement> entitySetElement =
+                extractElement(reader, null, Collections.<String>singletonList("EntitySet"),
+                null, false, 0, -1, -1);
+
+        retrieveLinks(entitySetElement.getValue(), metadataLinkInfo);
+      }
+    } catch (Exception e) {
+    } finally {
+      reader.close();
+    }
+  }
+
+  private void retrieveLinks(final XmlElement entitySetElement, final MetadataLinkInfo metadataLinkInfo)
+          throws Exception {
+
+    final InputStream metadata = fsManager.readFile(Constants.METADATA, Accept.XML);
+
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    IOUtils.copy(metadata, bos);
+    IOUtils.closeQuietly(metadata);
+
+    final String entitySetName = entitySetElement.getStart().getAttributeByName(new QName("Name")).getValue().trim();
+    final String entityType = entitySetElement.getStart().getAttributeByName(new QName("EntityType")).getValue().trim();
+
+    final Collection<Map.Entry<String, String>> filter = new HashSet<Map.Entry<String, String>>();
+    filter.add(new SimpleEntry<String, String>(
+            "Name", entityType.substring(entityType.lastIndexOf(".") + 1, entityType.length())));
+    filter.add(new SimpleEntry<String, String>("BaseType", entityType));
+
+    final XMLEventReader reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
+
+    final Map.Entry<Integer, XmlElement> entityTypeElement = extractElement(
+            reader, null, Collections.<String>singletonList("EntityType"), filter, true, 0, -1, -1);
+
+    final XMLEventReader entityReader = entityTypeElement.getValue().getContentReader();
+    int size = 0;
+
+    try {
+      while (true) {
+        final XmlElement navProperty =
+                extractElement(entityReader, null, Collections.<String>singletonList("NavigationProperty"),
+                null, false, 0, -1, -1).getValue();
+
+        final String linkName = navProperty.getStart().getAttributeByName(new QName("Name")).getValue();
+        final Map.Entry<String, Boolean> target = getTargetInfo(navProperty.getStart(), linkName);
+
+        metadataLinkInfo.addLink(
+                entitySetName,
+                linkName,
+                target.getKey(),
+                target.getValue());
+
+        size++;
+      }
+    } catch (Exception e) {
+    } finally {
+      entityReader.close();
+    }
+
+    if (size == 0) {
+      metadataLinkInfo.addEntitySet(entitySetName);
+    }
+  }
+
+  private Map.Entry<String, Boolean> getTargetInfo(final StartElement element, final String linkName)
+          throws Exception {
+    final InputStream metadata = fsManager.readFile(Constants.METADATA, Accept.XML);
+
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    IOUtils.copy(metadata, bos);
+    IOUtils.closeQuietly(metadata);
+
+    // ------------------------------------
+    // Retrieve association
+    // ------------------------------------
+    XMLEventReader reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
+
+    final String associationName = element.getAttributeByName(new QName("Relationship")).getValue();
+
+    final Map.Entry<Integer, XmlElement> association = extractElement(
+            reader, null, Collections.<String>singletonList("Association"),
+            Collections.<Map.Entry<String, String>>singleton(new SimpleEntry<String, String>(
+            "Name", associationName.substring(associationName.lastIndexOf(".") + 1))), false,
+            0, 4, 4);
+
+    reader.close();
+    // ------------------------------------
+
+    // ------------------------------------
+    // check for feed or not from Association role
+    // ------------------------------------
+    InputStream associationContent = association.getValue().toStream();
+    reader = getEventReader(associationContent);
+
+    Map.Entry<Integer, XmlElement> associationEnd = extractElement(
+            reader, null, Collections.<String>singletonList("End"),
+            Collections.<Map.Entry<String, String>>singleton(new SimpleEntry<String, String>("Role", linkName)),
+            false, 0, -1, -1);
+
+    reader.close();
+    IOUtils.closeQuietly(associationContent);
+
+    final boolean feed = associationEnd.getValue().getStart().getAttributeByName(
+            new QName("Multiplicity")).getValue().equals("*");
+    // ------------------------------------
+
+    // ------------------------------------
+    // Retrieve target association set name
+    // ------------------------------------
+    reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
+
+    final Map.Entry<Integer, XmlElement> associationSet = extractElement(
+            reader, null, Collections.<String>singletonList("AssociationSet"),
+            Collections.<Map.Entry<String, String>>singleton(new SimpleEntry<String, String>(
+            "Association", associationName)), false, 0, -1, -1);
+
+    reader.close();
+
+    associationContent = associationSet.getValue().toStream();
+    reader = getEventReader(associationContent);
+
+    associationEnd = extractElement(
+            reader, null, Collections.<String>singletonList("End"),
+            Collections.<Map.Entry<String, String>>singleton(new SimpleEntry<String, String>("Role", linkName)),
+            false, 0, -1, -1);
+
+    reader.close();
+    IOUtils.closeQuietly(associationContent);
+
+    final String target = associationEnd.getValue().getStart().getAttributeByName(new QName("EntitySet")).getValue();
+    // ------------------------------------
+
+    return new SimpleEntry<String, Boolean>(target, feed);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/9aefb959/fit/src/main/java/org/apache/olingo/fit/utils/v4/JSONUtilities.java
----------------------------------------------------------------------
diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/v4/JSONUtilities.java b/fit/src/main/java/org/apache/olingo/fit/utils/v4/JSONUtilities.java
new file mode 100644
index 0000000..daf75f4
--- /dev/null
+++ b/fit/src/main/java/org/apache/olingo/fit/utils/v4/JSONUtilities.java
@@ -0,0 +1,28 @@
+/*
+ * 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.fit.utils.v4;
+
+import org.apache.olingo.fit.utils.ODataVersion;
+
+public class JSONUtilities extends org.apache.olingo.fit.utils.AbstractJSONUtilities {
+
+  public JSONUtilities() throws Exception {
+    super(ODataVersion.v4);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata4/blob/9aefb959/fit/src/main/java/org/apache/olingo/fit/utils/v4/XMLUtilities.java
----------------------------------------------------------------------
diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/v4/XMLUtilities.java b/fit/src/main/java/org/apache/olingo/fit/utils/v4/XMLUtilities.java
new file mode 100644
index 0000000..c61d272
--- /dev/null
+++ b/fit/src/main/java/org/apache/olingo/fit/utils/v4/XMLUtilities.java
@@ -0,0 +1,142 @@
+/*
+ * 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.fit.utils.v4;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import org.apache.commons.io.IOUtils;
+import org.apache.olingo.fit.utils.Accept;
+import org.apache.olingo.fit.utils.Commons;
+import org.apache.olingo.fit.utils.Constants;
+import org.apache.olingo.fit.utils.MetadataLinkInfo;
+import org.apache.olingo.fit.utils.ODataVersion;
+import org.apache.olingo.fit.utils.XmlElement;
+
+public class XMLUtilities extends org.apache.olingo.fit.utils.AbstractXMLUtilities {
+
+  public XMLUtilities() throws Exception {
+    super(ODataVersion.v4);
+  }
+
+  @Override
+  public void retrieveLinkInfoFromMetadata() throws Exception {
+
+    final MetadataLinkInfo metadataLinkInfo = new MetadataLinkInfo();
+    Commons.getLinkInfo().put(version, metadataLinkInfo);
+
+    final InputStream metadata = fsManager.readFile(Constants.METADATA, Accept.XML);
+
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    IOUtils.copy(metadata, bos);
+    IOUtils.closeQuietly(metadata);
+
+    XMLEventReader reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
+
+    final Set<String> singletons = new HashSet<String>();
+
+    try {
+      while (true) {
+        final Map.Entry<Integer, XmlElement> entitySetElement =
+                extractElement(reader, null, Collections.<String>singletonList("Singleton"),
+                null, false, 0, -1, -1);
+
+        final String entitySetName =
+                entitySetElement.getValue().getStart().getAttributeByName(new QName("Name")).getValue().trim();
+        singletons.add(entitySetName);
+      }
+    } catch (Exception e) {
+    } finally {
+      reader.close();
+    }
+
+    reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
+
+    try {
+      while (true) {
+        final Map.Entry<Integer, XmlElement> entitySetElement =
+                extractElement(reader, null, Collections.<String>singletonList("EntitySet"),
+                null, false, 0, -1, -1);
+
+        retrieveLinks(entitySetElement.getValue(), metadataLinkInfo, singletons);
+      }
+    } catch (Exception e) {
+    } finally {
+      reader.close();
+    }
+
+    reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
+
+    try {
+      while (true) {
+        final Map.Entry<Integer, XmlElement> entitySetElement =
+                extractElement(reader, null, Collections.<String>singletonList("Singleton"),
+                null, false, 0, -1, -1);
+
+        retrieveLinks(entitySetElement.getValue(), metadataLinkInfo, singletons);
+      }
+    } catch (Exception e) {
+    } finally {
+      reader.close();
+    }
+  }
+
+  private void retrieveLinks(
+          final XmlElement entitySetElement, final MetadataLinkInfo metadataLinkInfo, final Set<String> singletons)
+          throws Exception {
+
+    final String entitySetName = entitySetElement.getStart().getAttributeByName(new QName("Name")).getValue().trim();
+
+    final XMLEventReader entityReader = entitySetElement.getContentReader();
+    int size = 0;
+
+    try {
+      while (true) {
+        final XmlElement navProperty =
+                extractElement(entityReader, null, Collections.<String>singletonList("NavigationPropertyBinding"),
+                null, false, 0, -1, -1).getValue();
+
+        final String linkName = navProperty.getStart().getAttributeByName(new QName("Path")).getValue();
+        final String target = navProperty.getStart().getAttributeByName(new QName("Target")).getValue();
+        final boolean feed = !singletons.contains(target);
+
+        metadataLinkInfo.addLink(
+                entitySetName,
+                linkName,
+                target,
+                feed);
+
+        size++;
+      }
+    } catch (Exception e) {
+    } finally {
+      entityReader.close();
+    }
+
+    if (size == 0) {
+      metadataLinkInfo.addEntitySet(entitySetName);
+    }
+  }
+}