/**
  * Method to prepare Complex type representation.
  *
  * @param writer
  * @param entityMetadata
  * @param propertyName
  * @param propertiesList
  * @param modelName
  */
 private void writePropertyComplexList(
     StreamWriter writer,
     EntityMetadata entityMetadata,
     EntityProperty property,
     String modelName) {
   @SuppressWarnings("unchecked")
   List<EntityProperties> propertiesList = (List<EntityProperties>) property.getValue();
   String name = entityMetadata.getEntityName() + "_" + property.getName();
   int parseCount = 0;
   for (EntityProperties properties : propertiesList) {
     String fqTypeName = modelName + Metadata.MODEL_SUFFIX + "." + name;
     // We should be able to differentiate List<ComplexType> with regular ComplexType
     if (entityMetadata.isPropertyList(property.getFullyQualifiedName())) {
       if (parseCount == 0) {
         writer.startElement(new QName(d, name, "d"));
         writer.writeAttribute(new QName(m, "type", "m"), "Bag(" + fqTypeName + ")");
         writer.startElement(new QName(d, "element", "d"));
         parseCount++;
       } else {
         writer.startElement(new QName(d, "element", "d"));
       }
     } else {
       writer.startElement(new QName(d, name, "d"));
       writer.writeAttribute(new QName(m, "type", "m"), fqTypeName);
     }
     writeProperties(writer, entityMetadata, properties, modelName);
     writer.endElement();
   }
   // For List<ComplexTypes> we should end the complex node here
   if (!propertiesList.isEmpty()
       && entityMetadata.isPropertyList(property.getFullyQualifiedName())) {
     writer.endElement();
   }
 }
 private void writeProperty(
     StreamWriter writer, EntityMetadata entityMetadata, EntityProperty property) {
   String elementText = entityMetadata.getPropertyValueAsString(property);
   writer.startElement(new QName(d, property.getName(), "d"));
   EdmType type =
       MetadataOData4j.termValueToEdmType(
           entityMetadata.getTermValue(property.getFullyQualifiedName(), TermValueType.TERM_NAME));
   boolean isNullable = entityMetadata.isPropertyNullable(property.getFullyQualifiedName());
   // Append Type Attribute
   if (!type.equals(EdmSimpleType.STRING)) {
     writer.writeAttribute(new QName(m, "type", "m"), type.getFullyQualifiedTypeName());
   }
   // Append Null attribute
   if (isNullable && (elementText.isEmpty()) && !type.equals(EdmSimpleType.STRING)) {
     writer.writeAttribute(new QName(m, "null", "m"), "true");
   }
   // Write the property text
   if (type.equals(EdmSimpleType.DATETIME) && !elementText.isEmpty()) {
     // Write dates in UTC format
     SimpleDateFormat formatUTC = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
     formatUTC.setTimeZone(TimeZone.getTimeZone("UTC"));
     writer.writeElementText(formatUTC.format((Date) property.getValue()));
   } else if (elementText != null) {
     writer.writeElementText(elementText);
   }
   writer.endElement();
 }
  public void write(
      UriInfo uriInfo,
      Writer w,
      String entityName,
      Entity entity,
      Collection<Link> links,
      Map<Transition, RESTResource> embeddedResources) {
    String baseUri = AtomXMLProvider.getBaseUri(serviceDocument, uriInfo);

    String absoluteId = getAbsoluteId(uriInfo, links);

    DateTime utc = new DateTime().withZone(DateTimeZone.UTC);
    String updated = InternalUtil.toString(utc);

    Abdera abdera = new Abdera();
    StreamWriter writer = abdera.newStreamWriter();
    writer.setOutputStream(new WriterOutputStream(w));
    writer.setAutoflush(false);
    writer.setAutoIndent(true);
    writer.startDocument();

    writer.startEntry();
    writer.writeNamespace("d", d);
    writer.writeNamespace("m", m);
    writer.writeAttribute("xml:base", baseUri);
    writeEntry(writer, entityName, entity, links, embeddedResources, baseUri, absoluteId, updated);
    writer.endEntry();
    writer.endDocument();
    writer.flush();
  }
  @SuppressWarnings("unchecked")
  protected void writeLinkInline(
      StreamWriter writer,
      Metadata metadata,
      Link linkToInline,
      RESTResource embeddedResource,
      String href,
      String baseUri,
      String absoluteId,
      String updated) {

    writer.startElement(new QName(m, "inline", "m"));
    if (embeddedResource instanceof CollectionResource) {
      CollectionResource<Entity> collectionResource = (CollectionResource<Entity>) embeddedResource;
      Collection<EntityResource<Entity>> entities = collectionResource.getEntities();

      if (entities != null && !entities.isEmpty()) {
        writer.startFeed();
        writer.writeTitle(Type.TEXT, linkToInline.getTitle());
        writer.writeId(baseUri + href);
        writer.writeUpdated(updated);
        writer.startLink(href, "self");
        writer.writeAttribute("title", linkToInline.getTitle());
        writer.endLink();

        for (EntityResource<Entity> entityResource : entities) {
          writeEntityResource(writer, entityResource, baseUri, absoluteId, updated);
        }
        writer.endFeed();
      }
    } else if (embeddedResource instanceof EntityResource) {
      EntityResource<Entity> entityResource = (EntityResource<Entity>) embeddedResource;
      writeEntityResource(writer, entityResource, baseUri, absoluteId, updated);
    } else {
      throw new RuntimeException("Unknown OLink type " + linkToInline.getClass());
    }
    writer.endElement(); // end inline
  }
  protected void writeEntry(
      StreamWriter writer,
      String entityName,
      Entity entity,
      Collection<Link> entityLinks,
      Map<Transition, RESTResource> embeddedResources,
      String baseUri,
      String absoluteId,
      String updated) {
    assert (entityName != null);

    // entity name could be different between entity resource and underlying entity
    // e.g., for Errors entity, entity resource would have the request entity name
    String entityMetadataName = entity != null ? entity.getName() : entityName;

    EntityMetadata entityMetadata = metadata.getEntityMetadata(entityMetadataName);
    String modelName = metadata.getModelName();
    writer.writeId(absoluteId);
    OAtomEntity oae = getAtomInfo(entity);

    writer.writeTitle(oae.getAtomEntityTitle());
    String summary = oae.getAtomEntitySummary();
    if (!summary.isEmpty()) {
      writer.writeSummary(summary);
    }

    LocalDateTime updatedTime = oae.getAtomEntityUpdated();
    if (updatedTime != null) {
      updated = InternalUtil.toString(updatedTime.toDateTime(DateTimeZone.UTC));
    }

    writer.writeUpdated(updated);
    writer.writeAuthor(oae.getAtomEntityAuthor());

    if (entityLinks != null) {
      for (Link link : entityLinks) {
        String type =
            (link.getTransition().getTarget() instanceof CollectionResourceState)
                ? atom_feed_content_type
                : atom_entry_content_type;
        String href = link.getRelativeHref(baseUri);
        String rel = link.getRel();
        writer.startLink(href, rel);

        if ("self".equals(link.getRel())) {
          ResourceState target = link.getTransition().getTarget();
          writer.writeAttribute("profile", target.getRel());
        }

        if (!"self".equals(link.getRel()) && !"edit".equals(link.getRel())) {
          writer.writeAttribute("type", type);
        }
        writer.writeAttribute("title", link.getTitle());
        if (embeddedResources != null && embeddedResources.get(link.getTransition()) != null) {
          String embeddedAbsoluteId = link.getHref();
          writeLinkInline(
              writer,
              metadata,
              link,
              embeddedResources.get(link.getTransition()),
              link.getHref(),
              baseUri,
              embeddedAbsoluteId,
              updated);
        }
        String linkId = link.getLinkId();
        if (linkId != null && linkId.length() > 0) {
          writer.writeAttribute("id", linkId);
        }
        writer.endLink();
      }
    }

    writer.writeCategory(modelName + Metadata.MODEL_SUFFIX + "." + entityName, scheme);
    writer.flush();

    writer.startContent(MediaType.APPLICATION_XML);

    writer.startElement(new QName(m, "properties", "m"));
    if (entity != null) {
      writeProperties(writer, entityMetadata, entity.getProperties(), modelName);
    }
    writer.endElement();

    writer.endContent();
  }