All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hcl.domino.jnx.rawdoc.json.service.RawDocDeserializer Maven / Gradle / Ivy

There is a newer version: 1.44.0
Show newest version
/*
 * ==========================================================================
 * Copyright (C) 2019-2022 HCL America, Inc. ( http://www.hcl.com/ )
 *                            All rights reserved.
 * ==========================================================================
 * Licensed 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 .
 *
 * 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 com.hcl.domino.jnx.rawdoc.json.service;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.time.Instant;
import java.time.temporal.TemporalAccessor;
import java.util.Base64;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hcl.domino.commons.json.AbstractJsonDeserializer;
import com.hcl.domino.commons.json.JsonUtil;
import com.hcl.domino.data.Document;
import com.hcl.domino.data.Document.IAttachmentProducer;
import com.hcl.domino.data.DocumentClass;
import com.hcl.domino.data.Item.ItemFlag;
import com.hcl.domino.data.ItemDataType;

/**
 * Deserializer for the {@link RawDocSerializer}.
 * 
 * @author Karsten Lehmann
 * @since 1.4.6
 */
public class RawDocDeserializer extends AbstractJsonDeserializer {
  
  @Override
  public Document fromJson(String json) {
    ObjectMapper mapper = new ObjectMapper();
    JsonFactory factory = mapper.getFactory();
    
    JsonNode docJson;
    try {
      JsonParser parser = factory.createParser(json);
      docJson = mapper.readTree(parser);
      
    } catch (IOException e) {
      throw new RuntimeException("Error parsing JSON string", e);
    }

    Document doc;
    if (this.targetDocument!=null) {
      doc = this.targetDocument;
    }
    else {
      if (this.targetDatabase == null) {
        throw new IllegalStateException("No target database specified");
      }
      
      doc = this.targetDatabase.createDocument();
    }
    
    JsonNode docClassNode = Objects.requireNonNull(docJson.get(RawDocSerializer.PROP_META_NOTECLASS), //$NON-NLS-1$
        MessageFormat.format("Property {0} is missing", RawDocSerializer.PROP_META_NOTECLASS));
    
    if (docClassNode.isArray()) {
      Set docClass =
          StreamSupport
          .stream(docClassNode.spliterator(), false)
          .map(JsonNode::textValue)
          .map(DocumentClass::valueOf)
          .collect(Collectors.toSet());

      if (docClass.isEmpty()) {
        docClass = EnumSet.of(DocumentClass.DATA);
      }
      doc.setDocumentClass(docClass);
    }
        
    JsonNode itemsArr = docJson.get(RawDocSerializer.PROP_ITEMS);
    if (itemsArr!=null && itemsArr.isArray()) {
      Set processedNames = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
      Set cleanedUpItemNames = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
      
      for (JsonNode currItemNode : itemsArr) {
        importItemIntoDoc(doc, currItemNode, processedNames, cleanedUpItemNames);
      }

      if (removeMissingItems) {
        doc.getItemNames().stream()
        .filter(name -> !"Form".equalsIgnoreCase(name)) //$NON-NLS-1$
        .filter(name -> !processedNames.contains(name))
        .filter(name -> !name.startsWith("$")) //$NON-NLS-1$
        .forEach(name -> {
          doc.removeItem(name);
        });
      }
    }

    return doc;
  }

  /**
   * Creates a new item in the document with data read from the
   * itemNode.
   * 
   * @param doc target document
   * @param itemNode JSON node with item data
   * @param retImportedItemNames we add the name if imported items here
   */
  private void importItemIntoDoc(Document doc, JsonNode itemNode, Set retImportedItemNames,
      Set cleanedUpItemNames) {
    String itemName = getRequiredJsonItem(itemNode, RawDocSerializer.PROP_ITEM_NAME);
    String itemTypeStr = getRequiredJsonItem(itemNode, RawDocSerializer.PROP_ITEM_TYPE);
    
    ItemDataType itemType;
    try {
      itemType = ItemDataType.valueOf(itemTypeStr);
    }
    catch (IllegalArgumentException e) {
      throw new IllegalArgumentException(MessageFormat.format("Invalid item type: {0}",
          itemTypeStr), e);
    }
    
    if ("$file".equalsIgnoreCase(itemName) && itemType==ItemDataType.TYPE_OBJECT) { //$NON-NLS-1$
      //reimport file attachment with referenced data
      String fileName = getRequiredJsonItem(itemNode, RawDocSerializer.PROP_FILE_NAME);

      doc.removeAttachment(fileName);
      
      long fileSize = Objects
          .requireNonNull(
              itemNode.get(RawDocSerializer.PROP_FILE_SIZE),
              MessageFormat.format("Attribute {0} is missing for item", RawDocSerializer.PROP_FILE_SIZE))
          .asLong();

      String fileCreatedStr = getRequiredJsonItem(itemNode, RawDocSerializer.PROP_FILE_CREATED);
      
      TemporalAccessor dtFileCreated = JsonUtil.tryDateTime(fileCreatedStr);
      if (dtFileCreated==null) {
        dtFileCreated = Instant.now();
      }
      
      String fileLastModifiedStr = getRequiredJsonItem(itemNode, RawDocSerializer.PROP_FILE_LASTMODIFIED);
      
      TemporalAccessor dtLastFileModified = JsonUtil.tryDateTime(fileLastModifiedStr);
      if (dtLastFileModified==null) {
        dtLastFileModified = Instant.now();
      }
      
      String fileDataBase64 = getRequiredJsonItem(itemNode, RawDocSerializer.PROP_FILE_DATA);
      
      try (InputStream in = Base64.getDecoder().wrap((new ByteArrayInputStream(fileDataBase64.getBytes(StandardCharsets.UTF_8))))) {
        doc.attachFile(fileName, dtFileCreated, dtLastFileModified, new IAttachmentProducer() {
          
          @Override
          public void produceAttachment(OutputStream out) throws IOException {
            byte[] buffer = new byte[16384];
            int len;
            
            while ((len = in.read(buffer))>0) {
              out.write(buffer, 0, len);
            }
          }
          
          @Override
          public long getSizeEstimation() {
            return fileSize;
          }
        });
      } catch (IOException e) {
        throw new UncheckedIOException(e);
      }
      
      retImportedItemNames.add("$file"); //$NON-NLS-1$
    }
    else {
      if (!cleanedUpItemNames.contains(itemName)) {
        cleanedUpItemNames.add(itemName);
        doc.removeItem(itemName);
      }
      
      JsonNode flagsNode = Objects.requireNonNull(
          itemNode.get(RawDocSerializer.PROP_ITEM_FLAGS),
          MessageFormat.format("Attribute {0} is missing for item", RawDocSerializer.PROP_ITEM_FLAGS));
      
      Set flags = EnumSet.noneOf(ItemFlag.class);
      
      if (flagsNode.isArray()) {
        for (JsonNode currFlagNode : flagsNode) {
          String currFlagStr = currFlagNode.textValue();
          if (!"".equals(currFlagStr)) { //$NON-NLS-1$
            try {
              flags.add(ItemFlag.valueOf(currFlagStr));
            }
            catch (IllegalArgumentException e) {
              throw new IllegalArgumentException(
                  MessageFormat.format("Invalid item flag value: {0}", currFlagStr), e);
            }
          }
        }
      }
      
      //normal item, write binary 
      String itemValueBase64 = getRequiredJsonItem(itemNode, RawDocSerializer.PROP_ITEM_VALUE_RAW);
      ByteBuffer binaryItemValue = ByteBuffer.wrap(Base64.getDecoder().decode(itemValueBase64)).order(ByteOrder.nativeOrder());
      
      doc.appendItemValue(itemName, flags, binaryItemValue);

      retImportedItemNames.add(itemName);
    }
  }
  
  private String getRequiredJsonItem(JsonNode json, String itemName) {
    return Objects
        .requireNonNull(
        json.get(itemName),
        MessageFormat.format("Attribute {0} is missing for item", itemName))
        .asText();
  }
  
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy