@Override
  public PartIteration filterPartIteration(PartMaster partMaster) {

    if (type.equals(ProductBaseline.BaselineType.RELEASED)) {

      for (PartIteration pi : partIterations) {
        if (pi.getPartRevision().getPartMaster().getKey().equals(partMaster.getKey())) {
          retainedPartIterations.add(pi);
          return pi;
        }
      }
      // Else, take the latest released
      PartRevision lastReleasedRevision = partMaster.getLastReleasedRevision();
      if (lastReleasedRevision != null) {
        PartIteration pi = lastReleasedRevision.getLastIteration();
        retainedPartIterations.add(pi);
        return pi;
      }

    } else if (type.equals(ProductBaseline.BaselineType.LATEST)) {

      PartIteration pi = partMaster.getLastRevision().getLastCheckedInIteration();

      if (pi != null) {
        retainedPartIterations.add(pi);
        return pi;
      }
    }

    return null;
  }
  public static void generateInstanceStreamWithGlobalMatrix(
      IProductManagerLocal productService,
      List<PartLink> currentPath,
      Matrix4d matrix,
      VirtualInstanceCollection virtualInstanceCollection,
      List<Integer> instanceIds,
      JsonGenerator jg) {
    try {

      PartLink partLink = currentPath.get(currentPath.size() - 1);
      PSFilter filter = virtualInstanceCollection.getFilter();
      List<PartIteration> filteredPartIterations = filter.filter(partLink.getComponent());

      if (!filteredPartIterations.isEmpty()) {

        PartIteration partI = filteredPartIterations.iterator().next();

        // Filter ACL on part
        if (!productService.canAccess(partI.getPartRevision().getKey())) {
          return;
        }

        for (CADInstance instance : partLink.getCadInstances()) {

          List<Integer> copyInstanceIds = new ArrayList<>(instanceIds);
          copyInstanceIds.add(instance.getId());

          Vector3d instanceTranslation =
              new Vector3d(instance.getTx(), instance.getTy(), instance.getTz());
          Vector3d instanceRotation =
              new Vector3d(instance.getRx(), instance.getRy(), instance.getRz());
          Matrix4d combinedMatrix =
              combineTransformation(matrix, instanceTranslation, instanceRotation);

          if (!partI.isAssembly() && !partI.getGeometries().isEmpty()) {
            writeLeaf(currentPath, copyInstanceIds, partI, combinedMatrix, jg);
          } else {
            for (PartLink subLink : partI.getComponents()) {
              List<PartLink> subPath = new ArrayList<>(currentPath);
              subPath.add(subLink);
              generateInstanceStreamWithGlobalMatrix(
                  productService,
                  subPath,
                  combinedMatrix,
                  virtualInstanceCollection,
                  copyInstanceIds,
                  jg);
            }
          }
        }
      }

    } catch (UserNotFoundException
        | UserNotActiveException
        | WorkspaceNotFoundException
        | PartRevisionNotFoundException e) {
      e.printStackTrace();
    }
  }
  private static void writeLeaf(
      List<PartLink> currentPath,
      List<Integer> copyInstanceIds,
      PartIteration partI,
      Matrix4d combinedMatrix,
      JsonGenerator jg) {
    String partIterationId = partI.toString();
    List<InstanceAttributeDTO> attributes = new ArrayList<>();
    for (InstanceAttribute attr : partI.getInstanceAttributes()) {
      attributes.add(mapper.map(attr, InstanceAttributeDTO.class));
    }

    jg.writeStartObject();
    jg.write("id", Tools.getPathInstanceAsString(currentPath, copyInstanceIds));
    jg.write("partIterationId", partIterationId);
    jg.write("path", Tools.getPathAsString(currentPath));

    writeMatrix(combinedMatrix, jg);
    writeGeometries(partI.getSortedGeometries(), jg);
    writeAttributes(attributes, jg);

    jg.writeEnd();
    jg.flush();
  }
  private String[] createXLSRowComments(List<String> selects, QueryResultRow row) {
    List<String> commentsData = new ArrayList<>();
    PartRevision part = row.getPartRevision();
    PartIteration lastIteration = part.getLastIteration();

    for (String select : selects) {

      if (select.equals(QueryField.CTX_SERIAL_NUMBER)) {
        String path = row.getPath();
        if (path != null && !path.isEmpty()) {
          commentsData.add(path);
        }

      } else if (select.startsWith(QueryField.PART_REVISION_ATTRIBUTES_PREFIX)) {
        String attributeSelectType =
            select
                .substring(0, select.indexOf("."))
                .substring(QueryField.PART_REVISION_ATTRIBUTES_PREFIX.length());
        String attributeSelectName = select.substring(select.indexOf(".") + 1);
        StringBuilder commentsSbattr = new StringBuilder();

        if (lastIteration != null) {
          List<InstanceAttribute> attributes = lastIteration.getInstanceAttributes();
          if (attributes != null) {
            for (InstanceAttribute attribute : attributes) {
              InstanceAttributeDescriptor attributeDescriptor =
                  new InstanceAttributeDescriptor(attribute);

              if (attributeDescriptor.getName().equals(attributeSelectName)
                  && attributeDescriptor.getStringType().equals(attributeSelectType)) {
                commentsSbattr.append(attribute.getId() + "|");
              }
            }
          }
        }

        String commentsContent = commentsSbattr.toString().trim();
        if (commentsContent.length() > 0) {
          commentsContent = commentsContent.substring(0, commentsContent.lastIndexOf("|"));
        }
        commentsData.add(commentsContent);

      } else if (select.startsWith(QueryField.PATH_DATA_ATTRIBUTES_PREFIX)) {
        String attributeSelectType =
            select
                .substring(0, select.indexOf("."))
                .substring(QueryField.PATH_DATA_ATTRIBUTES_PREFIX.length());
        String attributeSelectName = select.substring(select.indexOf(".") + 1);
        PathDataIteration pdi = row.getPathDataIteration();
        StringBuilder commentsSbpattr = new StringBuilder();

        if (pdi != null) {
          List<InstanceAttribute> attributes = pdi.getInstanceAttributes();
          if (attributes != null) {
            for (InstanceAttribute attribute : attributes) {
              InstanceAttributeDescriptor attributeDescriptor =
                  new InstanceAttributeDescriptor(attribute);

              if (attributeDescriptor.getName().equals(attributeSelectName)
                  && attributeDescriptor.getStringType().equals(attributeSelectType)) {
                commentsSbpattr.append(attribute.getId() + "|");
              }
            }
          }
        }

        String commentsContent = commentsSbpattr.toString().trim();
        if (commentsContent.length() > 0) {
          commentsContent = commentsContent.substring(0, commentsContent.lastIndexOf("|"));
        }
        commentsData.add(commentsContent);

      } else {
        commentsData.add("");
      }
    }

    String commentsRowData = StringUtils.join(commentsData, ";");
    return commentsRowData.split(";");
  }
  private String[] createXLSRow(List<String> selects, QueryResultRow row, String baseURL) {
    List<String> data = new ArrayList<>();
    PartRevision part = row.getPartRevision();
    PartIteration lastCheckedInIteration = part.getLastCheckedInIteration();
    PartIteration lastIteration = part.getLastIteration();
    QueryContext context = row.getContext();

    for (String select : selects) {

      switch (select) {
        case QueryField.CTX_PRODUCT_ID:
          String productId = context != null ? context.getConfigurationItemId() : "";
          data.add(productId);
          break;
        case QueryField.CTX_SERIAL_NUMBER:
          String serialNumber = context != null ? context.getSerialNumber() : "";
          data.add(serialNumber != null ? serialNumber : "");
          break;
        case QueryField.PART_MASTER_NUMBER:
          data.add(part.getPartNumber());
          break;
        case QueryField.PART_MASTER_NAME:
          String sName = part.getPartName();
          data.add(sName != null ? sName : "");
          break;
        case QueryField.PART_MASTER_TYPE:
          String sType = part.getType();
          data.add(sType != null ? sType : "");
          break;
        case QueryField.PART_REVISION_MODIFICATION_DATE:
          data.add(
              (lastIteration != null && lastIteration.getModificationDate() != null)
                  ? simpleDateFormat.format(lastIteration.getModificationDate())
                  : "");
          break;
        case QueryField.PART_REVISION_CREATION_DATE:
          data.add(
              (part.getCreationDate() != null)
                  ? simpleDateFormat.format(part.getCreationDate())
                  : "");
          break;
        case QueryField.PART_REVISION_CHECKOUT_DATE:
          data.add(
              (part.getCheckOutDate() != null)
                  ? simpleDateFormat.format(part.getCheckOutDate())
                  : "");
          break;
        case QueryField.PART_REVISION_CHECKIN_DATE:
          data.add(
              (lastCheckedInIteration != null && lastCheckedInIteration.getCheckInDate() != null)
                  ? simpleDateFormat.format(lastCheckedInIteration.getCheckInDate())
                  : "");
          break;
        case QueryField.PART_REVISION_VERSION:
          data.add(part.getVersion() != null ? part.getVersion() : "");
          break;
        case QueryField.PART_REVISION_LIFECYCLE_STATE:
          data.add(part.getLifeCycleState() != null ? part.getLifeCycleState() : "");
          break;
        case QueryField.PART_REVISION_STATUS:
          data.add(part.getStatus().toString());
          break;
        case QueryField.AUTHOR_LOGIN:
          User user = part.getAuthor();
          data.add(user.getLogin());
          break;
        case QueryField.AUTHOR_NAME:
          User userAuthor = part.getAuthor();
          data.add(userAuthor.getName());
          break;
        case QueryField.CTX_DEPTH:
          data.add(row.getDepth() + "");
          break;
        case QueryField.CTX_AMOUNT:
          data.add(row.getAmount() + "");
          break;
        case QueryField.PART_ITERATION_LINKED_DOCUMENTS:
          StringBuilder sb = new StringBuilder();
          if (lastCheckedInIteration != null) {
            Set<DocumentLink> linkedDocuments = lastCheckedInIteration.getLinkedDocuments();
            for (DocumentLink documentLink : linkedDocuments) {
              DocumentRevision targetDocument = documentLink.getTargetDocument();
              sb.append(
                  baseURL
                      + "/documents/"
                      + targetDocument.getWorkspaceId()
                      + "/"
                      + targetDocument.getId()
                      + "/"
                      + targetDocument.getVersion()
                      + " ");
            }
          }
          data.add(sb.toString());
          break;

        case QueryField.CTX_P2P_SOURCE:
          Map<String, List<PartLinkList>> sources = row.getSources();
          String sourcePartLinksAsString = Tools.getPartLinksAsExcelString(sources);
          data.add(sourcePartLinksAsString);
          break;

        case QueryField.CTX_P2P_TARGET:
          Map<String, List<PartLinkList>> targets = row.getTargets();
          String targetPartLinksAsString = Tools.getPartLinksAsExcelString(targets);
          data.add(targetPartLinksAsString);
          break;

        default:
          if (select.startsWith(QueryField.PART_REVISION_ATTRIBUTES_PREFIX)) {
            String attributeSelectType =
                select
                    .substring(0, select.indexOf("."))
                    .substring(QueryField.PART_REVISION_ATTRIBUTES_PREFIX.length());
            String attributeSelectName = select.substring(select.indexOf(".") + 1);
            String attributeValue = "";
            StringBuilder sbattr = new StringBuilder();

            if (lastIteration != null) {
              List<InstanceAttribute> attributes = lastIteration.getInstanceAttributes();
              if (attributes != null) {
                for (InstanceAttribute attribute : attributes) {
                  InstanceAttributeDescriptor attributeDescriptor =
                      new InstanceAttributeDescriptor(attribute);
                  if (attributeDescriptor.getName().equals(attributeSelectName)
                      && attributeDescriptor.getStringType().equals(attributeSelectType)) {

                    attributeValue = attribute.getValue() + "";
                    if (attributeDescriptor.getType() == InstanceAttributeDescriptor.Type.DATE) {
                      attributeValue =
                          attribute.getValue() != null
                              ? attributeDateFormat.format(attribute.getValue())
                              : "";
                    } else if (attribute instanceof InstanceListOfValuesAttribute) {
                      attributeValue =
                          ((InstanceListOfValuesAttribute) attribute).getSelectedName();
                    }
                    sbattr.append(attributeValue + "|");
                  }
                }
              }
            }
            String content = sbattr.toString().trim();
            if (content.length() > 0) {
              content = content.substring(0, content.lastIndexOf("|"));
            }
            data.add(content);
          }
          if (select.startsWith(QueryField.PATH_DATA_ATTRIBUTES_PREFIX)) {
            String attributeSelectType =
                select
                    .substring(0, select.indexOf("."))
                    .substring(QueryField.PATH_DATA_ATTRIBUTES_PREFIX.length());
            String attributeSelectName = select.substring(select.indexOf(".") + 1);
            String attributeValue = "";
            PathDataIteration pdi = row.getPathDataIteration();
            StringBuilder sbpdattr = new StringBuilder();

            if (pdi != null) {
              List<InstanceAttribute> attributes = pdi.getInstanceAttributes();
              if (attributes != null) {
                for (InstanceAttribute attribute : attributes) {
                  InstanceAttributeDescriptor attributeDescriptor =
                      new InstanceAttributeDescriptor(attribute);
                  if (attributeDescriptor.getName().equals(attributeSelectName)
                      && attributeDescriptor.getStringType().equals(attributeSelectType)) {

                    attributeValue = attribute.getValue() + "";
                    if (attributeDescriptor.getType() == InstanceAttributeDescriptor.Type.DATE) {
                      attributeValue =
                          attribute.getValue() != null
                              ? attributeDateFormat.format(attribute.getValue())
                              : "";
                    } else if (attribute instanceof InstanceListOfValuesAttribute) {
                      attributeValue =
                          ((InstanceListOfValuesAttribute) attribute).getSelectedName();
                    }
                    sbpdattr.append(attributeValue + "|");
                  }
                }
              }
            }
            String content = sbpdattr.toString().trim();
            if (content.length() > 0) {
              content = content.substring(0, content.lastIndexOf("|"));
            }
            data.add(content);
          }
      }
    }

    String rowData = StringUtils.join(data, ";");
    return rowData.split(";");
  }
  public static void generateInstanceStreamWithGlobalMatrix(
      IProductManagerLocal productService,
      List<PartLink> currentPath,
      Matrix4d matrix,
      InstanceCollection instanceCollection,
      List<Integer> instanceIds,
      JsonGenerator jg) {

    try {

      if (currentPath == null) {
        PartLink rootPartUsageLink =
            productService.getRootPartUsageLink(instanceCollection.getCiKey());
        currentPath = new ArrayList<>();
        currentPath.add(rootPartUsageLink);
      }

      Component component =
          productService.filterProductStructure(
              instanceCollection.getCiKey(), instanceCollection.getFilter(), currentPath, 1);

      PartLink partLink = component.getPartLink();
      PartIteration partI = component.getRetainedIteration();

      // Filter ACL on part
      if (!productService.canAccess(partI.getPartRevision().getKey())) {
        return;
      }

      for (CADInstance instance : partLink.getCadInstances()) {

        List<Integer> copyInstanceIds = new ArrayList<>(instanceIds);
        copyInstanceIds.add(instance.getId());

        Vector3d instanceTranslation =
            new Vector3d(instance.getTx(), instance.getTy(), instance.getTz());
        Vector3d instanceRotation =
            new Vector3d(instance.getRx(), instance.getRy(), instance.getRz());
        Matrix4d combinedMatrix =
            combineTransformation(matrix, instanceTranslation, instanceRotation);

        if (!partI.isAssembly()
            && !partI.getGeometries().isEmpty()
            && instanceCollection.isFiltered(currentPath)) {
          writeLeaf(currentPath, copyInstanceIds, partI, combinedMatrix, jg);
        } else {
          for (Component subComponent : component.getComponents()) {
            generateInstanceStreamWithGlobalMatrix(
                productService,
                subComponent.getPath(),
                combinedMatrix,
                instanceCollection,
                copyInstanceIds,
                jg);
          }
        }
      }

    } catch (PartMasterNotFoundException
        | PartRevisionNotFoundException
        | PartUsageLinkNotFoundException
        | UserNotFoundException
        | WorkspaceNotFoundException
        | ConfigurationItemNotFoundException e) {
      LOGGER.log(Level.SEVERE, null, e);
    } catch (AccessRightException
        | EntityConstraintException
        | NotAllowedException
        | UserNotActiveException e) {
      LOGGER.log(Level.FINEST, null, e);
    }
  }
  private void generateJSONResponse(OutputStream outputStream, QueryResult queryResult)
      throws UnsupportedEncodingException, NamingException {

    String charSet = "UTF-8";
    JsonGenerator jg = Json.createGenerator(new OutputStreamWriter(outputStream, charSet));
    jg.writeStartArray();

    List<String> selects = queryResult.getQuery().getSelects();
    List<String> partIterationSelectedAttributes = getPartIterationSelectedAttributes(selects);
    List<String> pathDataSelectedAttributes = getPathDataSelectedAttributes(selects);

    context = new InitialContext();
    IProductInstanceManagerLocal productInstanceService =
        (IProductInstanceManagerLocal)
            context.lookup(
                "java:global/docdoku-server-ear/docdoku-server-ejb/ProductInstanceManagerBean");

    for (QueryResultRow row : queryResult.getRows()) {

      QueryContext queryContext = row.getContext();

      PartRevision part = row.getPartRevision();
      PartIteration lastCheckedInIteration = part.getLastCheckedInIteration();

      jg.writeStartObject();

      jg.write(QueryField.PART_REVISION_PART_KEY, part.getPartNumber() + '-' + part.getVersion());

      // PartMaster data

      if (selects.contains(QueryField.PART_MASTER_NUMBER)) {
        jg.write(QueryField.PART_MASTER_NUMBER, part.getPartNumber());
      }

      if (selects.contains(QueryField.PART_MASTER_NAME)) {
        String sName = part.getPartName();
        jg.write(QueryField.PART_MASTER_NAME, sName != null ? sName : "");
      }

      if (selects.contains(QueryField.PART_MASTER_TYPE)) {
        String sType = part.getType();
        jg.write(QueryField.PART_MASTER_TYPE, sType != null ? sType : "");
      }

      // PartRevision data

      if (selects.contains(QueryField.PART_REVISION_MODIFICATION_DATE)) {
        PartIteration pi = part.getLastIteration();
        if (pi != null) {
          writeDate(jg, QueryField.PART_REVISION_MODIFICATION_DATE, pi.getModificationDate());
        }
      }

      if (selects.contains(QueryField.PART_REVISION_CREATION_DATE)) {
        writeDate(jg, QueryField.PART_REVISION_CREATION_DATE, part.getCreationDate());
      }

      if (selects.contains(QueryField.PART_REVISION_CHECKOUT_DATE)) {
        writeDate(jg, QueryField.PART_REVISION_CHECKOUT_DATE, part.getCheckOutDate());
      }

      if (selects.contains(QueryField.PART_REVISION_CHECKIN_DATE)) {
        writeDate(
            jg,
            QueryField.PART_REVISION_CHECKIN_DATE,
            lastCheckedInIteration != null ? lastCheckedInIteration.getCheckInDate() : null);
      }

      if (selects.contains(QueryField.PART_REVISION_VERSION)) {
        String version = part.getVersion();
        jg.write(QueryField.PART_REVISION_VERSION, version);
      }

      if (selects.contains(QueryField.PART_REVISION_LIFECYCLE_STATE)) {
        String lifeCycleState = part.getLifeCycleState();
        jg.write(
            QueryField.PART_REVISION_LIFECYCLE_STATE, lifeCycleState != null ? lifeCycleState : "");
      }

      if (selects.contains(QueryField.PART_REVISION_STATUS)) {
        PartRevision.RevisionStatus status = part.getStatus();
        jg.write(QueryField.PART_REVISION_STATUS, status.toString());
      }

      if (selects.contains(QueryField.AUTHOR_LOGIN)) {
        User user = part.getAuthor();
        jg.write(QueryField.AUTHOR_LOGIN, user.getLogin());
      }

      if (selects.contains(QueryField.AUTHOR_NAME)) {
        User user = part.getAuthor();
        jg.write(QueryField.AUTHOR_NAME, user.getName());
      }

      if (selects.contains(QueryField.CTX_DEPTH)) {
        jg.write(QueryField.CTX_DEPTH, row.getDepth());
      }

      if (selects.contains(QueryField.PART_ITERATION_LINKED_DOCUMENTS)) {

        StringBuilder sb = new StringBuilder();

        if (null != queryContext && null != queryContext.getSerialNumber()) {
          try {

            ProductInstanceMaster productInstanceMaster =
                productInstanceService.getProductInstanceMaster(
                    new ProductInstanceMasterKey(
                        queryContext.getSerialNumber(),
                        queryContext.getWorkspaceId(),
                        queryContext.getConfigurationItemId()));
            ProductInstanceIteration lastIteration = productInstanceMaster.getLastIteration();
            ProductBaseline basedOn = lastIteration.getBasedOn();
            PartCollection partCollection = basedOn.getPartCollection();
            BaselinedPart baselinedPart =
                partCollection.getBaselinedPart(
                    new BaselinedPartKey(
                        partCollection.getId(),
                        queryContext.getWorkspaceId(),
                        part.getPartNumber()));
            PartIteration targetPart = baselinedPart.getTargetPart();
            Set<DocumentLink> linkedDocuments = targetPart.getLinkedDocuments();
            DocumentCollection documentCollection = basedOn.getDocumentCollection();

            for (DocumentLink documentLink : linkedDocuments) {
              DocumentRevision targetDocument = documentLink.getTargetDocument();
              BaselinedDocument baselinedDocument =
                  documentCollection.getBaselinedDocument(
                      new BaselinedDocumentKey(
                          documentCollection.getId(),
                          queryContext.getWorkspaceId(),
                          targetDocument.getDocumentMasterId(),
                          targetDocument.getVersion()));
              if (null != baselinedDocument) {
                DocumentIteration targetDocumentIteration = baselinedDocument.getTargetDocument();
                sb.append(targetDocumentIteration.toString() + ",");
              }
            }

          } catch (UserNotFoundException
              | UserNotActiveException
              | WorkspaceNotFoundException
              | ProductInstanceMasterNotFoundException e) {
            LOGGER.log(Level.FINEST, null, e);
          }
        } else {
          if (lastCheckedInIteration != null) {
            Set<DocumentLink> linkedDocuments = lastCheckedInIteration.getLinkedDocuments();

            for (DocumentLink documentLink : linkedDocuments) {
              DocumentRevision targetDocument = documentLink.getTargetDocument();
              DocumentIteration targetDocumentLastCheckedInIteration =
                  targetDocument.getLastCheckedInIteration();
              if (targetDocumentLastCheckedInIteration != null) {
                sb.append(targetDocumentLastCheckedInIteration.toString() + ",");
              }
            }
          }
        }

        jg.write(QueryField.PART_ITERATION_LINKED_DOCUMENTS, sb.toString());
      }

      for (String attributeSelect : partIterationSelectedAttributes) {

        String attributeSelectType =
            attributeSelect
                .substring(0, attributeSelect.indexOf("."))
                .substring(QueryField.PART_REVISION_ATTRIBUTES_PREFIX.length());

        String attributeSelectName = attributeSelect.substring(attributeSelect.indexOf(".") + 1);

        String attributeValue = "";

        PartIteration pi = part.getLastIteration();

        if (pi != null) {
          List<InstanceAttribute> attributes = pi.getInstanceAttributes();

          if (attributes != null) {
            jg.writeStartArray(attributeSelect);

            for (InstanceAttribute attribute : attributes) {
              InstanceAttributeDescriptor attributeDescriptor =
                  new InstanceAttributeDescriptor(attribute);

              if (attributeDescriptor.getName().equals(attributeSelectName)
                  && attributeDescriptor.getStringType().equals(attributeSelectType)) {

                attributeValue = attribute.getValue() + "";

                if (attribute instanceof InstanceDateAttribute) {
                  attributeValue =
                      getFormattedDate(((InstanceDateAttribute) attribute).getDateValue());
                } else if (attribute instanceof InstanceListOfValuesAttribute) {
                  attributeValue = ((InstanceListOfValuesAttribute) attribute).getSelectedName();
                }

                jg.write(attributeValue);
              }
            }

            jg.writeEnd();

          } else {
            jg.write(attributeSelect, attributeValue);
          }

        } else {
          // TODO: maybe this line is useless and should be removed
          jg.write(attributeSelect, attributeValue);
        }
      }

      for (String attributeSelect : pathDataSelectedAttributes) {

        String attributeSelectType =
            attributeSelect
                .substring(0, attributeSelect.indexOf("."))
                .substring(QueryField.PATH_DATA_ATTRIBUTES_PREFIX.length());

        String attributeSelectName = attributeSelect.substring(attributeSelect.indexOf(".") + 1);

        String attributeValue = "";

        PathDataIteration pdi = row.getPathDataIteration();

        if (pdi != null) {
          List<InstanceAttribute> attributes = pdi.getInstanceAttributes();

          if (attributes != null) {
            jg.writeStartArray(attributeSelect);

            for (InstanceAttribute attribute : attributes) {
              InstanceAttributeDescriptor attributeDescriptor =
                  new InstanceAttributeDescriptor(attribute);

              if (attributeDescriptor.getName().equals(attributeSelectName)
                  && attributeDescriptor.getStringType().equals(attributeSelectType)) {

                attributeValue = attribute.getValue() + "";

                if (attribute instanceof InstanceDateAttribute) {
                  attributeValue =
                      getFormattedDate(((InstanceDateAttribute) attribute).getDateValue());
                } else if (attribute instanceof InstanceListOfValuesAttribute) {
                  attributeValue = ((InstanceListOfValuesAttribute) attribute).getSelectedName();
                }

                jg.write(attributeValue);
              }
            }

            jg.writeEnd();

          } else {
            jg.write(attributeSelect, attributeValue);
          }
        }
      }

      if (selects.contains(QueryField.CTX_PRODUCT_ID)) {
        String configurationItemId =
            queryContext != null ? queryContext.getConfigurationItemId() : "";
        jg.write(QueryField.CTX_PRODUCT_ID, configurationItemId);
      }
      if (selects.contains(QueryField.CTX_SERIAL_NUMBER)) {
        String serialNumber = queryContext != null ? queryContext.getSerialNumber() : "";
        jg.write(QueryField.CTX_SERIAL_NUMBER, serialNumber != null ? serialNumber : "");
      }
      if (selects.contains(QueryField.CTX_AMOUNT)) {
        String amount = row.getAmount() + "";
        jg.write(QueryField.CTX_AMOUNT, amount);
      }

      if (selects.contains(QueryField.CTX_P2P_SOURCE)) {
        Map<String, List<PartLinkList>> sources = row.getSources();
        String partLinksAsString = Tools.getPartLinksAsHumanString(sources);
        jg.write(QueryField.CTX_P2P_SOURCE, partLinksAsString);
      }

      if (selects.contains(QueryField.CTX_P2P_TARGET)) {
        Map<String, List<PartLinkList>> targets = row.getTargets();
        String partLinksAsString = Tools.getPartLinksAsHumanString(targets);
        jg.write(QueryField.CTX_P2P_TARGET, partLinksAsString);
      }

      if (selects.contains(QueryField.PART_MASTER_IS_STANDARD)) {
        boolean isStandard = row.getPartRevision().getPartMaster().isStandardPart();
        jg.write(QueryField.PART_MASTER_IS_STANDARD, isStandard);
      }

      jg.writeEnd();
    }

    jg.writeEnd();
    jg.flush();
  }